diff --git a/.gitignore b/.gitignore index 56b90b0e8e..c094f6a246 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,11 @@ venv/ #ignore avatar picture cache path /avatar +#Ignore autotest results +autotest-results.xml + +#ignore phpunit result cache +tests/.phpunit.result.cache + +#ignore .php_cs (local copy) +.php_cs diff --git a/.woodpecker/.continuous-deployment.yml b/.woodpecker/.continuous-deployment.yml index d334a4307a..5a29fe6129 100644 --- a/.woodpecker/.continuous-deployment.yml +++ b/.woodpecker/.continuous-deployment.yml @@ -9,7 +9,10 @@ depends_on: - database_checks - messages.po_check -platform: releaser/release # This prevents executing this pipeline at other servers than ci.friendi.ca +# This prevents executing this pipeline at other servers than ci.friendi.ca +labels: + location: friendica + type: releaser skip_clone: true diff --git a/.woodpecker/.releaser.yml b/.woodpecker/.releaser.yml index acac6ed2c4..5b56a6e1db 100644 --- a/.woodpecker/.releaser.yml +++ b/.woodpecker/.releaser.yml @@ -7,7 +7,10 @@ depends_on: - phpunit - code_standards_check -platform: releaser/release # This prevents executing this pipeline at other servers than ci.friendi.ca +# This prevents executing this pipeline at other servers than ci.friendi.ca +labels: + location: friendica + type: releaser skip_clone: true diff --git a/bin/composer.phar b/bin/composer.phar index c5d589526d..52f548bd23 100755 Binary files a/bin/composer.phar and b/bin/composer.phar differ diff --git a/bin/daemon.php b/bin/daemon.php index 1682d366ed..880115d0d0 100755 --- a/bin/daemon.php +++ b/bin/daemon.php @@ -26,7 +26,7 @@ * This script was taken from http://php.net/manual/en/function.pcntl-fork.php */ if (php_sapi_name() !== 'cli') { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden'); + header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); exit(); } @@ -45,13 +45,13 @@ $longopts = ['foreground']; $options = getopt($shortopts, $longopts); // Ensure that daemon.php is executed from the base path of the installation -if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) { - $directory = dirname($_SERVER["argv"][0]); +if (!file_exists('boot.php') && (sizeof($_SERVER['argv']) != 0)) { + $directory = dirname($_SERVER['argv'][0]); - if (substr($directory, 0, 1) != "/") { - $directory = $_SERVER["PWD"] . "/" . $directory; + if (substr($directory, 0, 1) != '/') { + $directory = $_SERVER['PWD'] . '/' . $directory; } - $directory = realpath($directory . "/.."); + $directory = realpath($directory . '/..'); chdir($directory); } @@ -86,16 +86,16 @@ TXT $pidfile = DI::config()->get('system', 'pidfile'); -if (in_array("start", $_SERVER["argv"])) { - $mode = "start"; +if (in_array('start', $_SERVER['argv'])) { + $mode = 'start'; } -if (in_array("stop", $_SERVER["argv"])) { - $mode = "stop"; +if (in_array('stop', $_SERVER['argv'])) { + $mode = 'stop'; } -if (in_array("status", $_SERVER["argv"])) { - $mode = "status"; +if (in_array('status', $_SERVER['argv'])) { + $mode = 'status'; } $foreground = array_key_exists('f', $options) || array_key_exists('foreground', $options); @@ -104,7 +104,7 @@ if (!isset($mode)) { die("Please use either 'start', 'stop' or 'status'.\n"); } -if (empty($_SERVER["argv"][0])) { +if (empty($_SERVER['argv'][0])) { die("Unexpected script behaviour. This message should never occur.\n"); } @@ -114,12 +114,12 @@ if (is_readable($pidfile)) { $pid = intval(file_get_contents($pidfile)); } -if (empty($pid) && in_array($mode, ["stop", "status"])) { +if (empty($pid) && in_array($mode, ['stop', 'status'])) { DI::config()->set('system', 'worker_daemon_mode', false); die("Pidfile wasn't found. Is the daemon running?\n"); } -if ($mode == "status") { +if ($mode == 'status') { if (posix_kill($pid, 0)) { die("Daemon process $pid is running.\n"); } @@ -130,12 +130,12 @@ if ($mode == "status") { die("Daemon process $pid isn't running.\n"); } -if ($mode == "stop") { +if ($mode == 'stop') { posix_kill($pid, SIGTERM); unlink($pidfile); - Logger::notice("Worker daemon process was killed", ["pid" => $pid]); + Logger::notice('Worker daemon process was killed', ['pid' => $pid]); DI::config()->set('system', 'worker_daemon_mode', false); die("Worker daemon process $pid was killed.\n"); @@ -145,7 +145,7 @@ if (!empty($pid) && posix_kill($pid, 0)) { die("Daemon process $pid is already running.\n"); } -Logger::notice('Starting worker daemon.', ["pid" => $pid]); +Logger::notice('Starting worker daemon.', ['pid' => $pid]); if (!$foreground) { echo "Starting worker daemon.\n"; @@ -194,7 +194,7 @@ $last_cron = 0; // Now running as a daemon. while (true) { if (!$do_cron && ($last_cron + $wait_interval) < time()) { - Logger::info('Forcing cron worker call.', ["pid" => $pid]); + Logger::info('Forcing cron worker call.', ['pid' => $pid]); $do_cron = true; } @@ -214,7 +214,7 @@ while (true) { } $start = time(); - Logger::info("Sleeping", ["pid" => $pid, 'until' => gmdate(DateTimeFormat::MYSQL, $start + $wait_interval)]); + Logger::info('Sleeping', ['pid' => $pid, 'until' => gmdate(DateTimeFormat::MYSQL, $start + $wait_interval)]); do { $seconds = (time() - $start); @@ -236,10 +236,10 @@ while (true) { if ($timeout) { $do_cron = true; - Logger::info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]); + Logger::info('Woke up after $wait_interval seconds.', ['pid' => $pid, 'sleep' => $wait_interval]); } else { $do_cron = false; - Logger::info("Worker jobs are calling to be forked.", ["pid" => $pid]); + Logger::info('Worker jobs are calling to be forked.', ['pid' => $pid]); } } diff --git a/autotest.sh b/bin/dev/autotest.sh similarity index 55% rename from autotest.sh rename to bin/dev/autotest.sh index 15067bf9d5..a3367db1e5 100755 --- a/autotest.sh +++ b/bin/dev/autotest.sh @@ -15,33 +15,34 @@ # - TEST_SELECTION= ... Specify which tests are used to run (based on the test-labeling) # - XDEBUG_CONFIG= ... Set some XDEBUG specific environment settings for development -DATABASENAME=${MYSQL_DATABASE:-test} -DATABASEUSER=${MYSQL_USERNAME:-friendica} -DATABASEHOST=${MYSQL_HOST:-localhost} -BASEDIR=$PWD +DATABASE_NAME=${FRIENDICA_MYSQL_DATABASE:-test} +DATABASE_USER=${FRIENDICA_MYSQL_USERNAME:-friendica} +DATABASE_HOST=${FRIENDICA_MYSQL_HOST:-localhost} +DATABASE_PASSWORD=${FRIENDICA_MYSQL_PASSWORD:-friendica} +BASEDIR=${PWD} DBCONFIGS="mysql mariadb" TESTS="REDIS MEMCACHE MEMCACHED APCU NODB" -export MYSQL_DATABASE="$DATABASENAME" -export MYSQL_USERNAME="$DATABASEUSER" -export MYSQL_PASSWORD="friendica" +export MYSQL_DATABASE="${DATABASE_NAME}" +export MYSQL_USERNAME="${DATABASE_USER}" +export MYSQL_PASSWORD="${DATABASE_PASSWORD}" -if [ -z "$PHP_EXE" ]; then +if [ -z "${PHP_EXE}" ]; then PHP_EXE=php fi -PHP=$(which "$PHP_EXE") +PHP=$(which "${PHP_EXE}") # Use the Friendica internal composer -COMPOSER="$BASEDIR/bin/composer.phar" +COMPOSER="${BASEDIR}/bin/composer.phar" set -e -_XDEBUG_CONFIG=$XDEBUG_CONFIG +_XDEBUG_CONFIG=${XDEBUG_CONFIG} unset XDEBUG_CONFIG function show_syntax() { echo -e "Syntax: ./autotest.sh [dbconfigname] [testfile]\n" >&2 - echo -e "\t\"dbconfigname\" can be one of: $DBCONFIGS" >&2 + echo -e "\t\"dbconfigname\" can be one of: ${DBCONFIGS}" >&2 echo -e "\t\"testfile\" is the name of a test file, for example lib/template.php" >&2 echo -e "\nDatabase environment variables:\n" >&2 echo -e "\t\"MYSQL_HOST\" Mysql Hostname (Default: localhost)" >&2 @@ -57,22 +58,22 @@ function show_syntax() { echo -e "\nIf no arguments are specified, all tests will be run with all database configs" >&2 } -if [ -x "$PHP" ]; then - echo "Using PHP executable $PHP" +if [ -x "${PHP}" ]; then + echo "Using PHP executable ${PHP}" else - echo "Could not find PHP executable $PHP_EXE" >&2 + echo "Could not find PHP executable ${PHP_EXE}" >&2 exit 3 fi echo "Installing depdendencies" -$PHP "$COMPOSER" install +${PHP} "$COMPOSER" install -PHPUNIT="$BASEDIR/vendor/bin/phpunit" +PHPUNIT="${BASEDIR}/vendor/bin/phpunit" -if [ -x "$PHPUNIT" ]; then - echo "Using PHPUnit executable $PHPUNIT" +if [ -x "${PHPUNIT}" ]; then + echo "Using PHPUnit executable ${PHPUNIT}" else - echo "Could not find PHPUnit executable after composer $PHPUNIT" >&2 + echo "Could not find PHPUnit executable after composer ${PHPUNIT}" >&2 exit 3 fi @@ -83,8 +84,8 @@ fi if [ "$1" ]; then FOUND=0 - for DBCONFIG in $DBCONFIGS; do - if [ "$1" = "$DBCONFIG" ]; then + for DBCONFIG in ${DBCONFIGS}; do + if [ "$1" = "${DBCONFIG}" ]; then FOUND=1 break fi @@ -103,13 +104,13 @@ fi function cleanup_config() { - if [ -n "$DOCKER_CONTAINER_ID" ]; then - echo "Kill the docker $DOCKER_CONTAINER_ID" - docker stop "$DOCKER_CONTAINER_ID" - docker rm -f "$DOCKER_CONTAINER_ID" + if [ -n "${DOCKER_CONTAINER_ID}" ]; then + echo "Kill the docker ${DOCKER_CONTAINER_ID}" + docker stop "${DOCKER_CONTAINER_ID}" + docker rm -f "${DOCKER_CONTAINER_ID}" fi - cd "$BASEDIR" + cd "${BASEDIR}" # Restore existing config if [ -f config/local.config-autotest-backup.php ]; then @@ -122,77 +123,77 @@ trap cleanup_config EXIT function execute_tests() { DB=$1 - echo "Setup environment for $DB testing ..." + echo "Setup environment for ${DB} testing ..." # back to root folder - cd "$BASEDIR" + cd "${BASEDIR}" # backup current config if [ -f config/local.config.php ]; then mv config/local.config.php config/local.config-autotest-backup.php fi - if [ -z "$NOINSTALL" ]; then + if [ -z "${NOINSTALL}" ]; then #drop database - if [ "$DB" == "mysql" ]; then - if [ -n "$USEDOCKER" ]; then + if [ "${DB}" == "mysql" ]; then + if [ -n "${USEDOCKER}" ]; then echo "Fire up the mysql docker" DOCKER_CONTAINER_ID=$(docker run \ -e MYSQL_ROOT_PASSWORD=friendica \ - -e MYSQL_USER="$DATABASEUSER" \ + -e MYSQL_USER="${DATABASE_USER}" \ -e MYSQL_PASSWORD=friendica \ - -e MYSQL_DATABASE="$DATABASENAME" \ + -e MYSQL_DATABASE="${DATABASE_NAME}" \ -d mysql) - DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID") + DATABASE_HOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "${DOCKER_CONTAINER_ID}") else - if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI + if [ -z "${DRONE}" ]; then # no need to drop the DB when we are on CI if [ "mysql" != "$(mysql --version | grep -o mysql)" ]; then echo "Your mysql binary is not provided by mysql" echo "To use the docker container set the USEDOCKER environment variable" exit 3 fi - mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true - mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST + mysql -u "${DATABASE_USER}" -pfriendica -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true + mysql -u "${DATABASE_USER}" -pfriendica -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST} else - DATABASEHOST=mysql + DATABASE_HOST=mysql fi fi - echo "Waiting for MySQL $DATABASEHOST initialization..." - if ! bin/wait-for-connection $DATABASEHOST 3306 300; then + echo "Waiting for MySQL ${DATABASE_HOST} initialization..." + if ! bin/wait-for-connection ${DATABASE_HOST} 3306 300; then echo "[ERROR] Waited 300 seconds, no response" >&2 exit 1 fi echo "MySQL is up." fi - if [ "$DB" == "mariadb" ]; then - if [ -n "$USEDOCKER" ]; then + if [ "${DB}" == "mariadb" ]; then + if [ -n "${USEDOCKER}" ]; then echo "Fire up the mariadb docker" DOCKER_CONTAINER_ID=$(docker run \ -e MYSQL_ROOT_PASSWORD=friendica \ - -e MYSQL_USER="$DATABASEUSER" \ + -e MYSQL_USER="${DATABASE_USER}" \ -e MYSQL_PASSWORD=friendica \ - -e MYSQL_DATABASE="$DATABASENAME" \ + -e MYSQL_DATABASE="${DATABASE_NAME}" \ -d mariadb) - DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID") + DATABASE_HOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "${DOCKER_CONTAINER_ID}") else - if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI + if [ -z "${DRONE}" ]; then # no need to drop the DB when we are on CI if [ "MariaDB" != "$(mysql --version | grep -o MariaDB)" ]; then echo "Your mysql binary is not provided by mysql" echo "To use the docker container set the USEDOCKER environment variable" exit 3 fi - mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true - mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST + mysql -u "${DATABASE_USER}" -pfriendica -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true + mysql -u "${DATABASE_USER}" -pfriendica -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST} else - DATABASEHOST=mariadb + DATABASE_HOST=mariadb fi fi - echo "Waiting for MariaDB $DATABASEHOST initialization..." - if ! bin/wait-for-connection $DATABASEHOST 3306 300; then + echo "Waiting for MariaDB ${DATABASE_HOST} initialization..." + if ! bin/wait-for-connection ${DATABASE_HOST} 3306 300; then echo "[ERROR] Waited 300 seconds, no response" >&2 exit 1 fi @@ -200,28 +201,28 @@ function execute_tests() { echo "MariaDB is up." fi - if [ -n "$USEDOCKER" ]; then + if [ -n "${USEDOCKER}" ]; then echo "Initialize database..." - docker exec $DOCKER_CONTAINER_ID mysql -u root -pfriendica -e 'CREATE DATABASE IF NOT EXISTS $DATABASENAME;' + docker exec ${DOCKER_CONTAINER_ID} mysql -u root -pfriendica -e "CREATE DATABASE IF NOT EXISTS ${DATABASE_NAME};" fi - export MYSQL_HOST="$DATABASEHOST" + export MYSQL_HOST="${DATABASE_HOST}" #call installer echo "Installing Friendica..." - "$PHP" ./bin/console.php autoinstall --dbuser="$DATABASEUSER" --dbpass=friendica --dbdata="$DATABASENAME" --dbhost="$DATABASEHOST" --url=https://friendica.local --admin=admin@friendica.local + "${PHP}" ./bin/console.php autoinstall --dbuser="${DATABASE_USER}" --dbpass=friendica --dbdata="${DATABASE_NAME}" --dbhost="${DATABASE_HOST}" --url=https://friendica.local --admin=admin@friendica.local fi #test execution echo "Testing..." rm -fr "coverage-html" mkdir "coverage-html" - if [[ "$_XDEBUG_CONFIG" ]]; then - export XDEBUG_CONFIG=$_XDEBUG_CONFIG + if [[ "${_XDEBUG_CONFIG}" ]]; then + export XDEBUG_CONFIG=${_XDEBUG_CONFIG} fi COVER='' - if [ -z "$NOCOVERAGE" ]; then + if [ -z "${NOCOVERAGE}" ]; then COVER="--coverage-clover tests/autotest-clover.xml" else echo "No coverage" @@ -229,51 +230,51 @@ function execute_tests() { # per default, there is no cache installed GROUP='--exclude-group REDIS,MEMCACHE,MEMCACHED,APCU' - if [ "$TEST_SELECTION" == "REDIS" ]; then + if [ "${TEST_SELECTION}" == "REDIS" ]; then GROUP="--group REDIS" fi - if [ "$TEST_SELECTION" == "MEMCACHE" ]; then + if [ "${TEST_SELECTION}" == "MEMCACHE" ]; then GROUP="--group MEMCACHE" fi - if [ "$TEST_SELECTION" == "MEMCACHED" ]; then + if [ "${TEST_SELECTION}" == "MEMCACHED" ]; then GROUP="--group MEMCACHED" fi - if [ "$TEST_SELECTION" == "APCU" ]; then + if [ "${TEST_SELECTION}" == "APCU" ]; then GROUP="--group APCU" fi - if [ "$TEST_SELECTION" == "NODB" ]; then + if [ "${TEST_SELECTION}" == "NODB" ]; then GROUP="--exclude-group DB,SLOWDB" fi - INPUT="$BASEDIR/tests" + INPUT="${BASEDIR}/tests" if [ -n "$2" ]; then - INPUT="$INPUT/$2" + INPUT="${INPUT}/$2" fi - echo "${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3" - "${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3" + echo "${PHPUNIT[@]}" --configuration tests/phpunit.xml ${GROUP} ${COVER} --log-junit "autotest-results.xml" "${INPUT}" "$3" + "${PHPUNIT[@]}" --configuration tests/phpunit.xml ${GROUP} ${COVER} --log-junit "autotest-results.xml" "${INPUT}" "$3" RESULT=$? - if [ -n "$DOCKER_CONTAINER_ID" ]; then - echo "Kill the docker $DOCKER_CONTAINER_ID" - docker stop $DOCKER_CONTAINER_ID - docker rm -f $DOCKER_CONTAINER_ID - unset $DOCKER_CONTAINER_ID + if [ -n "${DOCKER_CONTAINER_ID}" ]; then + echo "Kill the docker ${DOCKER_CONTAINER_ID}" + docker stop ${DOCKER_CONTAINER_ID} + docker rm -f ${DOCKER_CONTAINER_ID} + unset ${DOCKER_CONTAINER_ID} fi } # # Start the test execution # -if [ -z "$1" ] && [ -n "$TEST_SELECTION" ]; then +if [ -z "$1" ] && [ -n "${TEST_SELECTION}" ]; then # run all known database configs - for DBCONFIG in $DBCONFIGS; do - execute_tests "$DBCONFIG" + for DBCONFIG in ${DBCONFIGS}; do + execute_tests "${DBCONFIG}" done else FILENAME="$2" - if [ -n "$2" ] && [ ! -f "tests/$FILENAME" ] && [ "${FILENAME:0:2}" != "--" ]; then - FILENAME="../$FILENAME" + if [ -n "$2" ] && [ ! -f "tests/${FILENAME}" ] && [ "${FILENAME:0:2}" != "--" ]; then + FILENAME="../${FILENAME}" fi - execute_tests "$1" "$FILENAME" "$3" + execute_tests "$1" "${FILENAME}" "$3" fi diff --git a/boot.php b/boot.php index d227f7fe8b..c759bb93d2 100644 --- a/boot.php +++ b/boot.php @@ -87,8 +87,8 @@ define('PRIORITIES', [PRIORITY_CRITICAL, PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORIT /* @}*/ // Normally this constant is defined - but not if "pcntl" isn't installed -if (!defined("SIGTERM")) { - define("SIGTERM", 15); +if (!defined('SIGTERM')) { + define('SIGTERM', 15); } /** @@ -117,6 +117,7 @@ function local_user() if (!empty($_SESSION['authenticated']) && !empty($_SESSION['uid'])) { return intval($_SESSION['uid']); } + return false; } @@ -169,7 +170,7 @@ function remote_user() * * @param string $s - Text of notice */ -function notice($s) +function notice(string $s) { if (empty($_SESSION)) { return; @@ -189,7 +190,7 @@ function notice($s) * * @param string $s - Text of notice */ -function info($s) +function info(string $s) { if (empty($_SESSION)) { return; diff --git a/composer.lock b/composer.lock index fa20188253..68bf9bb7bd 100644 --- a/composer.lock +++ b/composer.lock @@ -545,12 +545,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "DivineOmega\\PasswordExposed\\": "src/" - }, "files": [ "src/PasswordExposedFunction.php" - ] + ], + "psr-4": { + "DivineOmega\\PasswordExposed\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -587,12 +587,12 @@ }, "type": "library", "autoload": { - "psr-0": { - "HTMLPurifier": "library/" - }, "files": [ "library/HTMLPurifier.composer.php" ], + "psr-0": { + "HTMLPurifier": "library/" + }, "exclude-from-classmap": [ "/library/HTMLPurifier/Language/" ] @@ -839,24 +839,24 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.5", + "version": "6.5.8", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", + "guzzlehttp/psr7": "^1.9", "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.17.0" + "symfony/polyfill-intl-idn": "^1.17" }, "require-dev": { "ext-curl": "*", @@ -873,22 +873,52 @@ } }, "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle is a PHP HTTP client library", @@ -902,7 +932,21 @@ "rest", "web service" ], - "time": "2020-06-16T21:01:06+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" }, { "name": "guzzlehttp/promises", @@ -931,12 +975,12 @@ } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -986,16 +1030,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.8.3", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85" + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/1afdd860a2566ed3c2b0b4a3de6e23434a79ec85", - "reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", + "reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318", "shasum": "" }, "require": { @@ -1016,16 +1060,16 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.9-dev" } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1088,7 +1132,7 @@ "type": "tidelift" } ], - "time": "2021-10-05T13:56:00+00:00" + "time": "2022-06-20T21:43:03+00:00" }, { "name": "league/html-to-markdown", @@ -1471,12 +1515,12 @@ }, "type": "library", "autoload": { - "classmap": [ - "Mobile_Detect.php" - ], "psr-0": { "Detection": "namespaced/" - } + }, + "classmap": [ + "Mobile_Detect.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1611,12 +1655,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "FastRoute\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "FastRoute\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3803,16 +3847,16 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.23.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", "shasum": "" }, "require": { @@ -3826,7 +3870,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3834,12 +3878,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3883,20 +3927,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "219aa369ceff116e673852dce47c3a41794c14bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", + "reference": "219aa369ceff116e673852dce47c3a41794c14bd", "shasum": "" }, "require": { @@ -3908,7 +3952,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3916,12 +3960,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -3964,7 +4008,7 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "symfony/polyfill-php56", @@ -4033,16 +4077,16 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.23.0", + "version": "v1.26.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2", + "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2", "shasum": "" }, "require": { @@ -4051,7 +4095,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.26-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4059,12 +4103,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4102,7 +4146,7 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2022-05-24T11:49:31+00:00" }, { "name": "ua-parser/uap-php", @@ -4865,12 +4909,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5618,11 +5662,11 @@ } }, "autoload": { - "classmap": [ - "src/" - ], "files": [ "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -6586,12 +6630,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ diff --git a/database.sql b/database.sql index 009a20fa00..01bd84b00b 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.09-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1469 +-- DB_UPDATE_VERSION 1473 -- ------------------------------------------ @@ -297,6 +297,7 @@ CREATE TABLE IF NOT EXISTS `2fa_trusted_browser` ( `cookie_hash` varchar(80) NOT NULL COMMENT 'Trusted cookie hash', `uid` mediumint unsigned NOT NULL COMMENT 'User ID', `user_agent` text COMMENT 'User agent string', + `trusted` boolean NOT NULL DEFAULT '1' COMMENT 'Whenever this browser should be trusted or not', `created` datetime NOT NULL COMMENT 'Datetime the trusted browser was recorded', `last_used` datetime COMMENT 'Datetime the trusted browser was last used', PRIMARY KEY(`cookie_hash`), @@ -1216,13 +1217,13 @@ CREATE TABLE IF NOT EXISTS `post-link` ( CREATE TABLE IF NOT EXISTS `post-media` ( `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri', - `url` varbinary(511) NOT NULL COMMENT 'Media URL', + `url` varbinary(1024) NOT NULL COMMENT 'Media URL', `type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Media type', `mimetype` varchar(60) COMMENT '', `height` smallint unsigned COMMENT 'Height of the media', `width` smallint unsigned COMMENT 'Width of the media', - `size` int unsigned COMMENT 'Media size', - `preview` varbinary(255) COMMENT 'Preview URL', + `size` bigint unsigned COMMENT 'Media size', + `preview` varbinary(512) COMMENT 'Preview URL', `preview-height` smallint unsigned COMMENT 'Height of the preview picture', `preview-width` smallint unsigned COMMENT 'Width of the preview picture', `description` text COMMENT '', @@ -1234,7 +1235,7 @@ CREATE TABLE IF NOT EXISTS `post-media` ( `publisher-name` varchar(255) COMMENT 'Name of the publisher of the media', `publisher-image` varbinary(255) COMMENT 'Image of the publisher of the media', PRIMARY KEY(`id`), - UNIQUE INDEX `uri-id-url` (`uri-id`,`url`), + UNIQUE INDEX `uri-id-url` (`uri-id`,`url`(512)), INDEX `uri-id-id` (`uri-id`,`id`), FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Attached media'; diff --git a/doc/Accesskeys.md b/doc/Accesskeys.md index 5945412de1..f79524c1b3 100644 --- a/doc/Accesskeys.md +++ b/doc/Accesskeys.md @@ -82,6 +82,7 @@ General ../settings --------- * o - Account +* 2 - Two-factor authentication * p - Profiles * t - Additional features * w - Social Networks diff --git a/doc/database/db_2fa_trusted_browser.md b/doc/database/db_2fa_trusted_browser.md index d12d9e1fc0..18126b49fc 100644 --- a/doc/database/db_2fa_trusted_browser.md +++ b/doc/database/db_2fa_trusted_browser.md @@ -6,13 +6,14 @@ Two-factor authentication trusted browsers Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ----------- | ------------------------------------------ | ------------------ | ---- | --- | ------- | ----- | -| cookie_hash | Trusted cookie hash | varchar(80) | NO | PRI | NULL | | -| uid | User ID | mediumint unsigned | NO | | NULL | | -| user_agent | User agent string | text | YES | | NULL | | -| created | Datetime the trusted browser was recorded | datetime | NO | | NULL | | -| last_used | Datetime the trusted browser was last used | datetime | YES | | NULL | | +| Field | Description | Type | Null | Key | Default | Extra | +| ----------- | ---------------------------------------------- | ------------------ | ---- | --- | ------- | ----- | +| cookie_hash | Trusted cookie hash | varchar(80) | NO | PRI | NULL | | +| uid | User ID | mediumint unsigned | NO | | NULL | | +| user_agent | User agent string | text | YES | | NULL | | +| trusted | Whenever this browser should be trusted or not | boolean | NO | | 1 | | +| created | Datetime the trusted browser was recorded | datetime | NO | | NULL | | +| last_used | Datetime the trusted browser was last used | datetime | YES | | NULL | | Indexes ------------ diff --git a/doc/database/db_post-media.md b/doc/database/db_post-media.md index 5c2a1bfd97..61a74b6987 100644 --- a/doc/database/db_post-media.md +++ b/doc/database/db_post-media.md @@ -10,13 +10,13 @@ Fields | --------------- | --------------------------------------------------------- | ----------------- | ---- | --- | ------- | -------------- | | id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | | uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | | NULL | | -| url | Media URL | varbinary(511) | NO | | NULL | | +| url | Media URL | varbinary(1024) | NO | | NULL | | | type | Media type | tinyint unsigned | NO | | 0 | | | mimetype | | varchar(60) | YES | | NULL | | | height | Height of the media | smallint unsigned | YES | | NULL | | | width | Width of the media | smallint unsigned | YES | | NULL | | -| size | Media size | int unsigned | YES | | NULL | | -| preview | Preview URL | varbinary(255) | YES | | NULL | | +| size | Media size | bigint unsigned | YES | | NULL | | +| preview | Preview URL | varbinary(512) | YES | | NULL | | | preview-height | Height of the preview picture | smallint unsigned | YES | | NULL | | | preview-width | Width of the preview picture | smallint unsigned | YES | | NULL | | | description | | text | YES | | NULL | | @@ -31,11 +31,11 @@ Fields Indexes ------------ -| Name | Fields | -| ---------- | ------------------- | -| PRIMARY | id | -| uri-id-url | UNIQUE, uri-id, url | -| uri-id-id | uri-id, id | +| Name | Fields | +| ---------- | ------------------------ | +| PRIMARY | id | +| uri-id-url | UNIQUE, uri-id, url(512) | +| uri-id-id | uri-id, id | Foreign Keys ------------ diff --git a/mod/display.php b/mod/display.php index cc594d7881..ed2c9ef0f7 100644 --- a/mod/display.php +++ b/mod/display.php @@ -302,7 +302,7 @@ function display_content(App $a, $update = false, $update_uid = 0) // Preparing the meta header $description = trim(BBCode::toPlaintext($item['body'])); - $title = trim(BBCode::toPlaintext($item['title'])); + $title = trim(BBCode::toPlaintext($item['title'] ?? '')); $author_name = $item['author-name']; $image = DI::baseUrl()->remove($item['author-avatar']); diff --git a/mod/editpost.php b/mod/editpost.php index ae5f55e905..3fb8c80ec0 100644 --- a/mod/editpost.php +++ b/mod/editpost.php @@ -83,7 +83,7 @@ function editpost_content(App $a) Hook::callAll('jot_tool', $jotplugins); - $tpl = Renderer::getMarkupTemplate("jot.tpl"); + $tpl = Renderer::getMarkupTemplate('jot.tpl'); $o .= Renderer::replaceMacros($tpl, [ '$is_edit' => true, '$return_path' => '/display/' . $item['guid'], diff --git a/mod/fbrowser.php b/mod/fbrowser.php index 81284d6b91..60b290850a 100644 --- a/mod/fbrowser.php +++ b/mod/fbrowser.php @@ -47,7 +47,7 @@ function fbrowser_content(App $a) } // Needed to match the correct template in a module that uses a different theme than the user/site/default - $theme = Strings::sanitizeFilePathItem($_GET['theme'] ?? null); + $theme = Strings::sanitizeFilePathItem($_GET['theme'] ?? ''); if ($theme && is_file("view/theme/$theme/config.php")) { $a->setCurrentTheme($theme); } diff --git a/mod/item.php b/mod/item.php index adfdc4cb03..a840ea9ad9 100644 --- a/mod/item.php +++ b/mod/item.php @@ -439,8 +439,13 @@ function item_post(App $a) { // Ensure to only modify attachments that you own $srch = '<' . intval($contact_id) . '>'; - $condition = ['allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '', - 'id' => $attach]; + $condition = [ + 'allow_cid' => $srch, + 'allow_gid' => '', + 'deny_cid' => '', + 'deny_gid' => '', + 'id' => $attach, + ]; if (!Attach::exists($condition)) { continue; } @@ -520,7 +525,7 @@ function item_post(App $a) { $origin = $_REQUEST['origin']; } - $uri = Item::newURI($api_source ? $profile_uid : $uid, $guid); + $uri = Item::newURI($guid); // Fallback so that we alway have a parent uri if (!$thr_parent_uri || !$toplevel_item_id) { diff --git a/mod/photos.php b/mod/photos.php index 0e2299770a..bd9762882e 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -187,7 +187,7 @@ function photos_post(App $a) } if (DI::args()->getArgc() > 3 && DI::args()->getArgv()[2] === 'album') { - if (!Strings::isHex(DI::args()->getArgv()[3])) { + if (!Strings::isHex(DI::args()->getArgv()[3] ?? '')) { DI::baseUrl()->redirect('photos/' . $user['nickname'] . '/album'); } $album = hex2bin(DI::args()->getArgv()[3]); @@ -360,7 +360,7 @@ function photos_post(App $a) if (DBA::isResult($photos) && !$item_id) { // Create item container $title = ''; - $uri = Item::newURI($page_owner_uid); + $uri = Item::newURI(); $arr = []; $arr['guid'] = System::createUUID(); @@ -524,7 +524,7 @@ function photos_post(App $a) if (count($taginfo)) { foreach ($taginfo as $tagged) { - $uri = Item::newURI($page_owner_uid); + $uri = Item::newURI(); $arr = []; $arr['guid'] = System::createUUID(); @@ -728,7 +728,7 @@ function photos_post(App $a) $smallest = 2; } - $uri = Item::newURI($page_owner_uid); + $uri = Item::newURI(); // Create item container $lat = $lon = null; @@ -892,7 +892,7 @@ function photos_content(App $a) return; } - $selname = Strings::isHex($datum) ? hex2bin($datum) : ''; + $selname = (!is_null($datum) && Strings::isHex($datum)) ? hex2bin($datum) : ''; $albumselect = ''; @@ -954,7 +954,7 @@ function photos_content(App $a) // Display a single photo album if ($datatype === 'album') { // if $datum is not a valid hex, redirect to the default page - if (!Strings::isHex($datum)) { + if (is_null($datum) || !Strings::isHex($datum)) { DI::baseUrl()->redirect('photos/' . $user['nickname']. '/album'); } $album = hex2bin($datum); @@ -977,7 +977,7 @@ function photos_content(App $a) /// @TODO I have seen this many times, maybe generalize it script-wide and encapsulate it? $order_field = $_GET['order'] ?? ''; - if ($order_field === 'posted') { + if ($order_field === 'created') { $order = 'ASC'; } else { $order = 'DESC'; @@ -1031,10 +1031,10 @@ function photos_content(App $a) $drop = [DI::l10n()->t('Drop Album'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album) . '/drop']; } - if ($order_field === 'posted') { + if ($order_field === 'created') { $order = [DI::l10n()->t('Show Newest First'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album), 'oldest']; } else { - $order = [DI::l10n()->t('Show Oldest First'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album) . '?order=posted', 'newest']; + $order = [DI::l10n()->t('Show Oldest First'), 'photos/' . $user['nickname'] . '/album/' . bin2hex($album) . '?order=created', 'newest']; } $photos = []; @@ -1054,7 +1054,7 @@ function photos_content(App $a) 'id' => $rr['id'], 'twist' => ' ' . ($twist ? 'rotleft' : 'rotright') . rand(2,4), 'link' => 'photos/' . $user['nickname'] . '/image/' . $rr['resource-id'] - . ($order_field === 'posted' ? '?order=posted' : ''), + . ($order_field === 'created' ? '?order=created' : ''), 'title' => DI::l10n()->t('View Photo'), 'src' => 'photo/' . $rr['resource-id'] . '-' . $rr['scale'] . '.' .$ext, 'alt' => $imgalt_e, @@ -1122,7 +1122,7 @@ function photos_content(App $a) if ($cmd === 'view' && !DI::config()->get('system', 'no_count', false)) { $order_field = $_GET['order'] ?? ''; - if ($order_field === 'posted') { + if ($order_field === 'created') { $params = ['order' => [$order_field]]; } elseif (!empty($order_field)) { $params = ['order' => [$order_field => true]]; @@ -1150,10 +1150,10 @@ function photos_content(App $a) } if (!is_null($prv)) { - $prevlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$prv]['resource-id'] . ($order_field === 'posted' ? '?order=posted' : ''); + $prevlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$prv]['resource-id'] . ($order_field === 'created' ? '?order=created' : ''); } if (!is_null($nxt)) { - $nextlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$nxt]['resource-id'] . ($order_field === 'posted' ? '?order=posted' : ''); + $nextlink = 'photos/' . $user['nickname'] . '/image/' . $prvnxt[$nxt]['resource-id'] . ($order_field === 'created' ? '?order=created' : ''); } $tpl = Renderer::getMarkupTemplate('photo_edit_head.tpl'); diff --git a/mod/tagger.php b/mod/tagger.php index 1acce4b0b6..e674efba69 100644 --- a/mod/tagger.php +++ b/mod/tagger.php @@ -73,7 +73,7 @@ function tagger_content(App $a) { return; } - $uri = Item::newURI($owner_uid); + $uri = Item::newURI(); $xterm = XML::escape($term); $post_type = (($item['resource-id']) ? DI::l10n()->t('photo') : DI::l10n()->t('status')); $targettype = (($item['resource-id']) ? Activity\ObjectType::IMAGE : Activity\ObjectType::NOTE ); diff --git a/mod/wall_upload.php b/mod/wall_upload.php index 36e313cece..4554c55aa8 100644 --- a/mod/wall_upload.php +++ b/mod/wall_upload.php @@ -157,9 +157,9 @@ function wall_upload_post(App $a, $desktopmode = true) " - size: " . $filesize . " - type: " . $filetype); $imagedata = @file_get_contents($src); - $Image = new Image($imagedata, $filetype); + $image = new Image($imagedata, $filetype); - if (!$Image->isValid()) { + if (!$image->isValid()) { $msg = DI::l10n()->t('Unable to process image.'); @unlink($src); if ($r_json) { @@ -170,18 +170,18 @@ function wall_upload_post(App $a, $desktopmode = true) System::exit(); } - $Image->orient($src); + $image->orient($src); @unlink($src); $max_length = DI::config()->get('system', 'max_image_length'); if ($max_length > 0) { - $Image->scaleDown($max_length); - $filesize = strlen($Image->asString()); + $image->scaleDown($max_length); + $filesize = strlen($image->asString()); Logger::info("File upload: Scaling picture to new size " . $max_length); } - $width = $Image->getWidth(); - $height = $Image->getHeight(); + $width = $image->getWidth(); + $height = $image->getHeight(); $maximagesize = DI::config()->get('system', 'maximagesize'); @@ -190,10 +190,10 @@ function wall_upload_post(App $a, $desktopmode = true) 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(); + $image->scaleDown($pixels); + $filesize = strlen($image->asString()); + $width = $image->getWidth(); + $height = $image->getHeight(); } } if ($filesize > $maximagesize) { @@ -220,7 +220,7 @@ function wall_upload_post(App $a, $desktopmode = true) $defperm = '<' . $default_cid . '>'; - $r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0, Photo::DEFAULT, $defperm); + $r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0, Photo::DEFAULT, $defperm); if (!$r) { $msg = DI::l10n()->t('Image upload failed.'); @@ -233,16 +233,16 @@ function wall_upload_post(App $a, $desktopmode = true) } if ($width > 640 || $height > 640) { - $Image->scaleDown(640); - $r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, Photo::DEFAULT, $defperm); + $image->scaleDown(640); + $r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, Photo::DEFAULT, $defperm); if ($r) { $smallest = 1; } } if ($width > 320 || $height > 320) { - $Image->scaleDown(320); - $r = Photo::store($Image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, Photo::DEFAULT, $defperm); + $image->scaleDown(320); + $r = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, Photo::DEFAULT, $defperm); if ($r && ($smallest == 0)) { $smallest = 2; } @@ -264,8 +264,8 @@ function wall_upload_post(App $a, $desktopmode = true) $picture["height"] = $photo["height"]; $picture["type"] = $photo["type"]; $picture["albumpage"] = DI::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id; - $picture["picture"] = DI::baseUrl() . "/photo/{$resource_id}-0." . $Image->getExt(); - $picture["preview"] = DI::baseUrl() . "/photo/{$resource_id}-{$smallest}." . $Image->getExt(); + $picture["picture"] = DI::baseUrl() . "/photo/{$resource_id}-0." . $image->getExt(); + $picture["preview"] = DI::baseUrl() . "/photo/{$resource_id}-{$smallest}." . $image->getExt(); if ($r_json) { System::jsonExit(['picture' => $picture]); @@ -280,7 +280,7 @@ function wall_upload_post(App $a, $desktopmode = true) System::jsonExit(['ok' => true]); } - echo "\n\n" . '[url=' . DI::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id . '][img]' . DI::baseUrl() . "/photo/{$resource_id}-{$smallest}.".$Image->getExt()."[/img][/url]\n\n"; + echo "\n\n" . '[url=' . DI::baseUrl() . '/photos/' . $page_owner_nick . '/image/' . $resource_id . '][img]' . DI::baseUrl() . "/photo/{$resource_id}-{$smallest}." . $image->getExt() . "[/img][/url]\n\n"; System::exit(); // NOTREACHED } diff --git a/src/App.php b/src/App.php index 6fa79c5014..f59b15d1db 100644 --- a/src/App.php +++ b/src/App.php @@ -145,7 +145,7 @@ class App $this->nickname = $nickname; } - public function isLoggedIn() + public function isLoggedIn(): bool { return local_user() && $this->user_id && ($this->user_id == local_user()); } @@ -155,7 +155,7 @@ class App * * @return bool true if user is an admin */ - public function isSiteAdmin() + public function isSiteAdmin(): bool { $admin_email = $this->config->get('config', 'admin_email'); @@ -166,18 +166,18 @@ class App /** * Fetch the user id - * @return int + * @return int User id */ - public function getLoggedInUserId() + public function getLoggedInUserId(): int { return $this->user_id; } /** * Fetch the user nick name - * @return string + * @return string User's nickname */ - public function getLoggedInUserNickname() + public function getLoggedInUserNickname(): string { return $this->nickname; } @@ -198,7 +198,7 @@ class App * * @return int */ - public function getProfileOwner():int + public function getProfileOwner(): int { return $this->profile_owner; } @@ -219,7 +219,7 @@ class App * * @return int */ - public function getContactId():int + public function getContactId(): int { return $this->contact_id; } @@ -241,7 +241,7 @@ class App * * @return int */ - public function getTimeZone():string + public function getTimeZone(): string { return $this->timezone; } @@ -260,9 +260,9 @@ class App /** * Fetch workerqueue information * - * @return array + * @return array Worker queue */ - public function getQueue() + public function getQueue(): array { return $this->queue ?? []; } @@ -270,8 +270,8 @@ class App /** * Fetch a specific workerqueue field * - * @param string $index - * @return mixed + * @param string $index Work queue record to fetch + * @return mixed Work queue item or NULL if not found */ public function getQueueValue(string $index) { @@ -306,9 +306,9 @@ class App /** * The basepath of this app * - * @return string + * @return string Base path from configuration */ - public function getBasePath() + public function getBasePath(): string { // Don't use the basepath of the config table for basepath (it should always be the config-file one) return $this->config->getCache()->get('system', 'basepath'); @@ -396,10 +396,10 @@ class App /** * Returns the current theme name. May be overriden by the mobile theme name. * - * @return string + * @return string Current theme name or empty string in installation phase * @throws Exception */ - public function getCurrentTheme() + public function getCurrentTheme(): string { if ($this->mode->isInstall()) { return ''; @@ -425,10 +425,10 @@ class App /** * Returns the current mobile theme name. * - * @return string + * @return string Mobile theme name or empty string if installer * @throws Exception */ - public function getCurrentMobileTheme() + public function getCurrentMobileTheme(): string { if ($this->mode->isInstall()) { return ''; @@ -441,12 +441,22 @@ class App return $this->currentMobileTheme; } - public function setCurrentTheme($theme) + /** + * Setter for current theme name + * + * @param string $theme Name of current theme + */ + public function setCurrentTheme(string $theme) { $this->currentTheme = $theme; } - public function setCurrentMobileTheme($theme) + /** + * Setter for current mobile theme name + * + * @param string $theme Name of current mobile theme + */ + public function setCurrentMobileTheme(string $theme) { $this->currentMobileTheme = $theme; } @@ -525,10 +535,10 @@ class App /** * Provide a sane default if nothing is chosen or the specified theme does not exist. * - * @return string + * @return string Current theme's stylsheet path * @throws Exception */ - public function getCurrentThemeStylesheetPath() + public function getCurrentThemeStylesheetPath(): string { return Core\Theme::getStylesheetPath($this->getCurrentTheme()); } @@ -604,9 +614,9 @@ class App if (!empty($_GET['zrl']) && $this->mode->isNormal() && !$this->mode->isBackend() && !local_user()) { // Only continue when the given profile link seems valid // Valid profile links contain a path with "/profile/" and no query parameters - if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == "") && - strstr(parse_url($_GET['zrl'], PHP_URL_PATH), "/profile/")) { - if (Core\Session::get('visitor_home') != $_GET["zrl"]) { + if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == '') && + strstr(parse_url($_GET['zrl'], PHP_URL_PATH), '/profile/')) { + if (Core\Session::get('visitor_home') != $_GET['zrl']) { Core\Session::set('my_url', $_GET['zrl']); Core\Session::set('authenticated', 0); @@ -695,7 +705,8 @@ class App // Initialize module that can set the current theme in the init() method, either directly or via App->setProfileOwner $page['page_title'] = $moduleName; - if (!$this->mode->isInstall() && !$this->mode->has(App\Mode::MAINTENANCEDISABLED)) { + // The "view" module is required to show the theme CSS + if (!$this->mode->isInstall() && !$this->mode->has(App\Mode::MAINTENANCEDISABLED) && $moduleName !== 'view') { $module = $router->getModule(Maintenance::class); } else { // determine the module class and save it to the module instance @@ -730,7 +741,7 @@ class App * * @throws HTTPException\InternalServerErrorException */ - public function redirect($toUrl) + public function redirect(string $toUrl) { if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) { Core\System::externalRedirect($toUrl); diff --git a/src/App/Arguments.php b/src/App/Arguments.php index 4d386fc255..6dfdcb560f 100644 --- a/src/App/Arguments.php +++ b/src/App/Arguments.php @@ -78,7 +78,7 @@ class Arguments /** * @return string The whole command of this call */ - public function getCommand() + public function getCommand(): string { return $this->command; } @@ -94,7 +94,7 @@ class Arguments /** * @return array All arguments of this call */ - public function getArgv() + public function getArgv(): array { return $this->argv; } @@ -102,7 +102,7 @@ class Arguments /** * @return string The used HTTP method */ - public function getMethod() + public function getMethod(): string { return $this->method; } @@ -110,7 +110,7 @@ class Arguments /** * @return int The count of arguments of this call */ - public function getArgc() + public function getArgc(): int { return $this->argc; } @@ -145,7 +145,7 @@ class Arguments * * @return bool if the argument position exists */ - public function has(int $position) + public function has(int $position): bool { return array_key_exists($position, $this->argv); } @@ -158,7 +158,7 @@ class Arguments * * @return Arguments The determined arguments */ - public function determine(array $server, array $get) + public function determine(array $server, array $get): Arguments { // removing leading / - maybe a nginx problem $server['QUERY_STRING'] = ltrim($server['QUERY_STRING'] ?? '', '/'); diff --git a/src/App/BaseURL.php b/src/App/BaseURL.php index 9a8348510d..9152d4bc2f 100644 --- a/src/App/BaseURL.php +++ b/src/App/BaseURL.php @@ -107,7 +107,7 @@ class BaseURL * * @return string */ - public function getHostname() + public function getHostname(): string { return $this->hostname; } @@ -117,7 +117,7 @@ class BaseURL * * @return string */ - public function getScheme() + public function getScheme(): string { return $this->scheme; } @@ -127,7 +127,7 @@ class BaseURL * * @return int */ - public function getSSLPolicy() + public function getSSLPolicy(): int { return $this->sslPolicy; } @@ -137,7 +137,7 @@ class BaseURL * * @return string */ - public function getUrlPath() + public function getUrlPath(): string { return $this->urlPath; } @@ -151,7 +151,7 @@ class BaseURL * * @return string */ - public function get($ssl = false) + public function get(bool $ssl = false): string { if ($this->sslPolicy === self::SSL_POLICY_SELFSIGN && $ssl) { return Network::switchScheme($this->url); @@ -168,8 +168,9 @@ class BaseURL * @param string? $urlPath * * @return bool true, if successful + * @TODO Find proper types */ - public function save($hostname = null, $sslPolicy = null, $urlPath = null) + public function save($hostname = null, $sslPolicy = null, $urlPath = null): bool { $currHostname = $this->hostname; $currSSLPolicy = $this->sslPolicy; @@ -224,11 +225,11 @@ class BaseURL /** * Save the current url as base URL * - * @param $url + * @param string $url * * @return bool true, if the save was successful */ - public function saveByURL($url) + public function saveByURL(string $url): bool { $parsed = @parse_url($url); @@ -421,7 +422,7 @@ class BaseURL * * @return string The cleaned url */ - public function remove(string $origURL) + public function remove(string $origURL): string { // Remove the hostname from the url if it is an internal link $nurl = Strings::normaliseLink($origURL); @@ -443,9 +444,13 @@ class BaseURL * @param string $toUrl The destination URL (Default is empty, which is the default page of the Friendica node) * @param bool $ssl if true, base URL will try to get called with https:// (works just for relative paths) * + * @throws HTTPException\FoundException + * @throws HTTPException\MovedPermanentlyException + * @throws HTTPException\TemporaryRedirectException + * * @throws HTTPException\InternalServerErrorException In Case the given URL is not relative to the Friendica node */ - public function redirect($toUrl = '', $ssl = false) + public function redirect(string $toUrl = '', bool $ssl = false) { if (!empty(parse_url($toUrl, PHP_URL_SCHEME))) { throw new HTTPException\InternalServerErrorException("'$toUrl is not a relative path, please use System::externalRedirectTo"); @@ -458,8 +463,8 @@ class BaseURL /** * Returns the base url as string */ - public function __toString() + public function __toString(): string { - return $this->get(); + return (string) $this->get(); } } diff --git a/src/App/Mode.php b/src/App/Mode.php index 3e7b9f0d16..5d6bd759f2 100644 --- a/src/App/Mode.php +++ b/src/App/Mode.php @@ -130,7 +130,7 @@ class Mode * * @throws \Exception */ - public function determine(BasePath $basepath, Database $database, Cache $configCache) + public function determine(BasePath $basepath, Database $database, Cache $configCache): Mode { $mode = 0; @@ -178,7 +178,7 @@ class Mode * * @return Mode returns the determined mode */ - public function determineRunMode(bool $isBackend, array $server, Arguments $args, MobileDetect $mobileDetect) + public function determineRunMode(bool $isBackend, array $server, Arguments $args, MobileDetect $mobileDetect): Mode { foreach (self::BACKEND_CONTENT_TYPES as $type) { if (strpos(strtolower($server['HTTP_ACCEPT'] ?? ''), $type) !== false) { @@ -201,7 +201,7 @@ class Mode * * @return bool returns true, if the mode is set */ - public function has($mode) + public function has(int $mode): bool { return ($this->mode & $mode) > 0; } @@ -227,7 +227,7 @@ class Mode * * @return int Execution Mode */ - public function getExecutor() + public function getExecutor(): int { return $this->executor; } @@ -235,9 +235,9 @@ class Mode /** * Install mode is when the local config file is missing or the DB schema hasn't been installed yet. * - * @return bool + * @return bool Whether installation mode is active (local/database configuration files present or not) */ - public function isInstall() + public function isInstall(): bool { return !$this->has(Mode::LOCALCONFIGPRESENT) || !$this->has(MODE::DBCONFIGAVAILABLE); @@ -248,7 +248,7 @@ class Mode * * @return bool */ - public function isNormal() + public function isNormal(): bool { return $this->has(Mode::LOCALCONFIGPRESENT) && $this->has(Mode::DBAVAILABLE) && @@ -261,7 +261,7 @@ class Mode * * @return bool Is it a backend call */ - public function isBackend() + public function isBackend(): bool { return $this->isBackend; } @@ -271,7 +271,7 @@ class Mode * * @return bool true if it was an AJAX request */ - public function isAjax() + public function isAjax(): bool { return $this->isAjax; } @@ -281,7 +281,7 @@ class Mode * * @return bool true if it was an mobile request */ - public function isMobile() + public function isMobile(): bool { return $this->isMobile; } @@ -291,7 +291,7 @@ class Mode * * @return bool true if it was an tablet request */ - public function isTablet() + public function isTablet(): bool { return $this->isTablet; } diff --git a/src/App/Page.php b/src/App/Page.php index d38757687c..475681054a 100644 --- a/src/App/Page.php +++ b/src/App/Page.php @@ -195,7 +195,7 @@ class Page implements ArrayAccess * @param string $media * @see Page::initHead() */ - public function registerStylesheet($path, string $media = 'screen') + public function registerStylesheet(string $path, string $media = 'screen') { $path = Network::appendQueryParam($path, ['v' => FRIENDICA_VERSION]); @@ -288,7 +288,7 @@ class Page implements ArrayAccess * * Taken from http://webcheatsheet.com/php/get_current_page_url.php */ - private function curPageURL() + private function curPageURL(): string { $pageURL = 'http'; if (!empty($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) { diff --git a/src/App/Request.php b/src/App/Request.php new file mode 100644 index 0000000000..71b6a9ea3f --- /dev/null +++ b/src/App/Request.php @@ -0,0 +1,152 @@ +. + * + */ + +namespace Friendica\App; + +use Friendica\Core\Config\Capability\IManageConfigValues; + +/** + * Container for the whole request + * + * @see https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface + * + * @todo future container class for whole requests, currently it's not :-) + */ +class Request +{ + /** + * A comma separated list of default headers that could contain the client IP in a proxy request + * + * @var string + */ + const DEFAULT_FORWARD_FOR_HEADER = 'HTTP_X_FORWARDED_FOR'; + + /** @var string The remote IP address of the current request */ + protected $remoteAddress; + + /** + * @return string The remote IP address of the current request + * + * Do always use this instead of $_SERVER['REMOTE_ADDR'] + */ + public function getRemoteAddress(): string + { + return $this->remoteAddress; + } + + public function __construct(IManageConfigValues $config, array $server = []) + { + $this->remoteAddress = $this->determineRemoteAddress($config, $server); + } + + /** + * Checks if given $remoteAddress matches given $trustedProxy. + * If $trustedProxy is an IPv4 IP range given in CIDR notation, true will be returned if + * $remoteAddress is an IPv4 address within that IP range. + * Otherwise, $remoteAddress will be compared to $trustedProxy literally and the result + * will be returned. + * + * @param string $trustedProxy The current, trusted proxy to check + * @param string $remoteAddress The current remote IP address + * + * + * @return boolean true if $remoteAddress matches $trustedProxy, false otherwise + */ + protected function matchesTrustedProxy(string $trustedProxy, string $remoteAddress): bool + { + $cidrre = '/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/([0-9]{1,2})$/'; + + if (preg_match($cidrre, $trustedProxy, $match)) { + $net = $match[1]; + $shiftbits = min(32, max(0, 32 - intval($match[2]))); + $netnum = ip2long($net) >> $shiftbits; + $ipnum = ip2long($remoteAddress) >> $shiftbits; + + return $ipnum === $netnum; + } + + return $trustedProxy === $remoteAddress; + } + + /** + * Checks if given $remoteAddress matches any entry in the given array $trustedProxies. + * For details regarding what "match" means, refer to `matchesTrustedProxy`. + * + * @param string[] $trustedProxies A list of the trusted proxies + * @param string $remoteAddress The current remote IP address + * + * @return boolean true if $remoteAddress matches any entry in $trustedProxies, false otherwise + */ + protected function isTrustedProxy(array $trustedProxies, string $remoteAddress): bool + { + foreach ($trustedProxies as $tp) { + if ($this->matchesTrustedProxy($tp, $remoteAddress)) { + return true; + } + } + + return false; + } + + /** + * Determines the remote address, if the connection came from a trusted proxy + * and `forwarded_for_headers` has been configured then the IP address + * specified in this header will be returned instead. + * + * @param IManageConfigValues $config + * @param array $server The $_SERVER array + * + * @return string + */ + protected function determineRemoteAddress(IManageConfigValues $config, array $server): string + { + $remoteAddress = $server['REMOTE_ADDR'] ?? '0.0.0.0'; + $trustedProxies = preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', $config->get('proxy', 'trusted_proxies', '')); + + if (\is_array($trustedProxies) && $this->isTrustedProxy($trustedProxies, $remoteAddress)) { + $forwardedForHeaders = preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', $config->get('proxy', 'forwarded_for_headers', static::DEFAULT_FORWARD_FOR_HEADER)); + + foreach ($forwardedForHeaders as $header) { + if (isset($server[$header])) { + foreach (explode(',', $server[$header]) as $IP) { + $IP = trim($IP); + + // remove brackets from IPv6 addresses + if (strpos($IP, '[') === 0 && substr($IP, -1) === ']') { + $IP = substr($IP, 1, -1); + } + + // skip trusted proxies in the list itself + if ($this->isTrustedProxy($trustedProxies, $IP)) { + continue; + } + + if (filter_var($IP, FILTER_VALIDATE_IP) !== false) { + return $IP; + } + } + } + } + } + + return $remoteAddress; + } +} diff --git a/src/App/Router.php b/src/App/Router.php index 6e390a84d9..9906568925 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -152,7 +152,7 @@ class Router * * @throws HTTPException\InternalServerErrorException In case of invalid configs */ - public function loadRoutes(array $routes) + public function loadRoutes(array $routes): Router { $routeCollector = ($this->routeCollector ?? new RouteCollector(new Std(), new GroupCountBased())); @@ -166,6 +166,13 @@ class Router return $this; } + /** + * Adds multiple routes to a route collector + * + * @param RouteCollector $routeCollector Route collector instance + * @param array $routes Multiple routes to be added + * @throws HTTPException\InternalServerErrorException If route was wrong (somehow) + */ private function addRoutes(RouteCollector $routeCollector, array $routes) { foreach ($routes as $route => $config) { @@ -221,7 +228,7 @@ class Router * * @return bool */ - private function isRoute(array $config) + private function isRoute(array $config): bool { return // The config array should at least have one entry @@ -253,7 +260,7 @@ class Router * @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't * @throws HTTPException\NotFoundException If no rule matched */ - private function getModuleClass() + private function getModuleClass(): string { $cmd = $this->args->getCommand(); $cmd = '/' . ltrim($cmd, '/'); diff --git a/src/BaseCollection.php b/src/BaseCollection.php index 0bf46f0dcb..f6fa9bbd4d 100644 --- a/src/BaseCollection.php +++ b/src/BaseCollection.php @@ -70,9 +70,11 @@ class BaseCollection extends \ArrayIterator } /** - * @return int + * Getter for total count + * + * @return int Total count */ - public function getTotalCount() + public function getTotalCount(): int { return $this->totalCount; } @@ -85,7 +87,7 @@ class BaseCollection extends \ArrayIterator * @return array * @see array_column() */ - public function column($column, $index_key = null) + public function column(string $column, $index_key = null): array { return array_column($this->getArrayCopy(true), $column, $index_key); } @@ -97,7 +99,7 @@ class BaseCollection extends \ArrayIterator * @return BaseCollection * @see array_map() */ - public function map(callable $callback) + public function map(callable $callback): BaseCollection { return new static(array_map($callback, $this->getArrayCopy()), $this->getTotalCount()); } @@ -110,7 +112,7 @@ class BaseCollection extends \ArrayIterator * @return BaseCollection * @see array_filter() */ - public function filter(callable $callback = null, int $flag = 0) + public function filter(callable $callback = null, int $flag = 0): BaseCollection { return new static(array_filter($this->getArrayCopy(), $callback, $flag)); } diff --git a/src/BaseEntity.php b/src/BaseEntity.php index 8e8938febc..065d100fa3 100644 --- a/src/BaseEntity.php +++ b/src/BaseEntity.php @@ -55,14 +55,14 @@ abstract class BaseEntity extends BaseDataTransferObject } /** - * @param $name + * @param mixed $name * @return bool * @throws HTTPException\InternalServerErrorException */ - public function __isset($name) + public function __isset($name): bool { if (!property_exists($this, $name)) { - throw new HTTPException\InternalServerErrorException('Unknown property ' . $name . ' in Entity ' . static::class); + throw new HTTPException\InternalServerErrorException('Unknown property ' . $name . ' of type ' . gettype($name) . ' in Entity ' . static::class); } return !empty($this->$name); diff --git a/src/BaseModel.php b/src/BaseModel.php index 768e9e9e53..06a61c505a 100644 --- a/src/BaseModel.php +++ b/src/BaseModel.php @@ -110,11 +110,11 @@ abstract class BaseModel extends BaseDataTransferObject * - $model->field (outside of class) * - $this->field (inside of class) * - * @param $name + * @param string $name Name of data to fetch * @return mixed * @throws HTTPException\InternalServerErrorException */ - public function __get($name) + public function __get(string $name) { $this->checkValid(); diff --git a/src/BaseModule.php b/src/BaseModule.php index c03a77e29e..99c297b756 100644 --- a/src/BaseModule.php +++ b/src/BaseModule.php @@ -102,6 +102,7 @@ abstract class BaseModule implements ICanHandleRequests * e.g. from protocol implementations. * * @param string[] $request The $_REQUEST content + * @return void */ protected function rawContent(array $request = []) { @@ -117,6 +118,7 @@ abstract class BaseModule implements ICanHandleRequests * XML feed or a JSON output. * * @param string[] $request The $_REQUEST content + * @return string */ protected function content(array $request = []): string { @@ -130,6 +132,7 @@ abstract class BaseModule implements ICanHandleRequests * Doesn't display any content * * @param string[] $request The $_REQUEST content + * @return void */ protected function delete(array $request = []) { @@ -142,6 +145,7 @@ abstract class BaseModule implements ICanHandleRequests * Doesn't display any content * * @param string[] $request The $_REQUEST content + * @return void */ protected function patch(array $request = []) { @@ -154,7 +158,7 @@ abstract class BaseModule implements ICanHandleRequests * Doesn't display any content * * @param string[] $request The $_REQUEST content - * + * @return void */ protected function post(array $request = []) { @@ -168,6 +172,7 @@ abstract class BaseModule implements ICanHandleRequests * Doesn't display any content * * @param string[] $request The $_REQUEST content + * @return void */ protected function put(array $request = []) { @@ -279,12 +284,12 @@ abstract class BaseModule implements ICanHandleRequests /** * Fetch a request value and apply default values and check against minimal and maximal values * - * @param array $input - * @param string $parameter - * @param mixed $default - * @param mixed $minimal_value - * @param mixed $maximum_value - * @return mixed + * @param array $input Input fields + * @param string $parameter Parameter + * @param mixed $default Default + * @param mixed $minimal_value Minimal value + * @param mixed $maximum_value Maximum value + * @return mixed null on error anything else on success (?) */ public function getRequestValue(array $input, string $parameter, $default = null, $minimal_value = null, $maximum_value = null) { @@ -320,7 +325,7 @@ abstract class BaseModule implements ICanHandleRequests return $value; } - /* + /** * Functions used to protect against Cross-Site Request Forgery * The security token has to base on at least one value that an attacker can't know - here it's the session ID and the private key. * In this implementation, a security token is reusable (if the user submits a form, goes back and resubmits the form, maybe with small changes; @@ -330,8 +335,11 @@ abstract class BaseModule implements ICanHandleRequests * If the new page contains by any chance external elements, then the used security token is exposed by the referrer. * Actually, important actions should not be triggered by Links / GET-Requests at all, but sometimes they still are, * so this mechanism brings in some damage control (the attacker would be able to forge a request to a form of this type, but not to forms of other types). + * + * @param string $typename Type name + * @return string Security hash with timestamp */ - public static function getFormSecurityToken($typename = '') + public static function getFormSecurityToken(string $typename = ''): string { $user = User::getById(DI::app()->getLoggedInUserId(), ['guid', 'prvkey']); $timestamp = time(); @@ -340,7 +348,14 @@ abstract class BaseModule implements ICanHandleRequests return $timestamp . '.' . $sec_hash; } - public static function checkFormSecurityToken($typename = '', $formname = 'form_security_token') + /** + * Checks if form's security (CSRF) token is valid. + * + * @param string $typename ??? + * @param string $formname Name of form/field (???) + * @return bool Whether it is valid + */ + public static function checkFormSecurityToken(string $typename = '', string $formname = 'form_security_token'): bool { $hash = null; @@ -372,12 +387,12 @@ abstract class BaseModule implements ICanHandleRequests return ($sec_hash == $x[1]); } - public static function getFormSecurityStandardErrorMessage() + public static function getFormSecurityStandardErrorMessage(): string { return DI::l10n()->t("The form security token was not correct. This probably happened because the form has been opened for too long \x28>3 hours\x29 before submitting it.") . EOL; } - public static function checkFormSecurityTokenRedirectOnError($err_redirect, $typename = '', $formname = 'form_security_token') + public static function checkFormSecurityTokenRedirectOnError(string $err_redirect, string $typename = '', string $formname = 'form_security_token') { if (!self::checkFormSecurityToken($typename, $formname)) { Logger::notice('checkFormSecurityToken failed: user ' . DI::app()->getLoggedInUserNickname() . ' - form element ' . $typename); @@ -387,7 +402,7 @@ abstract class BaseModule implements ICanHandleRequests } } - public static function checkFormSecurityTokenForbiddenOnError($typename = '', $formname = 'form_security_token') + public static function checkFormSecurityTokenForbiddenOnError(string $typename = '', string $formname = 'form_security_token') { if (!self::checkFormSecurityToken($typename, $formname)) { Logger::notice('checkFormSecurityToken failed: user ' . DI::app()->getLoggedInUserNickname() . ' - form element ' . $typename); @@ -397,7 +412,7 @@ abstract class BaseModule implements ICanHandleRequests } } - protected static function getContactFilterTabs(string $baseUrl, string $current, bool $displayCommonTab) + protected static function getContactFilterTabs(string $baseUrl, string $current, bool $displayCommonTab): array { $tabs = [ [ diff --git a/src/Console/Addon.php b/src/Console/Addon.php index 1389e97bf4..13e1951f2e 100644 --- a/src/Console/Addon.php +++ b/src/Console/Addon.php @@ -82,7 +82,7 @@ HELP; AddonCore::loadAddons(); } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); @@ -116,8 +116,7 @@ HELP; /** * Lists plugins * - * @return int Return code of this command - * + * @return int|bool Return code of this command, false on error (?) * @throws \Exception */ private function list() @@ -165,10 +164,9 @@ HELP; * Enables an addon * * @return int Return code of this command - * * @throws \Exception */ - private function enable() + private function enable(): int { $addonname = $this->getArgument(1); @@ -190,10 +188,9 @@ HELP; * Disables an addon * * @return int Return code of this command - * * @throws \Exception */ - private function disable() + private function disable(): int { $addonname = $this->getArgument(1); diff --git a/src/Console/ArchiveContact.php b/src/Console/ArchiveContact.php index 4990d99e0b..4bd832a616 100644 --- a/src/Console/ArchiveContact.php +++ b/src/Console/ArchiveContact.php @@ -80,7 +80,7 @@ HELP; $this->l10n = $l10n; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/AutomaticInstallation.php b/src/Console/AutomaticInstallation.php index e3e9e22cb3..1a6d10c241 100644 --- a/src/Console/AutomaticInstallation.php +++ b/src/Console/AutomaticInstallation.php @@ -110,7 +110,7 @@ HELP; $this->dba = $dba; } - protected function doExecute() + protected function doExecute(): int { // Initialise the app $this->out("Initializing setup..."); @@ -225,7 +225,7 @@ HELP; $installer->resetChecks(); - if (!$installer->installDatabase($basePathConf)) { + if (!$installer->installDatabase()) { $errorMessage = $this->extractErrors($installer->getChecks()); throw new RuntimeException($errorMessage); } diff --git a/src/Console/Cache.php b/src/Console/Cache.php index e02d2225a2..5062872e84 100644 --- a/src/Console/Cache.php +++ b/src/Console/Cache.php @@ -90,7 +90,7 @@ HELP; $this->cache = $cache; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Executable: ' . $this->executable); diff --git a/src/Console/Config.php b/src/Console/Config.php index e32983a68a..760b1ca51b 100644 --- a/src/Console/Config.php +++ b/src/Console/Config.php @@ -102,7 +102,7 @@ HELP; $this->config = $config; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Executable: ' . $this->executable); diff --git a/src/Console/Contact.php b/src/Console/Contact.php index f051d870a2..37f3f056e4 100644 --- a/src/Console/Contact.php +++ b/src/Console/Contact.php @@ -76,7 +76,7 @@ HELP; $this->appMode = $appMode; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/CreateDoxygen.php b/src/Console/CreateDoxygen.php index f7cdeaa3ef..3d5ba865c0 100644 --- a/src/Console/CreateDoxygen.php +++ b/src/Console/CreateDoxygen.php @@ -45,7 +45,7 @@ HELP; return $help; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/DatabaseStructure.php b/src/Console/DatabaseStructure.php index 652abfd97d..88f12476f5 100644 --- a/src/Console/DatabaseStructure.php +++ b/src/Console/DatabaseStructure.php @@ -25,6 +25,12 @@ use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Update; use Friendica\Database\Database; use Friendica\Database\DBStructure; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; +use Friendica\Util\BasePath; +use Friendica\Util\Writer\DbaDefinitionSqlWriter; +use Friendica\Util\Writer\DocWriter; +use Friendica\Util\Writer\ViewDefinitionSqlWriter; use RuntimeException; /** @@ -34,15 +40,21 @@ class DatabaseStructure extends \Asika\SimpleConsole\Console { protected $helpOptions = ['h', 'help', '?']; - /** - * @var Database - */ + /** @var Database */ private $dba; - /** - * @var Cache - */ + + /** @var Cache */ private $configCache; + /** @var DbaDefinition */ + private $dbaDefinition; + + /** @var ViewDefinition */ + private $viewDefinition; + + /** @var string */ + private $basePath; + protected function getHelp() { $help = <<dba = $dba; + $this->dbaDefinition = $dbaDefinition; + $this->viewDefinition = $viewDefinition; $this->configCache = $configCache; + $this->basePath = $basePath->getPath(); } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); @@ -120,10 +135,9 @@ HELP; $output = ob_get_clean(); break; case "dumpsql": - DBStructure::writeStructure(); - ob_start(); - DBStructure::printStructure($basePath); - $output = ob_get_clean(); + DocWriter::writeDbDefinition($this->dbaDefinition, $this->basePath); + $output = DbaDefinitionSqlWriter::create($this->dbaDefinition); + $output .= ViewDefinitionSqlWriter::create($this->viewDefinition); break; case "toinnodb": ob_start(); diff --git a/src/Console/DocBloxErrorChecker.php b/src/Console/DocBloxErrorChecker.php index 9e9eb14970..3d3a2b6d86 100644 --- a/src/Console/DocBloxErrorChecker.php +++ b/src/Console/DocBloxErrorChecker.php @@ -71,7 +71,7 @@ HELP; return $help; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/Extract.php b/src/Console/Extract.php index 1d651f6413..06015f6970 100644 --- a/src/Console/Extract.php +++ b/src/Console/Extract.php @@ -49,7 +49,7 @@ HELP; return $help; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/FixAPDeliveryWorkerTaskParameters.php b/src/Console/FixAPDeliveryWorkerTaskParameters.php index e4b895dead..eb285da8d7 100644 --- a/src/Console/FixAPDeliveryWorkerTaskParameters.php +++ b/src/Console/FixAPDeliveryWorkerTaskParameters.php @@ -85,7 +85,7 @@ HELP; $this->l10n = $l10n; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/GlobalCommunityBlock.php b/src/Console/GlobalCommunityBlock.php index 39ce6d3014..81099712ea 100644 --- a/src/Console/GlobalCommunityBlock.php +++ b/src/Console/GlobalCommunityBlock.php @@ -70,7 +70,7 @@ HELP; $this->l10n = $l10n; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/GlobalCommunitySilence.php b/src/Console/GlobalCommunitySilence.php index a493bbcb86..89674efd39 100644 --- a/src/Console/GlobalCommunitySilence.php +++ b/src/Console/GlobalCommunitySilence.php @@ -75,7 +75,7 @@ HELP; $this->dba =$dba; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/Lock.php b/src/Console/Lock.php index eea5d51e10..a89f3d861a 100644 --- a/src/Console/Lock.php +++ b/src/Console/Lock.php @@ -84,7 +84,7 @@ HELP; $this->lock = $lock; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Executable: ' . $this->executable); diff --git a/src/Console/Maintenance.php b/src/Console/Maintenance.php index 7e73182846..7744c9ee47 100644 --- a/src/Console/Maintenance.php +++ b/src/Console/Maintenance.php @@ -77,7 +77,7 @@ HELP; $this->config = $config; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/MergeContacts.php b/src/Console/MergeContacts.php index 543ad316e7..0d05c579fa 100644 --- a/src/Console/MergeContacts.php +++ b/src/Console/MergeContacts.php @@ -67,7 +67,7 @@ HELP; $this->l10n = $l10n; } - protected function doExecute() + protected function doExecute(): int { $duplicates = $this->dba->p("SELECT COUNT(*) AS `total`, `uri-id`, MAX(`url`) AS `url` FROM `contact` WHERE `uid` = 0 GROUP BY `uri-id` HAVING total > 1"); while ($duplicate = $this->dba->fetch($duplicates)) { diff --git a/src/Console/MoveToAvatarCache.php b/src/Console/MoveToAvatarCache.php index 441dff682d..1f3147791f 100644 --- a/src/Console/MoveToAvatarCache.php +++ b/src/Console/MoveToAvatarCache.php @@ -85,7 +85,7 @@ HELP; $this->config = $config; } - protected function doExecute() + protected function doExecute(): int { if (!$this->config->get('system', 'avatar_cache')) { $this->err($this->l10n->t('The avatar cache needs to be enabled to use this command.')); diff --git a/src/Console/PhpToPo.php b/src/Console/PhpToPo.php index a6667048f4..4041c4069c 100644 --- a/src/Console/PhpToPo.php +++ b/src/Console/PhpToPo.php @@ -63,7 +63,7 @@ HELP; return $help; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/PoToPhp.php b/src/Console/PoToPhp.php index b67327826b..4f28db88b2 100644 --- a/src/Console/PoToPhp.php +++ b/src/Console/PoToPhp.php @@ -50,7 +50,7 @@ HELP; return $help; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/PostUpdate.php b/src/Console/PostUpdate.php index 376d3abb4b..8bec14e276 100644 --- a/src/Console/PostUpdate.php +++ b/src/Console/PostUpdate.php @@ -69,7 +69,7 @@ HELP; $this->l10n = $l10n; } - protected function doExecute() + protected function doExecute(): int { $a = \Friendica\DI::app(); diff --git a/src/Console/Relay.php b/src/Console/Relay.php index dfa39d8600..f06c3a7d5c 100644 --- a/src/Console/Relay.php +++ b/src/Console/Relay.php @@ -76,7 +76,7 @@ HELP; $this->dba = $dba; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Executable: ' . $this->executable); diff --git a/src/Console/Relocate.php b/src/Console/Relocate.php index c0054d3963..c1db6ef534 100644 --- a/src/Console/Relocate.php +++ b/src/Console/Relocate.php @@ -74,7 +74,7 @@ HELP; $this->config = $config; } - protected function doExecute() + protected function doExecute(): int { if (count($this->args) == 0) { $this->out($this->getHelp()); diff --git a/src/Console/ServerBlock.php b/src/Console/ServerBlock.php index 9bf2c0ecca..38ae35d105 100644 --- a/src/Console/ServerBlock.php +++ b/src/Console/ServerBlock.php @@ -79,7 +79,7 @@ HELP; $this->config = $config; } - protected function doExecute() + protected function doExecute(): int { if (count($this->args) == 0) { $this->printBlockedServers($this->config); diff --git a/src/Console/Storage.php b/src/Console/Storage.php index d5af7c5135..587601ba0c 100644 --- a/src/Console/Storage.php +++ b/src/Console/Storage.php @@ -69,7 +69,7 @@ HELP; return $help; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Executable: ' . $this->executable); diff --git a/src/Console/Test.php b/src/Console/Test.php index 062e386f05..15c6bf60b0 100644 --- a/src/Console/Test.php +++ b/src/Console/Test.php @@ -42,7 +42,7 @@ HELP; return $help; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/Typo.php b/src/Console/Typo.php index 1397f6092f..4414662e7f 100644 --- a/src/Console/Typo.php +++ b/src/Console/Typo.php @@ -60,7 +60,7 @@ HELP; $this->config = $config; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Console/User.php b/src/Console/User.php index 1c1d26b0a9..586c300eaf 100644 --- a/src/Console/User.php +++ b/src/Console/User.php @@ -97,7 +97,7 @@ HELP; $this->pConfig = $pConfig; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Class: ' . __CLASS__); diff --git a/src/Contact/Avatar.php b/src/Contact/Avatar.php index 60981485e8..f43ed7b8c7 100644 --- a/src/Contact/Avatar.php +++ b/src/Contact/Avatar.php @@ -123,7 +123,7 @@ class Avatar return $fields; } - private static function getFilename(string $url) + private static function getFilename(string $url): string { $guid = Item::guidFromUri($url, parse_url($url, PHP_URL_HOST)); diff --git a/src/Contact/LocalRelationship/Factory/LocalRelationship.php b/src/Contact/LocalRelationship/Factory/LocalRelationship.php index 74ddd8e7a3..5e53f5b467 100644 --- a/src/Contact/LocalRelationship/Factory/LocalRelationship.php +++ b/src/Contact/LocalRelationship/Factory/LocalRelationship.php @@ -52,7 +52,7 @@ class LocalRelationship extends BaseFactory implements ICanCreateFromTableRow $row['hub-verify'] ?? '', $row['protocol'] ?? Protocol::PHANTOM, $row['rating'] ?? null, - $row['priority'] ?? null + $row['priority'] ?? 0 ); } } diff --git a/src/Content/BoundariesPager.php b/src/Content/BoundariesPager.php index 358539794c..df6ebf08a5 100644 --- a/src/Content/BoundariesPager.php +++ b/src/Content/BoundariesPager.php @@ -49,7 +49,7 @@ class BoundariesPager extends Pager * @param string $last_item_id The id† of the last item in the displayed item list * @param integer $itemsPerPage An optional number of items per page to override the default value */ - public function __construct(L10n $l10n, $queryString, $first_item_id = null, $last_item_id = null, $itemsPerPage = 50) + public function __construct(L10n $l10n, string $queryString, string $first_item_id = null, string $last_item_id = null, int $itemsPerPage = 50) { parent::__construct($l10n, $queryString, $itemsPerPage); @@ -73,12 +73,12 @@ class BoundariesPager extends Pager } } - public function getStart() + public function getStart(): int { throw new \BadMethodCallException(); } - public function getPage() + public function getPage(): int { throw new \BadMethodCallException(); } @@ -102,7 +102,7 @@ class BoundariesPager extends Pager * @return string HTML string of the pager * @throws \Exception */ - public function renderMinimal(int $itemCount) + public function renderMinimal(int $itemCount): string { $displayedItemCount = max(0, intval($itemCount)); @@ -130,7 +130,10 @@ class BoundariesPager extends Pager return Renderer::replaceMacros($tpl, ['pager' => $data]); } - public function renderFull($itemCount) + /** + * Unsupported method, must be type-compatible + */ + public function renderFull(int $itemCount): string { throw new \BadMethodCallException(); } diff --git a/src/Content/ContactSelector.php b/src/Content/ContactSelector.php index 6c7e09945f..db7ad80ca6 100644 --- a/src/Content/ContactSelector.php +++ b/src/Content/ContactSelector.php @@ -41,7 +41,7 @@ class ContactSelector * @param boolean $disabled optional, default false * @return string */ - public static function pollInterval($current, $disabled = false) + public static function pollInterval(string $current, bool $disabled = false): string { $dis = (($disabled) ? ' disabled="disabled" ' : ''); $o = ''; @@ -84,7 +84,7 @@ class ContactSelector * @return string Server URL * @throws \Exception */ - private static function getServerURLForProfile($profile) + private static function getServerURLForProfile(string $profile): string { if (!empty(self::$server_url[$profile])) { return self::$server_url[$profile]; @@ -111,13 +111,16 @@ class ContactSelector } /** + * Determines network name + * * @param string $network network of the contact * @param string $profile optional, default empty * @param string $protocol (Optional) Protocol that is used for the transmission + * @param int $gsid Server id * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function networkToName($network, $profile = '', $protocol = '', $gsid = 0) + public static function networkToName(string $network, string $profile = '', string $protocol = '', int $gsid = null): string { $nets = [ Protocol::DFRN => DI::l10n()->t('DFRN'), @@ -179,12 +182,15 @@ class ContactSelector } /** + * Determines network's icon name + * * @param string $network network * @param string $profile optional, default empty - * @return string + * @param int $gsid Server id + * @return string Name for network icon * @throws \Exception */ - public static function networkToIcon($network, $profile = "", $gsid = 0) + public static function networkToIcon(string $network, string $profile = "", int $gsid = null): string { $nets = [ Protocol::DFRN => 'friendica', diff --git a/src/Content/Conversation.php b/src/Content/Conversation.php index a82cb35e00..5bb47b23b1 100644 --- a/src/Content/Conversation.php +++ b/src/Content/Conversation.php @@ -154,7 +154,7 @@ class Conversation } // Skip when the causer of the parent is the same as the author of the announce - if (($verb == Activity::ANNOUNCE) && !empty($thread_parent['causer-id'] && ($thread_parent['causer-id'] == $activity['author-id']))) { + if (($verb == Activity::ANNOUNCE) && !empty($thread_parent['causer-id']) && ($thread_parent['causer-id'] == $activity['author-id'])) { continue; } @@ -189,7 +189,7 @@ class Conversation * @return string formatted text * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function formatActivity(array $links, $verb, $id) + public function formatActivity(array $links, string $verb, int $id): string { $this->profiler->startRecording('rendering'); $o = ''; @@ -275,7 +275,7 @@ class Conversation return $o; } - public function statusEditor(array $x = [], $notes_cid = 0, $popup = false) + public function statusEditor(array $x = [], int $notes_cid = 0, bool $popup = false): string { $user = User::getById($this->app->getLoggedInUserId(), ['uid', 'nickname', 'allow_location', 'default-location']); if (empty($user['uid'])) { @@ -414,8 +414,8 @@ class Conversation * 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 $mode - * @param $update + * @param string $mode + * @param $update @TODO Which type? * @param bool $preview * @param string $order * @param int $uid @@ -423,7 +423,7 @@ class Conversation * @throws ImagickException * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function create(array $items, $mode, $update, $preview = false, $order = 'commented', $uid = 0) + public function create(array $items, string $mode, $update, bool $preview = false, string $order = 'commented', int $uid = 0): string { $this->profiler->startRecording('rendering'); @@ -582,7 +582,7 @@ class Conversation $uriids[] = $item['uri-id']; - if (!$this->item->visibleActivity($item)) { + if (!$this->item->isVisibleActivity($item)) { continue; } @@ -745,7 +745,7 @@ class Conversation continue; } - if (!$this->item->visibleActivity($item)) { + if (!$this->item->isVisibleActivity($item)) { continue; } @@ -784,7 +784,7 @@ class Conversation return $o; } - private function getBlocklist() + private function getBlocklist(): array { if (!local_user()) { return []; @@ -816,7 +816,7 @@ class Conversation * * @return array items with parents and comments */ - private function addRowInformation(array $row, array $activity, array $thr_parent) + private function addRowInformation(array $row, array $activity, array $thr_parent): array { $this->profiler->startRecording('rendering'); @@ -911,7 +911,7 @@ class Conversation * @return array items with parents and comments * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode) + private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode): array { $this->profiler->startRecording('rendering'); if (count($parents) > 1) { @@ -1005,7 +1005,7 @@ class Conversation * @param bool $recursive * @return array */ - private function getItemChildren(array &$item_list, array $parent, $recursive = true) + private function getItemChildren(array &$item_list, array $parent, bool $recursive = true): array { $this->profiler->startRecording('rendering'); $children = []; @@ -1040,7 +1040,7 @@ class Conversation * @param array $items * @return array */ - private function sortItemChildren(array $items) + private function sortItemChildren(array $items): array { $this->profiler->startRecording('rendering'); $result = $items; @@ -1086,7 +1086,7 @@ class Conversation * @param array $parent A tree-like array of items * @return array */ - private function smartFlattenConversation(array $parent) + private function smartFlattenConversation(array $parent): array { $this->profiler->startRecording('rendering'); if (!isset($parent['children']) || count($parent['children']) == 0) { @@ -1142,7 +1142,7 @@ class Conversation * @return array * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private function convSort(array $item_list, $order) + private function convSort(array $item_list, string $order): array { $this->profiler->startRecording('rendering'); $parents = []; @@ -1222,7 +1222,7 @@ class Conversation * @param array $b * @return int */ - private function sortThrFeaturedReceived(array $a, array $b) + private function sortThrFeaturedReceived(array $a, array $b): int { if ($b['featured'] && !$a['featured']) { return 1; @@ -1240,7 +1240,7 @@ class Conversation * @param array $b * @return int */ - private function sortThrFeaturedCommented(array $a, array $b) + private function sortThrFeaturedCommented(array $a, array $b): int { if ($b['featured'] && !$a['featured']) { return 1; @@ -1258,7 +1258,7 @@ class Conversation * @param array $b * @return int */ - private function sortThrReceived(array $a, array $b) + private function sortThrReceived(array $a, array $b): int { return strcmp($b['received'], $a['received']); } @@ -1270,7 +1270,7 @@ class Conversation * @param array $b * @return int */ - private function sortThrReceivedRev(array $a, array $b) + private function sortThrReceivedRev(array $a, array $b): int { return strcmp($a['received'], $b['received']); } @@ -1282,7 +1282,7 @@ class Conversation * @param array $b * @return int */ - private function sortThrCommented(array $a, array $b) + private function sortThrCommented(array $a, array $b): int { return strcmp($b['commented'], $a['commented']); } @@ -1294,7 +1294,7 @@ class Conversation * @param array $b * @return int */ - private function sortThrCreated(array $a, array $b) + private function sortThrCreated(array $a, array $b): int { return strcmp($b['created'], $a['created']); } diff --git a/src/Content/Item.php b/src/Content/Item.php index 66dcde0ff3..ccd3396c22 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -85,7 +85,7 @@ class Item * ] * ] */ - public function determineCategoriesTerms(array $item, int $uid = 0) + public function determineCategoriesTerms(array $item, int $uid = 0): array { $categories = []; $folders = []; @@ -141,16 +141,16 @@ class Item * This function removes the tag $tag from the text $body and replaces it with * the appropriate link. * - * @param string $body the text to replace the tag in - * @param integer $profile_uid the user id to replace the tag for (0 = anyone) - * @param string $tag the tag to replace - * @param string $network The network of the post + * @param string $body the text to replace the tag in + * @param int $profile_uid the user id to replace the tag for (0 = anyone) + * @param string $tag the tag to replace + * @param string $network The network of the post * - * @return array|bool ['replaced' => $replaced, 'contact' => $contact]; + * @return array|bool ['replaced' => $replaced, 'contact' => $contact] or "false" on if already replaced * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function replaceTag(&$body, $profile_uid, $tag, $network = '') + public static function replaceTag(string &$body, int $profile_uid, string $tag, string $network = '') { $replaced = false; @@ -244,16 +244,17 @@ class Item /** * Render actions localized * - * @param $item + * @param array $item + * @return void * @throws ImagickException * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function localize(&$item) + public function localize(array &$item) { $this->profiler->startRecording('rendering'); /// @todo The following functionality needs to be cleaned up. if (!empty($item['verb'])) { - $xmlhead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">"; + $xmlhead = ''; if (stristr($item['verb'], Activity::POKE)) { $verb = urldecode(substr($item['verb'], strpos($item['verb'],'#') + 1)); @@ -261,7 +262,7 @@ class Item $this->profiler->stopRecording(); return; } - if ($item['object-type'] == "" || $item['object-type'] !== Activity\ObjectType::PERSON) { + if ($item['object-type'] == '' || $item['object-type'] !== Activity\ObjectType::PERSON) { $this->profiler->stopRecording(); return; } @@ -270,18 +271,22 @@ class Item $Bname = $obj->title; $Blink = $obj->id; - $Bphoto = ""; + $Bphoto = ''; foreach ($obj->link as $l) { $atts = $l->attributes(); switch ($atts['rel']) { - case "alternate": $Blink = $atts['href']; - case "photo": $Bphoto = $atts['href']; + case 'alternate': $Blink = $atts['href']; + case 'photo': $Bphoto = $atts['href']; } } - $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'], + ]; $A = '[url=' . Contact::magicLinkByContact($author) . ']' . $item['author-name'] . '[/url]'; if (!empty($Blink)) { @@ -290,7 +295,7 @@ class Item $B = ''; } - if ($Bphoto != "" && !empty($Blink)) { + if ($Bphoto != '' && !empty($Blink)) { $Bphoto = '[url=' . Contact::magicLink($Blink) . '][img=80x80]' . $Bphoto . '[/img][/url]'; } @@ -305,9 +310,7 @@ class Item $txt = str_replace($poked_t, $this->l10n->t($verb), $txt); // then do the sprintf on the translation string - $item['body'] = sprintf($txt, $A, $B) . "\n\n\n" . $Bphoto; - } if ($this->activity->match($item['verb'], Activity::TAG)) { @@ -319,12 +322,20 @@ class Item return; } - $author_arr = ['uid' => 0, 'id' => $item['author-id'], - 'network' => $item['author-network'], 'url' => $item['author-link']]; + $author_arr = [ + 'uid' => 0, + 'id' => $item['author-id'], + 'network' => $item['author-network'], + 'url' => $item['author-link'], + ]; $author = '[url=' . Contact::magicLinkByContact($author_arr) . ']' . $item['author-name'] . '[/url]'; - $author_arr = ['uid' => 0, 'id' => $obj['author-id'], - 'network' => $obj['author-network'], 'url' => $obj['author-link']]; + $author_arr = [ + 'uid' => 0, + 'id' => $obj['author-id'], + 'network' => $obj['author-network'], + 'url' => $obj['author-link'], + ]; $objauthor = '[url=' . Contact::magicLinkByContact($author_arr) . ']' . $obj['author-name'] . '[/url]'; switch ($obj['verb']) { @@ -337,6 +348,7 @@ class Item $post_type = $this->l10n->t('status'); } break; + default: if ($obj['resource-id']) { $post_type = $this->l10n->t('photo'); @@ -360,25 +372,29 @@ class Item $this->profiler->stopRecording(); } - public function photoMenu($item, string $formSecurityToken) + /** + * Renders photo menu based on item + * + * @param array $item + * @param string $formSecurityToken + * @return string + */ + public function photoMenu(array $item, string $formSecurityToken): string { $this->profiler->startRecording('rendering'); - $sub_link = ''; - $poke_link = ''; - $contact_url = ''; - $pm_url = ''; - $status_link = ''; - $photos_link = ''; - $posts_link = ''; - $block_link = ''; - $ignore_link = ''; + $sub_link = $poke_link = $contact_url = $pm_url = $status_link = ''; + $photos_link = $posts_link = $block_link = $ignore_link = ''; if (local_user() && local_user() == $item['uid'] && $item['gravity'] == GRAVITY_PARENT && !$item['self'] && !$item['mention']) { $sub_link = 'javascript:doFollowThread(' . $item['id'] . '); return false;'; } - $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'], + ]; $profile_link = Contact::magicLinkByContact($author, $item['author-link']); $sparkle = (strpos($profile_link, 'redir/') === 0); @@ -435,7 +451,7 @@ class Item } if ($network == Protocol::DFRN) { - $menu[$this->l10n->t("Poke")] = $poke_link; + $menu[$this->l10n->t('Poke')] = $poke_link; } if ((($cid == 0) || ($rel == Contact::FOLLOWER)) && @@ -465,24 +481,28 @@ class Item return $o; } - public function visibleActivity($item) { - + /** + * Checks if the activity is visible to current user + * + * @param array $item Activity item + * @return bool Whether the item is visible to the user + */ + public function isVisibleActivity(array $item): bool + { + // Empty verb or hidden? if (empty($item['verb']) || $this->activity->isHidden($item['verb'])) { return false; } - // @TODO below if() block can be rewritten to a single line: $isVisible = allConditionsHere; - if ($this->activity->match($item['verb'], Activity::FOLLOW) && + // Check conditions + return (!($this->activity->match($item['verb'], Activity::FOLLOW) && $item['object-type'] === Activity\ObjectType::NOTE && empty($item['self']) && - $item['uid'] == local_user()) { - return false; - } - - return true; + $item['uid'] == local_user()) + ); } - public function expandTags(array $item, bool $setPermissions = false) + public function expandTags(array $item, bool $setPermissions = false): array { // Look for any tags and linkify them $item['inform'] = ''; diff --git a/src/Content/Nav.php b/src/Content/Nav.php index c30a157067..77f068863a 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -62,7 +62,7 @@ class Nav * * @param string $item */ - public static function setSelected($item) + public static function setSelected(string $item) { self::$selected[$item] = 'selected'; } @@ -74,7 +74,7 @@ class Nav * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function build(App $a) + public static function build(App $a): string { // Placeholder div for popup panel $nav = ''; @@ -106,7 +106,7 @@ class Nav * * @return array */ - public static function getAppMenu() + public static function getAppMenu(): array { if (is_null(self::$app_menu)) { self::populateAppMenu(); @@ -117,6 +117,8 @@ class Nav /** * Fills the apps static variable with apps that require a menu + * + * @return void */ private static function populateAppMenu() { diff --git a/src/Content/OEmbed.php b/src/Content/OEmbed.php index dbba99fcff..498a65e33b 100644 --- a/src/Content/OEmbed.php +++ b/src/Content/OEmbed.php @@ -49,7 +49,13 @@ use Friendica\Util\Strings; */ class OEmbed { - public static function replaceCallback($matches) + /** + * Callback for fetching URL, checking allowance and returning formatted HTML + * + * @param array $matches + * @return string Formatted HTML + */ + public static function replaceCallback(array $matches): string { $embedurl = $matches[1]; $j = self::fetchURL($embedurl, !self::isAllowedURL($embedurl)); @@ -68,7 +74,7 @@ class OEmbed * @return \Friendica\Object\OEmbed * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function fetchURL($embedurl, bool $no_rich_type = false, bool $use_parseurl = true) + public static function fetchURL(string $embedurl, bool $no_rich_type = false, bool $use_parseurl = true): \Friendica\Object\OEmbed { $embedurl = trim($embedurl, '\'"'); @@ -209,12 +215,18 @@ class OEmbed return $oembed; } - private static function formatObject(\Friendica\Object\OEmbed $oembed) + /** + * Returns a formatted string from OEmbed object + * + * @param \Friendica\Object\OEmbed $oembed + * @return string + */ + private static function formatObject(\Friendica\Object\OEmbed $oembed): string { $ret = '
'; switch ($oembed->type) { - case "video": + case 'video': if ($oembed->thumbnail_url) { $tw = (isset($oembed->thumbnail_width) && intval($oembed->thumbnail_width)) ? $oembed->thumbnail_width : 200; $th = (isset($oembed->thumbnail_height) && intval($oembed->thumbnail_height)) ? $oembed->thumbnail_height : 180; @@ -236,14 +248,14 @@ class OEmbed } break; - case "photo": + case 'photo': $ret .= ''; break; - case "link": + case 'link': break; - case "rich": + case 'rich': $ret .= Proxy::proxifyHtml($oembed->html); break; } @@ -292,9 +304,15 @@ class OEmbed return str_replace("\n", "", $ret); } - public static function BBCode2HTML($text) + /** + * Converts BBCode to HTML code + * + * @param string $text + * @return string + */ + public static function BBCode2HTML(string $text): string { - $stopoembed = DI::config()->get("system", "no_oembed"); + $stopoembed = DI::config()->get('system', 'no_oembed'); if ($stopoembed == true) { return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "" . DI::l10n()->t('Embedding disabled') . " : $1", $text); } @@ -305,14 +323,13 @@ class OEmbed * Find .... * and replace it with [embed]url[/embed] * - * @param $text + * @param string $text * @return string */ - public static function HTML2BBCode($text) + public static function HTML2BBCode(string $text): string { // start parser only if 'oembed' is in text - if (strpos($text, "oembed")) { - + if (strpos($text, 'oembed')) { // convert non ascii chars to html entities $html_text = mb_convert_encoding($text, 'HTML-ENTITIES', mb_detect_encoding($text)); @@ -323,17 +340,17 @@ class OEmbed } $xpath = new DOMXPath($dom); - $xattr = self::buildXPath("class", "oembed"); + $xattr = self::buildXPath('class', 'oembed'); $entries = $xpath->query("//div[$xattr]"); $xattr = "@rel='oembed'"; //oe_build_xpath("rel","oembed"); foreach ($entries as $e) { $href = $xpath->evaluate("a[$xattr]/@href", $e)->item(0)->nodeValue; if (!is_null($href)) { - $e->parentNode->replaceChild(new DOMText("[embed]" . $href . "[/embed]"), $e); + $e->parentNode->replaceChild(new DOMText('[embed]' . $href . '[/embed]'), $e); } } - return self::getInnerHTML($dom->getElementsByTagName("body")->item(0)); + return self::getInnerHTML($dom->getElementsByTagName('body')->item(0)); } else { return $text; } @@ -346,7 +363,7 @@ class OEmbed * @return boolean * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function isAllowedURL($url) + public static function isAllowedURL(string $url): bool { if (!DI::config()->get('system', 'no_oembed_rich_content')) { return true; @@ -367,7 +384,14 @@ class OEmbed return Network::isDomainAllowed($domain, $allowed); } - public static function getHTML($url, $title = null) + /** + * Returns a formmated HTML code from given URL and sets optional title + * + * @param string $url URL to fetch + * @param string $title Optional title (default: what comes from OEmbed object) + * @return string Formatted HTML + */ + public static function getHTML(string $url, string $title = '') { $o = self::fetchURL($url, !self::isAllowedURL($url)); @@ -401,12 +425,12 @@ class OEmbed * @param string $src Original remote URL to embed * @param string $width * @param string $height - * @return string formatted HTML + * @return string Formatted HTML * * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @see oembed_format_object() */ - private static function iframe($src, $width, $height) + private static function iframe(string $src, string $width, string $height): string { if (!$height || strstr($height, '%')) { $height = '200'; @@ -427,7 +451,7 @@ class OEmbed * @param string $value Value to search in a space-separated list * @return string */ - private static function buildXPath($attr, $value) + private static function buildXPath(string $attr, $value): string { // https://www.westhoffswelt.de/blog/2009/6/9/select-html-elements-with-more-than-one-css-class-using-xpath return "contains(normalize-space(@$attr), ' $value ') or substring(normalize-space(@$attr), 1, string-length('$value') + 1) = '$value ' or substring(normalize-space(@$attr), string-length(@$attr) - string-length('$value')) = ' $value' or @$attr = '$value'"; @@ -439,7 +463,7 @@ class OEmbed * @param DOMNode $node * @return string */ - private static function getInnerHTML(DOMNode $node) + private static function getInnerHTML(DOMNode $node): string { $innerHTML = ''; $children = $node->childNodes; diff --git a/src/Content/PageInfo.php b/src/Content/PageInfo.php index 41ecb3d7fa..71ffebc444 100644 --- a/src/Content/PageInfo.php +++ b/src/Content/PageInfo.php @@ -64,7 +64,7 @@ class PageInfo * @return string * @throws HTTPException\InternalServerErrorException */ - public static function appendDataToBody(string $body, array $data, bool $no_photos = false) + public static function appendDataToBody(string $body, array $data, bool $no_photos = false): string { // Only one [attachment] tag per body is allowed $existingAttachmentPos = strpos($body, '[attachment'); @@ -90,7 +90,7 @@ class PageInfo * @return string * @throws HTTPException\InternalServerErrorException */ - public static function getFooterFromUrl(string $url, bool $no_photos = false, string $photo = '', bool $keywords = false, string $keyword_denylist = '') + public static function getFooterFromUrl(string $url, bool $no_photos = false, string $photo = '', bool $keywords = false, string $keyword_denylist = ''): string { $data = self::queryUrl($url, $photo, $keywords, $keyword_denylist); @@ -103,7 +103,7 @@ class PageInfo * @return string * @throws HTTPException\InternalServerErrorException */ - public static function getFooterFromData(array $data, bool $no_photos = false) + public static function getFooterFromData(array $data, bool $no_photos = false): string { Hook::callAll('page_info_data', $data); @@ -220,7 +220,7 @@ class PageInfo * @return array * @throws HTTPException\InternalServerErrorException */ - public static function getTagsFromUrl(string $url, string $photo = '', string $keyword_denylist = '') + public static function getTagsFromUrl(string $url, string $photo = '', string $keyword_denylist = ''): array { $data = self::queryUrl($url, $photo, true, $keyword_denylist); @@ -282,7 +282,7 @@ class PageInfo * @param string $url * @return string */ - protected static function stripTrailingUrlFromBody(string $body, string $url) + protected static function stripTrailingUrlFromBody(string $body, string $url): string { $quotedUrl = preg_quote($url, '#'); $body = preg_replace_callback("#(?: diff --git a/src/Content/Pager.php b/src/Content/Pager.php index bf5a5f6914..98b885d425 100644 --- a/src/Content/Pager.php +++ b/src/Content/Pager.php @@ -48,11 +48,11 @@ class Pager * * Guesses the page number from the GET parameter 'page'. * - * @param L10n $l10n - * @param string $queryString The query string of the current page - * @param integer $itemsPerPage An optional number of items per page to override the default value + * @param L10n $l10n + * @param string $queryString The query string of the current page + * @param int $itemsPerPage An optional number of items per page to override the default value */ - public function __construct(L10n $l10n, $queryString, $itemsPerPage = 50) + public function __construct(L10n $l10n, string $queryString, int $itemsPerPage = 50) { $this->l10n = $l10n; @@ -64,9 +64,9 @@ class Pager /** * Returns the start offset for a LIMIT clause. Starts at 0. * - * @return integer + * @return int */ - public function getStart() + public function getStart(): int { return max(0, ($this->page * $this->itemsPerPage) - $this->itemsPerPage); } @@ -74,9 +74,9 @@ class Pager /** * Returns the number of items per page * - * @return integer + * @return int */ - public function getItemsPerPage() + public function getItemsPerPage(): int { return $this->itemsPerPage; } @@ -86,7 +86,7 @@ class Pager * * @return int */ - public function getPage() + public function getPage(): int { return $this->page; } @@ -108,9 +108,9 @@ class Pager /** * Sets the number of items per page, 1 minimum. * - * @param integer $itemsPerPage + * @param int $itemsPerPage */ - public function setItemsPerPage($itemsPerPage) + public function setItemsPerPage(int $itemsPerPage) { $this->itemsPerPage = max(1, intval($itemsPerPage)); } @@ -118,11 +118,11 @@ class Pager /** * Sets the current page number. Starts at 1. * - * @param integer $page + * @param int $page */ - public function setPage($page) + public function setPage(int $page) { - $this->page = max(1, intval($page)); + $this->page = max(1, $page); } /** @@ -132,7 +132,7 @@ class Pager * * @param string $queryString */ - public function setQueryString($queryString) + public function setQueryString(string $queryString) { $stripped = preg_replace('/([&?]page=[0-9]*)/', '', $queryString); @@ -160,7 +160,7 @@ class Pager * @return string HTML string of the pager * @throws \Exception */ - public function renderMinimal(int $itemCount) + public function renderMinimal(int $itemCount): string { $displayedItemCount = max(0, intval($itemCount)); @@ -199,13 +199,13 @@ class Pager * * $html = $pager->renderFull(); * - * @param integer $itemCount The total number of items including those note displayed on the page + * @param int $itemCount The total number of items including those note displayed on the page * @return string HTML string of the pager * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function renderFull($itemCount) + public function renderFull(int $itemCount): string { - $totalItemCount = max(0, intval($itemCount)); + $totalItemCount = max(0, $itemCount); $data = []; diff --git a/src/Content/Smilies.php b/src/Content/Smilies.php index 411f03b463..04dcf99070 100644 --- a/src/Content/Smilies.php +++ b/src/Content/Smilies.php @@ -39,10 +39,9 @@ class Smilies * @param array $b Array of emoticons * @param string $smiley The text smilie * @param string $representation The replacement - * * @return void */ - public static function add(&$b, $smiley, $representation) + public static function add(array &$b, string $smiley, string $representation) { $found = array_search($smiley, $b['texts']); @@ -66,7 +65,7 @@ class Smilies * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @hook smilie ('texts' => smilies texts array, 'icons' => smilies html array) */ - public static function getList() + public static function getList(): array { $texts = [ '<3', @@ -169,7 +168,7 @@ class Smilies * * @return string $subject with all substrings in the $search array replaced by the values in the $replace array */ - private static function strOrigReplace($search, $replace, $subject) + private static function strOrigReplace(array $search, array $replace, string $subject): string { return strtr($subject, array_combine($search, $replace)); } @@ -191,7 +190,7 @@ class Smilies * @return string HTML Output of the Smilie * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function replace($s, $no_images = false) + public static function replace(string $s, bool $no_images = false): string { $smilies = self::getList(); @@ -211,7 +210,7 @@ class Smilies * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function replaceFromArray($text, array $smilies, $no_images = false) + public static function replaceFromArray(string $text, array $smilies, bool $no_images = false): string { if (intval(DI::config()->get('system', 'no_smilies')) || (local_user() && intval(DI::pConfig()->get(local_user(), 'system', 'no_smilies'))) @@ -234,7 +233,7 @@ class Smilies $smilies = $cleaned; } - $text = preg_replace_callback('/<(3+)/', 'self::pregHeart', $text); + $text = preg_replace_callback('/<(3+)/', 'self::heartReplaceCallback', $text); $text = self::strOrigReplace($smilies['texts'], $smilies['icons'], $text); $text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', 'self::decode', $text); @@ -244,22 +243,24 @@ class Smilies } /** - * @param string $m string + * Encodes smiley match array to BASE64 string * + * @param array $m Match array * @return string base64 encoded string */ - private static function encode($m) + private static function encode(array $m): string { return '<' . $m[1] . '>' . Strings::base64UrlEncode($m[2]) . ''; } /** - * @param string $m string + * Decodes a previously BASE64-encoded match array to a string * + * @param array $m Matches array * @return string base64 decoded string * @throws \Exception */ - private static function decode($m) + private static function decode(array $m): string { return '<' . $m[1] . '>' . Strings::base64UrlDecode($m[2]) . ''; } @@ -268,24 +269,20 @@ class Smilies /** * expand <3333 to the correct number of hearts * - * @param string $x string - * + * @param array $matches * @return string HTML Output - * - * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function pregHeart($x) + private static function heartReplaceCallback(array $matches): string { - if (strlen($x[1]) == 1) { - return $x[0]; + if (strlen($matches[1]) == 1) { + return $matches[0]; } $t = ''; - for ($cnt = 0; $cnt < strlen($x[1]); $cnt ++) { + for ($cnt = 0; $cnt < strlen($matches[1]); $cnt ++) { $t .= '❤'; } - $r = str_replace($x[0], $t, $x[0]); - return $r; + return str_replace($matches[0], $t, $matches[0]); } } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 8a3eb3d570..7bb65b698f 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -81,7 +81,7 @@ class BBCode * 'description' -> Description of the attachment * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function getOldAttachmentData($body) + private static function getOldAttachmentData(string $body): array { $post = []; @@ -152,7 +152,7 @@ class BBCode * 'description' -> Description of the attachment * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getAttachmentData($body) + public static function getAttachmentData(string $body): array { DI::profiler()->startRecording('rendering'); $data = [ @@ -187,26 +187,31 @@ class BBCode case 'publisher_name': $data['provider_name'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); break; + case 'publisher_url': $data['provider_url'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); break; + case 'author_name': $data['author_name'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); if ($data['provider_name'] == $data['author_name']) { $data['author_name'] = ''; } break; + case 'author_url': $data['author_url'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); if ($data['provider_url'] == $data['author_url']) { $data['author_url'] = ''; } break; + case 'title': $value = self::convert(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), false, true); $value = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); $value = str_replace(['[', ']'], ['[', ']'], $value); $data['title'] = $value; + default: $data[$field] = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); break; @@ -241,7 +246,7 @@ class BBCode return $data; } - public static function getAttachedData($body, $item = []) + public static function getAttachedData(string $body, array $item = []): array { /* - text: @@ -303,7 +308,7 @@ class BBCode // Workaround: // Sometimes photo posts to the own album are not detected at the start. // So we seem to cannot use the cache for these cases. That's strange. - if (($data['type'] != 'photo') && strstr($pictures[0][1], "/photos/")) { + if (($data['type'] != 'photo') && strstr($pictures[0][1], '/photos/')) { $data = ParseUrl::getSiteinfo($pictures[0][1]); } @@ -320,7 +325,7 @@ class BBCode $post['text'] = trim(str_replace($pictures[0][0], '', $body)); } else { $imgdata = Images::getInfoFromURLCached($pictures[0][1]); - if ($imgdata && substr($imgdata['mime'], 0, 6) == 'image/') { + if (($imgdata) && substr($imgdata['mime'], 0, 6) == 'image/') { $post['type'] = 'photo'; $post['image'] = $pictures[0][1]; $post['preview'] = $pictures[0][2]; @@ -390,7 +395,7 @@ class BBCode } if (!isset($post['type'])) { - $post['type'] = "text"; + $post['type'] = 'text'; $post['text'] = trim($body); } @@ -419,10 +424,9 @@ class BBCode * * @param string $body * @param boolean $no_link_desc No link description - * * @return string with replaced body */ - public static function removeAttachment($body, $no_link_desc = false) + public static function removeAttachment(string $body, bool $no_link_desc = false): string { return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism", function ($match) use ($body, $no_link_desc) { @@ -442,12 +446,11 @@ class BBCode /** * Converts a BBCode text into plaintext * - * @param $text + * @param string $text * @param bool $keep_urls Whether to keep URLs in the resulting plaintext - * * @return string */ - public static function toPlaintext($text, $keep_urls = true) + public static function toPlaintext(string $text, bool $keep_urls = true): string { DI::profiler()->startRecording('rendering'); // Remove pictures in advance to avoid unneeded proxy calls @@ -463,7 +466,7 @@ class BBCode return $naked_text; } - private static function proxyUrl($image, $simplehtml = self::INTERNAL, $uriid = 0, $size = '') + private static function proxyUrl(string $image, int $simplehtml = self::INTERNAL, int $uriid = 0, string $size = ''): string { // Only send proxied pictures to API and for internal display if (!in_array($simplehtml, [self::INTERNAL, self::API])) { @@ -483,7 +486,7 @@ class BBCode * @param string $srctext The body with images * @return string The body with possibly scaled images */ - public static function scaleExternalImages(string $srctext) + public static function scaleExternalImages(string $srctext): string { DI::profiler()->startRecording('rendering'); $s = $srctext; @@ -551,7 +554,7 @@ class BBCode * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function limitBodySize($body) + public static function limitBodySize(string $body): string { DI::profiler()->startRecording('rendering'); $maxlen = DI::config()->get('config', 'max_import_size', 0); @@ -646,7 +649,7 @@ class BBCode * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function convertAttachment($text, $simplehtml = self::INTERNAL, $tryoembed = true, array $data = [], $uriid = 0) + public static function convertAttachment(string $text, int $simplehtml = self::INTERNAL, bool $tryoembed = true, array $data = [], int $uriid = 0): string { DI::profiler()->startRecording('rendering'); $data = $data ?: self::getAttachmentData($text); @@ -659,10 +662,10 @@ class BBCode $data['title'] = strip_tags($data['title']); $data['title'] = str_replace(['http://', 'https://'], '', $data['title']); } else { - $data['title'] = null; + $data['title'] = ''; } - if (((strpos($data['text'], "[img=") !== false) || (strpos($data['text'], "[img]") !== false) || DI::config()->get('system', 'always_show_preview')) && !empty($data['image'])) { + if (((strpos($data['text'], '[img=') !== false) || (strpos($data['text'], '[img]') !== false) || DI::config()->get('system', 'always_show_preview')) && !empty($data['image'])) { $data['preview'] = $data['image']; $data['image'] = ''; } @@ -716,14 +719,14 @@ class BBCode return trim(($data['text'] ?? '') . ' ' . $return . ' ' . ($data['after'] ?? '')); } - public static function removeShareInformation($Text, $plaintext = false, $nolink = false) + public static function removeShareInformation(string $text, bool $plaintext = false, bool $nolink = false): string { DI::profiler()->startRecording('rendering'); - $data = self::getAttachmentData($Text); + $data = self::getAttachmentData($text); if (!$data) { DI::profiler()->stopRecording(); - return $Text; + return $text; } elseif ($nolink) { DI::profiler()->stopRecording(); return $data['text'] . ($data['after'] ?? ''); @@ -767,7 +770,7 @@ class BBCode * @param array $match Array with the matching values * @return string reformatted link including HTML codes */ - private static function convertUrlForActivityPubCallback($match) + private static function convertUrlForActivityPubCallback(array $match): string { $url = $match[1]; @@ -789,10 +792,9 @@ class BBCode * @param string $url URL that is about to be reformatted * @return string reformatted link including HTML codes */ - private static function convertUrlForActivityPub($url) + private static function convertUrlForActivityPub(string $url): string { - $html = '%s'; - return sprintf($html, $url, self::getStyledURL($url)); + return sprintf('%s', $url, self::getStyledURL($url)); } /** @@ -801,7 +803,7 @@ class BBCode * @param string $url URL that is about to be reformatted * @return string reformatted link */ - private static function getStyledURL($url) + private static function getStyledURL(string $url): string { $parts = parse_url($url); $scheme = $parts['scheme'] . '://'; @@ -818,8 +820,11 @@ class BBCode * [noparse][i]italic[/i][/noparse] turns into * [noparse][ i ]italic[ /i ][/noparse], * to hide them from parser. + * + * @param array $match + * @return string */ - private static function escapeNoparseCallback($match) + private static function escapeNoparseCallback(array $match): string { $whole_match = $match[0]; $captured = $match[1]; @@ -832,8 +837,11 @@ class BBCode * The previously spacefied [noparse][ i ]italic[ /i ][/noparse], * now turns back and the [noparse] tags are trimed * returning [i]italic[/i] + * + * @param array $match + * @return string */ - private static function unescapeNoparseCallback($match) + private static function unescapeNoparseCallback(array $match): string { $captured = $match[1]; $unspacefied = preg_replace("/\[ (.*?)\ ]/", "[$1]", $captured); @@ -849,7 +857,7 @@ class BBCode * @param int $occurrences Number of first occurrences to skip * @return boolean|array */ - public static function getTagPosition($text, $name, $occurrences = 0) + public static function getTagPosition(string $text, string $name, int $occurrences = 0) { DI::profiler()->startRecording('rendering'); if ($occurrences < 0) { @@ -913,7 +921,7 @@ class BBCode * @param string $text Text to search * @return string */ - public static function pregReplaceInTag($pattern, $replace, $name, $text) + public static function pregReplaceInTag(string $pattern, string $replace, string $name, string $text): string { DI::profiler()->startRecording('rendering'); $occurrences = 0; @@ -936,7 +944,7 @@ class BBCode return $text; } - private static function extractImagesFromItemBody($body) + private static function extractImagesFromItemBody(string $body): array { $saved_image = []; $orig_body = $body; @@ -977,7 +985,7 @@ class BBCode return ['body' => $new_body, 'images' => $saved_image]; } - private static function interpolateSavedImagesIntoItemBody($uriid, $body, array $images) + private static function interpolateSavedImagesIntoItemBody(int $uriid, string $body, array $images): string { $newbody = $body; @@ -995,29 +1003,51 @@ class BBCode } /** - * - * @param string $text A BBCode string - * @return array share attributes + * @param string $text A BBCode string + * @return array Empty array if no share tag is present or the following array, missing attributes end up empty strings: + * - comment: Text before the opening share tag + * - shared : Text inside the share tags + * - author : (Optional) Display name of the shared author + * - profile: (Optional) Profile page URL of the shared author + * - avatar : (Optional) Profile picture URL of the shared author + * - link : (Optional) Canonical URL of the shared post + * - posted : (Optional) Date the shared post was initially posted ("Y-m-d H:i:s" in GMT) + * - guid : (Optional) Shared post GUID if any */ - public static function fetchShareAttributes($text) + public static function fetchShareAttributes(string $text): array { DI::profiler()->startRecording('rendering'); // See Issue https://github.com/friendica/friendica/issues/10454 // Hashtags in usernames are expanded to links. This here is a quick fix. - $text = preg_replace('/([@!#])\[url\=.*?\](.*?)\[\/url\]/ism', '$1$2', $text); + $text = preg_replace('~([@!#])\[url=.*?](.*?)\[/url]~ism', '$1$2', $text); - $attributes = []; - if (!preg_match("/(.*?)\[share(.*?)\](.*)\[\/share\]/ism", $text, $matches)) { + if (!preg_match('~(.*?)\[share(.*?)](.*)\[/share]~ism', $text, $matches)) { DI::profiler()->stopRecording(); - return $attributes; + return []; } - $attribute_string = $matches[2]; + $attributes = self::extractShareAttributes($matches[2]); + + $attributes['comment'] = trim($matches[1]); + $attributes['shared'] = trim($matches[3]); + + DI::profiler()->stopRecording(); + return $attributes; + } + + /** + * @see BBCode::fetchShareAttributes() + * @param string $shareString Internal opening share tag string matched by the regular expression + * @return array A fixed attribute array where missing attribute are represented by empty strings + */ + private static function extractShareAttributes(string $shareString): array + { + $attributes = []; foreach (['author', 'profile', 'avatar', 'link', 'posted', 'guid'] as $field) { - preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches); + preg_match("/$field=(['\"])(.+?)\\1/ism", $shareString, $matches); $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'); } - DI::profiler()->stopRecording(); + return $attributes; } @@ -1040,18 +1070,13 @@ class BBCode * @param callable $callback * @return string The BBCode string with all [share] blocks replaced */ - public static function convertShare($text, callable $callback, int $uriid = 0) + public static function convertShare(string $text, callable $callback, int $uriid = 0): string { DI::profiler()->startRecording('rendering'); $return = preg_replace_callback( - "/(.*?)\[share(.*?)\](.*)\[\/share\]/ism", + '~(.*?)\[share(.*?)](.*)\[/share]~ism', function ($match) use ($callback, $uriid) { - $attribute_string = $match[2]; - $attributes = []; - foreach (['author', 'profile', 'avatar', 'link', 'posted', 'guid'] as $field) { - preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches); - $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'); - } + $attributes = self::extractShareAttributes($match[2]); $author_contact = Contact::getByURL($attributes['profile'], false, ['id', 'url', 'addr', 'name', 'micro']); $author_contact['url'] = ($author_contact['url'] ?? $attributes['profile']); @@ -1086,7 +1111,7 @@ class BBCode * @param integer $uriid * @return string */ - private static function convertImages(string $text, int $simplehtml, int $uriid = 0):string + private static function convertImages(string $text, int $simplehtml, int $uriid = 0): string { DI::profiler()->startRecording('rendering'); $return = preg_replace_callback( @@ -1129,7 +1154,7 @@ class BBCode * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function convertShareCallback(array $attributes, array $author_contact, $content, $is_quote_share, $simplehtml) + private static function convertShareCallback(array $attributes, array $author_contact, string $content, bool $is_quote_share, int $simplehtml): string { DI::profiler()->startRecording('rendering'); $mention = $attributes['author'] . ' (' . ($author_contact['addr'] ?? '') . ')'; @@ -1198,7 +1223,7 @@ class BBCode return $text; } - private static function removePictureLinksCallback($match) + private static function removePictureLinksCallback(array $match): string { $cache_key = 'remove:' . $match[1]; $text = DI::cache()->get($cache_key); @@ -1212,9 +1237,9 @@ class BBCode } if (substr($mimetype, 0, 6) == 'image/') { - $text = "[url=" . $match[1] . ']' . $match[1] . "[/url]"; + $text = '[url=' . $match[1] . ']' . $match[1] . '[/url]'; } else { - $text = "[url=" . $match[2] . ']' . $match[2] . "[/url]"; + $text = '[url=' . $match[2] . ']' . $match[2] . '[/url]'; // if its not a picture then look if its a page that contains a picture link $body = DI::httpClient()->fetch($match[1], HttpClientAccept::HTML, 0); @@ -1226,7 +1251,7 @@ class BBCode $doc = new DOMDocument(); @$doc->loadHTML($body); $xpath = new DOMXPath($doc); - $list = $xpath->query("//meta[@name]"); + $list = $xpath->query('//meta[@name]'); foreach ($list as $node) { $attr = []; @@ -1247,16 +1272,28 @@ class BBCode return $text; } - private static function expandLinksCallback($match) + /** + * Callback: Expands links from given $match array + * + * @param arrat $match Array with link match + * @return string BBCode + */ + private static function expandLinksCallback(array $match): string { if (($match[3] == '') || ($match[2] == $match[3]) || stristr($match[2], $match[3])) { - return ($match[1] . "[url]" . $match[2] . "[/url]"); + return ($match[1] . '[url]' . $match[2] . '[/url]'); } else { - return ($match[1] . $match[3] . " [url]" . $match[2] . "[/url]"); + return ($match[1] . $match[3] . ' [url]' . $match[2] . '[/url]'); } } - private static function cleanPictureLinksCallback($match) + /** + * Callback: Cleans picture links + * + * @param arrat $match Array with link match + * @return string BBCode + */ + private static function cleanPictureLinksCallback(array $match): string { // When the picture link is the own photo path then we can avoid fetching the link $own_photo_url = preg_quote(Strings::normaliseLink(DI::baseUrl()->get()) . '/photos/'); @@ -1302,7 +1339,7 @@ class BBCode $doc = new DOMDocument(); @$doc->loadHTML($body); $xpath = new DOMXPath($doc); - $list = $xpath->query("//meta[@name]"); + $list = $xpath->query('//meta[@name]'); foreach ($list as $node) { $attr = []; if ($node->attributes->length) { @@ -1325,7 +1362,13 @@ class BBCode return $text; } - public static function cleanPictureLinks($text) + /** + * Cleans picture links + * + * @param string $text HTML/BBCode string + * @return string Cleaned HTML/BBCode + */ + public static function cleanPictureLinks(string $text): string { DI::profiler()->startRecording('rendering'); $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $text); @@ -1334,7 +1377,13 @@ class BBCode return $return; } - public static function removeLinks(string $bbcode) + /** + * Removes links + * + * @param string $text HTML/BBCode string + * @return string Cleaned HTML/BBCode + */ + public static function removeLinks(string $bbcode): string { DI::profiler()->startRecording('rendering'); $bbcode = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", ' $1 ', $bbcode); @@ -1350,10 +1399,10 @@ class BBCode /** * Replace names in mentions with nicknames * - * @param string $body + * @param string $body HTML/BBCode * @return string Body with replaced mentions */ - public static function setMentionsToNicknames(string $body):string + public static function setMentionsToNicknames(string $body): string { DI::profiler()->startRecording('rendering'); $regexp = "/([@!])\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; @@ -1366,10 +1415,10 @@ class BBCode * Callback function to replace a Friendica style mention in a mention with the nickname * * @param array $match Matching values for the callback - * @return string Replaced mention + * @return string Replaced mention or empty string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function mentionCallback($match) + private static function mentionCallback(array $match): string { if (empty($match[2])) { return ''; @@ -1407,7 +1456,7 @@ class BBCode * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function convertForUriId(int $uriid = null, string $text = null, int $simple_html = self::INTERNAL) + public static function convertForUriId(int $uriid = null, string $text = null, int $simple_html = self::INTERNAL): string { $try_oembed = ($simple_html == self::INTERNAL); @@ -1437,10 +1486,10 @@ class BBCode * @param int $simple_html * @param bool $for_plaintext * @param int $uriid - * @return string + * @return string Converted code or empty string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function convert(string $text = null, $try_oembed = true, $simple_html = self::INTERNAL, $for_plaintext = false, $uriid = 0) + public static function convert(string $text = null, bool $try_oembed = true, int $simple_html = self::INTERNAL, bool $for_plaintext = false, int $uriid = 0): string { // Accounting for null default column values if (is_null($text) || $text === '') { @@ -1462,10 +1511,10 @@ class BBCode * $match[1] = $url * $match[2] = $title or absent */ - $try_oembed_callback = function ($match) + $try_oembed_callback = function (array $match) { $url = $match[1]; - $title = $match[2] ?? null; + $title = $match[2] ?? ''; try { $return = OEmbed::getHTML($url, $title); @@ -1788,7 +1837,7 @@ class BBCode $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); - //$Text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $Text); + //$text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); // Simplify "video" element $text = preg_replace('(\[video[^\]]*?\ssrc\s?=\s?([^\s\]]+)[^\]]*?\].*?\[/video\])ism', '[video]$1[/video]', $text); @@ -1916,8 +1965,8 @@ class BBCode if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) { $text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", "self::expandLinksCallback", $text); - //$Text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $Text); - $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]',$text); + //$text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $text); + $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]', $text); } // Perform URL Search @@ -2142,7 +2191,7 @@ class BBCode * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function bbCodeMention2DiasporaCallback($match) + private static function bbCodeMention2DiasporaCallback(array $match): string { $contact = Contact::getByURL($match[3], false, ['addr']); if (empty($contact['addr'])) { @@ -2164,7 +2213,7 @@ class BBCode * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function toMarkdown($text, $for_diaspora = true) + public static function toMarkdown(string $text, bool $for_diaspora = true): string { DI::profiler()->startRecording('rendering'); $original_text = $text; @@ -2201,7 +2250,7 @@ class BBCode $tagline .= '#' . $tag . ' '; } } - $text = $text . " " . $tagline; + $text = $text . ' ' . $tagline; } } else { $text = self::convert($text, false, self::CONNECTORS); @@ -2246,10 +2295,9 @@ class BBCode * Returns array of tags found, or empty array. * * @param string $string Post content - * * @return array List of tag and person names */ - public static function getTags($string) + public static function getTags(string $string): array { DI::profiler()->startRecording('rendering'); $ret = []; @@ -2309,13 +2357,13 @@ class BBCode /** * Expand tags to URLs, checks the tag is at the start of a line or preceded by a non-word character * - * @param string $body + * @param string $body HTML/BBCode * @return string body with expanded tags */ - public static function expandTags(string $body) + public static function expandTags(string $body): string { return preg_replace_callback("/(?<=\W|^)([!#@])([^\^ \x0D\x0A,;:?'\"]*[^\^ \x0D\x0A,;:?!'\".])/", - function ($match) { + function (array $match) { switch ($match[1]) { case '!': case '@': @@ -2326,6 +2374,7 @@ class BBCode return $match[1] . $match[2]; } break; + case '#': default: return $match[1] . '[url=' . DI::baseUrl() . '/search?tag=' . $match[2] . ']' . $match[2] . '[/url]'; @@ -2336,7 +2385,7 @@ class BBCode /** * Perform a custom function on a text after having escaped blocks enclosed in the provided tag list. * - * @param string $text + * @param string $text HTML/BBCode * @param array $tagList A list of tag names, e.g ['noparse', 'nobb', 'pre'] * @param callable $callback * @return string @@ -2352,14 +2401,14 @@ class BBCode /** * Replaces mentions in the provided message body in BBCode links for the provided user and network if any * - * @param $body - * @param $profile_uid - * @param $network - * @return string + * @param string $body HTML/BBCode + * @param int $profile_uid Profile user id + * @param string $network Network name + * @return string HTML/BBCode with inserted images * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function setMentions($body, $profile_uid = 0, $network = '') + public static function setMentions(string $body, $profile_uid = 0, $network = '') { DI::profiler()->startRecording('rendering'); $body = self::performWithEscapedTags($body, ['noparse', 'pre', 'code', 'img'], function ($body) use ($profile_uid, $network) { @@ -2406,7 +2455,7 @@ class BBCode * @return string * @TODO Rewrite to handle over whole record array */ - public static function getShareOpeningTag(string $author, string $profile, string $avatar, string $link, string $posted, string $guid = null) + public static function getShareOpeningTag(string $author, string $profile, string $avatar, string $link, string $posted, string $guid = null): string { DI::profiler()->startRecording('rendering'); $header = "[share author='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $author) . @@ -2438,8 +2487,7 @@ class BBCode * @param string|null $tags * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException - *@see ParseUrl::getSiteinfoCached - * + * @see ParseUrl::getSiteinfoCached */ public static function embedURL(string $url, bool $tryAttachment = true, string $title = null, string $description = null, string $tags = null): string { diff --git a/src/Content/Text/HTML.php b/src/Content/Text/HTML.php index ae9452abb0..9121087296 100644 --- a/src/Content/Text/HTML.php +++ b/src/Content/Text/HTML.php @@ -61,7 +61,7 @@ class HTML * inner value from an attribute value and disregard the tag children. * @return bool Whether a replacement was done */ - private static function tagToBBCodeSub(DOMDocument $doc, string $tag, array $attributes, string $startbb, string $endbb, bool $ignoreChildren = false) + private static function tagToBBCodeSub(DOMDocument $doc, string $tag, array $attributes, string $startbb, string $endbb, bool $ignoreChildren = false): bool { $savestart = str_replace('$', '\x01', $startbb); $replace = false; @@ -141,8 +141,16 @@ class HTML * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function toBBCode($message, $basepath = '') + public static function toBBCode(string $message, string $basepath = ''): string { + /* + * Check if message is empty to prevent a lot code below being executed + * for just an empty message. + */ + if (empty($message)) { + return ''; + } + DI::profiler()->startRecording('rendering'); $message = str_replace("\r", "", $message); @@ -409,7 +417,7 @@ class HTML * * @return string The expanded URL */ - private static function qualifyURLsSub($matches, $basepath) + private static function qualifyURLsSub(array $matches, string $basepath): string { $base = parse_url($basepath); unset($base['query']); @@ -436,7 +444,7 @@ class HTML * * @return string Body with expanded URLs */ - private static function qualifyURLs($body, $basepath) + private static function qualifyURLs(string $body, string $basepath): string { $URLSearchString = "^\[\]"; @@ -462,7 +470,7 @@ class HTML return $body; } - private static function breakLines($line, $level, $wraplength = 75) + private static function breakLines(string $line, int $level, int $wraplength = 75): string { if ($wraplength == 0) { $wraplength = 2000000; @@ -503,7 +511,7 @@ class HTML return implode("\n", $newlines); } - private static function quoteLevel($message, $wraplength = 75) + private static function quoteLevel(string $message, int $wraplength = 75): string { $lines = explode("\n", $message); @@ -539,7 +547,7 @@ class HTML return implode("\n", $newlines); } - private static function collectURLs($message) + private static function collectURLs(string $message): array { $pattern = '/(.*?)<\/a>/is'; preg_match_all($pattern, $message, $result, PREG_SET_ORDER); @@ -585,7 +593,7 @@ class HTML * @param bool $compact True: Completely strips image tags; False: Keeps image URLs * @return string */ - public static function toPlaintext(string $html, $wraplength = 75, $compact = false) + public static function toPlaintext(string $html, int $wraplength = 75, bool $compact = false): string { DI::profiler()->startRecording('rendering'); $message = str_replace("\r", "", $html); @@ -705,7 +713,7 @@ class HTML * @param string $html * @return string */ - public static function toMarkdown($html) + public static function toMarkdown(string $html): string { DI::profiler()->startRecording('rendering'); $converter = new HtmlConverter(['hard_break' => true]); @@ -721,7 +729,7 @@ class HTML * @param string $s * @return string */ - public static function toBBCodeVideo($s) + public static function toBBCodeVideo(string $s): string { $s = preg_replace( '#]+>(.*?)https?://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+)(.*?)#ism', @@ -751,7 +759,7 @@ class HTML * @param string $base base url * @return string */ - public static function relToAbs($text, $base) + public static function relToAbs(string $text, string $base): string { if (empty($base)) { return $text; @@ -790,7 +798,7 @@ class HTML * @return string html for loader * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function scrollLoader() + public static function scrollLoader(): string { $tpl = Renderer::getMarkupTemplate("scroll_loader.tpl"); return Renderer::replaceMacros($tpl, [ @@ -819,7 +827,7 @@ class HTML * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function micropro($contact, $redirect = false, $class = '', $textmode = false) + public static function micropro(array $contact, bool $redirect = false, string $class = '', bool $textmode = false): string { // Use the contact URL if no address is available if (empty($contact['addr'])) { @@ -859,13 +867,12 @@ class HTML * * @param string $s Search query. * @param string $id HTML id - * @param string $url Search url. * @param bool $aside Display the search widgit aside. * * @return string Formatted HTML. * @throws \Exception */ - public static function search($s, $id = 'search-box', $aside = true) + public static function search(string $s, string $id = 'search-box', bool $aside = true): string { $mode = 'text'; @@ -906,7 +913,7 @@ class HTML * @param string $s * @return string */ - public static function toLink($s) + public static function toLink(string $s): string { $s = preg_replace("/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\'\%\$\!\+]*)/", ' $1', $s); $s = preg_replace("/\<(.*?)(src|href)=(.*?)\&\;(.*?)\>/ism", '<$1$2=$3&$4>', $s); @@ -923,7 +930,7 @@ class HTML * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function applyContentFilter($html, array $reasons) + public static function applyContentFilter(string $html, array $reasons): string { if (count($reasons)) { $tpl = Renderer::getMarkupTemplate('wall/content_filter.tpl'); @@ -943,7 +950,7 @@ class HTML * @param string $s * @return string */ - public static function unamp($s) + public static function unamp(string $s): string { return str_replace('&', '&', $s); } diff --git a/src/Content/Text/Plaintext.php b/src/Content/Text/Plaintext.php index 2fcff72d59..ab8b712d89 100644 --- a/src/Content/Text/Plaintext.php +++ b/src/Content/Text/Plaintext.php @@ -36,7 +36,7 @@ class Plaintext * * @todo For Twitter URLs aren't shortened, but they have to be calculated as if. */ - public static function shorten(string $msg, int $limit, int $uid = 0):string + public static function shorten(string $msg, int $limit, int $uid = 0): string { $ellipsis = html_entity_decode("…", ENT_QUOTES, 'UTF-8'); diff --git a/src/Content/Widget.php b/src/Content/Widget.php index 1b2502d2d6..fba027680c 100644 --- a/src/Content/Widget.php +++ b/src/Content/Widget.php @@ -45,7 +45,7 @@ class Widget * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function follow($value = "") + public static function follow(string $value = ''): string { return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/follow.tpl'), array( '$connect' => DI::l10n()->t('Add New Contact'), @@ -58,8 +58,10 @@ class Widget /** * Return Find People widget + * + * @return string HTML code respresenting "People Widget" */ - public static function findPeople() + public static function findPeople(): string { $global_dir = Search::getGlobalDirectory(); @@ -97,7 +99,7 @@ class Widget * * @return array Unsupported networks */ - public static function unavailableNetworks() + public static function unavailableNetworks(): array { // Always hide content from these networks $networks = [Protocol::PHANTOM, Protocol::FACEBOOK, Protocol::APPNET, Protocol::ZOT]; @@ -154,7 +156,7 @@ class Widget * @return string * @throws \Exception */ - private static function filter($type, $title, $desc, $all, $baseUrl, array $options, $selected = null) + private static function filter(string $type, string $title, string $desc, string $all, string $baseUrl, array $options, string $selected = null): string { $queryString = parse_url($baseUrl, PHP_URL_QUERY); $queryArray = []; @@ -191,7 +193,7 @@ class Widget * @return string * @throws \Exception */ - public static function groups($baseurl, $selected = '') + public static function groups(string $baseurl, string $selected = ''): string { if (!local_user()) { return ''; @@ -223,7 +225,7 @@ class Widget * @return string * @throws \Exception */ - public static function contactRels($baseurl, $selected = '') + public static function contactRels(string $baseurl, string $selected = ''): string { if (!local_user()) { return ''; @@ -254,7 +256,7 @@ class Widget * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function networks($baseurl, $selected = '') + public static function networks(string $baseurl, string $selected = ''): string { if (!local_user()) { return ''; @@ -292,10 +294,10 @@ class Widget * * @param string $baseurl baseurl * @param string $selected optional, default empty - * @return string|void + * @return string * @throws \Exception */ - public static function fileAs($baseurl, $selected = '') + public static function fileAs(string $baseurl, string $selected = ''): string { if (!local_user()) { return ''; @@ -323,10 +325,10 @@ class Widget * @param int $uid Id of the user owning the categories * @param string $baseurl Base page URL * @param string $selected Selected category - * @return string|void + * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function categories(int $uid, string $baseurl, string $selected = '') + public static function categories(int $uid, string $baseurl, string $selected = ''): string { if (!Feature::isEnabled($uid, 'categories')) { return ''; @@ -353,11 +355,11 @@ class Widget * * @param int $uid Viewed profile user ID * @param string $nickname Viewed profile user nickname - * @return string|void + * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function commonFriendsVisitor(int $uid, string $nickname) + public static function commonFriendsVisitor(int $uid, string $nickname): string { if (local_user() == $uid) { return ''; @@ -414,7 +416,7 @@ class Widget * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function tagCloud(int $uid, int $limit = 50) + public static function tagCloud(int $uid, int $limit = 50): string { if (empty($uid)) { return ''; @@ -439,7 +441,7 @@ class Widget * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function postedByYear(string $url, int $uid, bool $wall) + public static function postedByYear(string $url, int $uid, bool $wall): string { $o = ''; @@ -510,10 +512,10 @@ class Widget * The account type value is added as a parameter to the url * * @param string $base Basepath - * @param int $accounttype Acount type + * @param string $accounttype Account type * @return string */ - public static function accounttypes(string $base, $accounttype) + public static function accountTypes(string $base, string $accounttype): string { $accounts = [ ['ref' => 'person', 'name' => DI::l10n()->t('Persons')], diff --git a/src/Core/Addon.php b/src/Core/Addon.php index f6d0d49740..37ef335a47 100644 --- a/src/Core/Addon.php +++ b/src/Core/Addon.php @@ -124,7 +124,7 @@ class Addon * @return void * @throws \Exception */ - public static function uninstall($addon) + public static function uninstall(string $addon) { $addon = Strings::sanitizeFilePathItem($addon); @@ -149,7 +149,7 @@ class Addon * @return bool * @throws \Exception */ - public static function install($addon) + public static function install(string $addon): bool { $addon = Strings::sanitizeFilePathItem($addon); @@ -185,6 +185,8 @@ class Addon /** * reload all updated addons + * + * @return void */ public static function reload() { @@ -222,7 +224,7 @@ class Addon * @return array with the addon information * @throws \Exception */ - public static function getInfo($addon) + public static function getInfo(string $addon): array { $addon = Strings::sanitizeFilePathItem($addon); @@ -287,7 +289,7 @@ class Addon * @param string $addon * @return boolean */ - public static function isEnabled($addon) + public static function isEnabled(string $addon): bool { return in_array($addon, self::$addons); } @@ -297,7 +299,7 @@ class Addon * * @return array */ - public static function getEnabledList() + public static function getEnabledList(): array { return self::$addons; } @@ -308,7 +310,7 @@ class Addon * @return array * @throws \Exception */ - public static function getVisibleList() + public static function getVisibleList(): array { $visible_addons = []; $stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]); diff --git a/src/Core/Cache/Type/MemcacheCache.php b/src/Core/Cache/Type/MemcacheCache.php index 441c64c3a0..225c338911 100644 --- a/src/Core/Cache/Type/MemcacheCache.php +++ b/src/Core/Cache/Type/MemcacheCache.php @@ -68,6 +68,17 @@ class MemcacheCache extends AbstractCache implements ICanCacheInMemory } } + /** + * Memcache doesn't allow spaces in keys + * + * @param string $key + * @return string + */ + protected function getCacheKey(string $key): string + { + return str_replace(' ', '_', parent::getCacheKey($key)); + } + /** * (@inheritdoc) */ diff --git a/src/Core/Cache/Type/MemcachedCache.php b/src/Core/Cache/Type/MemcachedCache.php index d86906de76..2d8b4e1c2f 100644 --- a/src/Core/Cache/Type/MemcachedCache.php +++ b/src/Core/Cache/Type/MemcachedCache.php @@ -93,6 +93,17 @@ class MemcachedCache extends AbstractCache implements ICanCacheInMemory } } + /** + * Memcached doesn't allow spaces in keys + * + * @param string $key + * @return string + */ + protected function getCacheKey(string $key): string + { + return str_replace(' ', '_', parent::getCacheKey($key)); + } + /** * (@inheritdoc) */ diff --git a/src/Core/Console.php b/src/Core/Console.php index ebd4c51a9d..2521e21bef 100644 --- a/src/Core/Console.php +++ b/src/Core/Console.php @@ -121,7 +121,7 @@ HELP; $this->dice = $dice; } - protected function doExecute() + protected function doExecute(): int { if ($this->getOption('v')) { $this->out('Executable: ' . $this->executable); diff --git a/src/Core/Hook.php b/src/Core/Hook.php index 89e882e35e..f2fb52f5e8 100644 --- a/src/Core/Hook.php +++ b/src/Core/Hook.php @@ -49,6 +49,8 @@ class Hook /** * Load hooks + * + * @return void */ public static function loadHooks() { @@ -69,8 +71,9 @@ class Hook * @param string $hook * @param string $file * @param string $function + * @return void */ - public static function add($hook, $file, $function) + public static function add(string $hook, string $file, string $function) { if (!array_key_exists($hook, self::$hooks)) { self::$hooks[$hook] = []; @@ -90,7 +93,7 @@ class Hook * @return mixed|bool * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function register($hook, $file, $function, $priority = 0) + public static function register(string $hook, string $file, string $function, int $priority = 0) { $file = str_replace(DI::app()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); @@ -111,7 +114,7 @@ class Hook * @return boolean * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function unregister($hook, $file, $function) + public static function unregister(string $hook, string $file, string $function): bool { $relative_file = str_replace(DI::app()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); @@ -120,8 +123,8 @@ class Hook self::delete($condition); $condition = ['hook' => $hook, 'file' => $relative_file, 'function' => $function]; - $result = self::delete($condition); - return $result; + + return self::delete($condition); } /** @@ -130,7 +133,7 @@ class Hook * @param string $name Name of the hook * @return array */ - public static function getByName($name) + public static function getByName(string $name): array { $return = []; @@ -149,9 +152,10 @@ class Hook * @param integer $priority of the hook * @param string $name of the hook to call * @param mixed $data to transmit to the callback handler + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function fork($priority, $name, $data = null) + public static function fork(int $priority, string $name, $data = null) { if (array_key_exists($name, self::$hooks)) { foreach (self::$hooks[$name] as $hook) { @@ -184,9 +188,10 @@ class Hook * * @param string $name of the hook to call * @param string|array &$data to transmit to the callback handler + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function callAll($name, &$data = null) + public static function callAll(string $name, &$data = null) { if (array_key_exists($name, self::$hooks)) { foreach (self::$hooks[$name] as $hook) { @@ -202,9 +207,10 @@ class Hook * @param string $name of the hook to call * @param array $hook Hook data * @param string|array &$data to transmit to the callback handler + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function callSingle(App $a, $name, $hook, &$data = null) + public static function callSingle(App $a, string $name, array $hook, &$data = null) { // Don't run a theme's hook if the user isn't using the theme if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . $a->getCurrentTheme()) === false) { @@ -229,7 +235,7 @@ class Hook * @param string $name Name of the addon * @return boolean */ - public static function isAddonApp($name) + public static function isAddonApp(string $name): bool { $name = Strings::sanitizeFilePathItem($name); @@ -253,7 +259,7 @@ class Hook * @return bool * @throws \Exception */ - public static function delete(array $condition) + public static function delete(array $condition): bool { $result = DBA::delete('hook', $condition); @@ -273,7 +279,7 @@ class Hook * @return bool * @throws \Exception */ - private static function insert(array $condition) + private static function insert(array $condition): bool { $result = DBA::insert('hook', $condition); diff --git a/src/Core/Installer.php b/src/Core/Installer.php index 516408b4e3..ff759c9feb 100644 --- a/src/Core/Installer.php +++ b/src/Core/Installer.php @@ -189,14 +189,12 @@ class Installer /*** * Installs the DB-Scheme for Friendica * - * @param string $basePath The base path of this application - * * @return bool true if the installation was successful, otherwise false * @throws Exception */ - public function installDatabase($basePath) + public function installDatabase(): bool { - $result = DBStructure::install($basePath); + $result = DBStructure::install(); if ($result) { $txt = DI::l10n()->t('You may need to import the file "database.sql" manually using phpmyadmin or mysql.') . EOL; @@ -656,7 +654,7 @@ class Installer * @return bool true if the check was successful, otherwise false * @throws Exception */ - public function checkDB(Database $dba) + public function checkDB(Database $dba): bool { $dba->reconnect(); diff --git a/src/Core/L10n.php b/src/Core/L10n.php index 050c190737..2c45fb9551 100644 --- a/src/Core/L10n.php +++ b/src/Core/L10n.php @@ -128,7 +128,7 @@ class L10n private function setLangFromSession(IHandleSessions $session) { if ($session->get('language') !== $this->lang) { - $this->loadTranslationTable($session->get('language')); + $this->loadTranslationTable($session->get('language') ?? $this->lang); } } @@ -140,10 +140,10 @@ class L10n * Uses an App object shim since all the strings files refer to $a->strings * * @param string $lang language code to load - * + * @return void * @throws \Exception */ - private function loadTranslationTable($lang) + private function loadTranslationTable(string $lang) { $lang = Strings::sanitizeFilePathItem($lang); @@ -183,7 +183,7 @@ class L10n * * @return string The two-letter language code */ - public static function detectLanguage(array $server, array $get, string $sysLang = self::DEFAULT) + public static function detectLanguage(array $server, array $get, string $sysLang = self::DEFAULT): string { $lang_variable = $server['HTTP_ACCEPT_LANGUAGE'] ?? null; @@ -269,7 +269,7 @@ class L10n * * @return string */ - public function t($s, ...$vars) + public function t(string $s, ...$vars): string { if (empty($s)) { return ''; @@ -307,7 +307,7 @@ class L10n * @return string * @throws \Exception */ - public function tt(string $singular, string $plural, int $count) + public function tt(string $singular, string $plural, int $count): string { $s = null; @@ -352,7 +352,7 @@ class L10n * * @return bool */ - private function stringPluralSelectDefault($n) + private function stringPluralSelectDefault(int $n): bool { return $n != 1; } @@ -369,7 +369,7 @@ class L10n * * @return array */ - public static function getAvailableLanguages() + public static function getAvailableLanguages(): array { $langs = []; $strings_file_paths = glob('view/lang/*/strings.php'); @@ -391,10 +391,9 @@ class L10n * Translate days and months names. * * @param string $s String with day or month name. - * * @return string Translated string. */ - public function getDay($s) + public function getDay(string $s): string { $ret = str_replace(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], [$this->t('Monday'), $this->t('Tuesday'), $this->t('Wednesday'), $this->t('Thursday'), $this->t('Friday'), $this->t('Saturday'), $this->t('Sunday')], @@ -411,10 +410,9 @@ class L10n * Translate short days and months names. * * @param string $s String with short day or month name. - * * @return string Translated string. */ - public function getDayShort($s) + public function getDayShort(string $s): string { $ret = str_replace(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], [$this->t('Mon'), $this->t('Tue'), $this->t('Wed'), $this->t('Thu'), $this->t('Fri'), $this->t('Sat'), $this->t('Sun')], @@ -435,7 +433,7 @@ class L10n * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @hook poke_verbs pokes array */ - public function getPokeVerbs() + public function getPokeVerbs(): array { // index is present tense verb // value is array containing past tense verb, translation of present, translation of past @@ -461,7 +459,7 @@ class L10n * @return static A new L10n instance * @throws \Exception */ - public function withLang(string $lang) + public function withLang(string $lang): L10n { // Don't create a new instance for same language if ($lang === $this->lang) { diff --git a/src/Core/Logger.php b/src/Core/Logger.php index 2a62e5513f..0885764c68 100644 --- a/src/Core/Logger.php +++ b/src/Core/Logger.php @@ -47,7 +47,7 @@ class Logger /** * @return LoggerInterface */ - private static function getWorker() + private static function getInstance() { if (self::$type === self::TYPE_LOGGER) { return DI::logger(); @@ -66,7 +66,7 @@ class Logger public static function enableWorker(string $functionName) { self::$type = self::TYPE_WORKER; - self::getWorker()->setFunctionName($functionName); + self::getInstance()->setFunctionName($functionName); } /** @@ -82,15 +82,14 @@ class Logger * * @see LoggerInterface::emergency() * - * @param string $message - * @param array $context - * + * @param string $message Message to log + * @param array $context Optional variables * @return void * @throws \Exception */ - public static function emergency($message, $context = []) + public static function emergency(string $message, array $context = []) { - self::getWorker()->emergency($message, $context); + self::getInstance()->emergency($message, $context); } /** @@ -100,15 +99,14 @@ class Logger * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. * - * @param string $message - * @param array $context - * + * @param string $message Message to log + * @param array $context Optional variables * @return void * @throws \Exception */ - public static function alert($message, $context = []) + public static function alert(string $message, array $context = []) { - self::getWorker()->alert($message, $context); + self::getInstance()->alert($message, $context); } /** @@ -117,15 +115,14 @@ class Logger * * Example: Application component unavailable, unexpected exception. * - * @param string $message - * @param array $context - * + * @param string $message Message to log + * @param array $context Optional variables * @return void * @throws \Exception */ - public static function critical($message, $context = []) + public static function critical(string $message, array $context = []) { - self::getWorker()->critical($message, $context); + self::getInstance()->critical($message, $context); } /** @@ -133,15 +130,14 @@ class Logger * be logged and monitored. * @see LoggerInterface::error() * - * @param string $message - * @param array $context - * + * @param string $message Message to log + * @param array $context Optional variables * @return void * @throws \Exception */ - public static function error($message, $context = []) + public static function error(string $message, array $context = []) { - self::getWorker()->error($message, $context); + self::getInstance()->error($message, $context); } /** @@ -151,30 +147,28 @@ class Logger * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. * - * @param string $message - * @param array $context - * + * @param string $message Message to log + * @param array $context Optional variables * @return void * @throws \Exception */ - public static function warning($message, $context = []) + public static function warning(string $message, array $context = []) { - self::getWorker()->warning($message, $context); + self::getInstance()->warning($message, $context); } /** * Normal but significant events. * @see LoggerInterface::notice() * - * @param string $message - * @param array $context - * + * @param string $message Message to log + * @param array $context Optional variables * @return void * @throws \Exception */ - public static function notice($message, $context = []) + public static function notice(string $message, array $context = []) { - self::getWorker()->notice($message, $context); + self::getInstance()->notice($message, $context); } /** @@ -189,24 +183,23 @@ class Logger * @return void * @throws \Exception */ - public static function info($message, $context = []) + public static function info(string $message, array $context = []) { - self::getWorker()->info($message, $context); + self::getInstance()->info($message, $context); } /** * Detailed debug information. * @see LoggerInterface::debug() * - * @param string $message - * @param array $context - * + * @param string $message Message to log + * @param array $context Optional variables * @return void * @throws \Exception */ - public static function debug($message, $context = []) + public static function debug(string $message, array $context = []) { - self::getWorker()->debug($message, $context); + self::getInstance()->debug($message, $context); } /** @@ -216,12 +209,13 @@ class Logger * to isolate particular elements they are targetting * personally without background noise * - * @param string $msg - * @param string $level + * @param string $message Message to log + * @param string $level Logging level + * @return void * @throws \Exception */ - public static function devLog($msg, $level = LogLevel::DEBUG) + public static function devLog(string $message, string $level = LogLevel::DEBUG) { - DI::devLogger()->log($level, $msg); + DI::devLogger()->log($level, $message); } } diff --git a/src/Core/Logger/Type/Monolog/DevelopHandler.php b/src/Core/Logger/Type/Monolog/DevelopHandler.php index dc7d1b00d2..febb8d6cda 100644 --- a/src/Core/Logger/Type/Monolog/DevelopHandler.php +++ b/src/Core/Logger/Type/Monolog/DevelopHandler.php @@ -21,6 +21,7 @@ namespace Friendica\Core\Logger\Type\Monolog; +use Friendica\App\Request; use Monolog\Handler; use Monolog\Logger; @@ -38,15 +39,22 @@ class DevelopHandler extends Handler\AbstractHandler private $developerIp; /** - * @param string $developerIp The IP of the developer who wants to debug - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @var string The IP of the current request */ - public function __construct($developerIp, $level = Logger::DEBUG, bool $bubble = true) + private $remoteAddress; + + /** + * @param Request $request The current http request + * @param string $developerIp The IP of the developer who wants to debug + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(Request $request, $developerIp, int $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); - $this->developerIp = $developerIp; + $this->developerIp = $developerIp; + $this->remoteAddress = $request->getRemoteAddress(); } /** @@ -59,7 +67,7 @@ class DevelopHandler extends Handler\AbstractHandler } /// Just in case the remote IP is the same as the developer IP log the output - if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp) { + if (!is_null($this->developerIp) && $this->remoteAddress != $this->developerIp) { return false; } diff --git a/src/Core/Renderer.php b/src/Core/Renderer.php index 29bbb2b894..879fdfe19e 100644 --- a/src/Core/Renderer.php +++ b/src/Core/Renderer.php @@ -71,7 +71,7 @@ class Renderer * @return string * @throws ServiceUnavailableException */ - public static function replaceMacros(string $template, array $vars = []) + public static function replaceMacros(string $template, array $vars = []): string { DI::profiler()->startRecording('rendering'); diff --git a/src/Core/System.php b/src/Core/System.php index 7601a6f840..8712b6ca59 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -441,6 +441,12 @@ class System * * @param string $url The new Location to redirect * @param int $code The redirection code, which is used (Default is 302) + * + * @throws FoundException + * @throws MovedPermanentlyException + * @throws TemporaryRedirectException + * + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function externalRedirect($url, $code = 302) { diff --git a/src/Core/Theme.php b/src/Core/Theme.php index 57dfaa4d63..834787da69 100644 --- a/src/Core/Theme.php +++ b/src/Core/Theme.php @@ -32,7 +32,7 @@ require_once 'boot.php'; */ class Theme { - public static function getAllowedList() + public static function getAllowedList(): array { $allowed_themes_str = DI::config()->get('system', 'allowed_themes'); $allowed_themes_raw = explode(',', str_replace(' ', '', $allowed_themes_str)); @@ -69,7 +69,7 @@ class Theme * @param string $theme the name of the theme * @return array */ - public static function getInfo($theme) + public static function getInfo(string $theme): array { $theme = Strings::sanitizeFilePathItem($theme); @@ -133,7 +133,7 @@ class Theme * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getScreenshot($theme) + public static function getScreenshot(string $theme): string { $theme = Strings::sanitizeFilePathItem($theme); @@ -146,7 +146,13 @@ class Theme return DI::baseUrl() . '/images/blank.png'; } - public static function uninstall($theme) + /** + * Uninstalls given theme name + * + * @param string $theme Name of theme + * @return bool true on success + */ + public static function uninstall(string $theme) { $theme = Strings::sanitizeFilePathItem($theme); @@ -167,10 +173,18 @@ class Theme if ($key !== false) { unset($allowed_themes[$key]); Theme::setAllowedList($allowed_themes); + return true; } + return false; } - public static function install($theme) + /** + * Installs given theme name + * + * @param string $theme Name of theme + * @return bool true on success + */ + public static function install(string $theme): bool { $theme = Strings::sanitizeFilePathItem($theme); @@ -208,7 +222,7 @@ class Theme * @return string Path to the file or empty string if the file isn't found * @throws \Exception */ - public static function getPathForFile($file) + public static function getPathForFile(string $file): string { $a = DI::app(); @@ -237,10 +251,9 @@ class Theme * Provide a sane default if nothing is chosen or the specified theme does not exist. * * @param string $theme Theme name - * * @return string */ - public static function getStylesheetPath($theme) + public static function getStylesheetPath(string $theme): string { $theme = Strings::sanitizeFilePathItem($theme); @@ -263,10 +276,10 @@ class Theme /** * Returns the path of the provided theme * - * @param $theme + * @param string $theme Theme name * @return string|null */ - public static function getConfigFile($theme) + public static function getConfigFile(string $theme) { $theme = Strings::sanitizeFilePathItem($theme); @@ -285,11 +298,11 @@ class Theme /** * Returns the background color of the provided theme if available. * - * @param string $theme + * @param string $theme Theme name * @param int|null $uid Current logged-in user id * @return string|null */ - public static function getBackgroundColor(string $theme, $uid = null) + public static function getBackgroundColor(string $theme, int $uid = null) { $theme = Strings::sanitizeFilePathItem($theme); diff --git a/src/Core/Update.php b/src/Core/Update.php index 978baec10f..ddb9effd71 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -41,7 +41,7 @@ class Update * @param string $basePath The base path of this application * @param boolean $via_worker Is the check run via the worker? * @param App\Mode $mode The current app mode - * + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function check(string $basePath, bool $via_worker, App\Mode $mode) @@ -73,7 +73,7 @@ class Update } // The postupdate has to completed version 1288 for the new post views to take over - $postupdate = DI::config()->get("system", "post_update_version", NEW_TABLE_STRUCTURE_VERSION); + $postupdate = DI::config()->get('system', 'post_update_version', NEW_TABLE_STRUCTURE_VERSION); if ($postupdate < NEW_TABLE_STRUCTURE_VERSION) { $error = DI::l10n()->t('Updates from postupdate version %s are not supported. Please update at least to version 2021.01 and wait until the postupdate finished version 1383.', $postupdate); if (DI::mode()->getExecutor() == Mode::INDEX) { @@ -85,9 +85,11 @@ class Update if ($build < DB_UPDATE_VERSION) { if ($via_worker) { - // Calling the database update directly via the worker enables us to perform database changes to the workerqueue table itself. - // This is a fallback, since normally the database update will be performed by a worker job. - // This worker job doesn't work for changes to the "workerqueue" table itself. + /* + * Calling the database update directly via the worker enables us to perform database changes to the workerqueue table itself. + * This is a fallback, since normally the database update will be performed by a worker job. + * This worker job doesn't work for changes to the "workerqueue" table itself. + */ self::run($basePath); } else { Worker::add(PRIORITY_CRITICAL, 'DBUpdate'); @@ -103,11 +105,10 @@ class Update * @param bool $override Overrides any running/stuck updates * @param bool $verbose Run the Update-Check verbose * @param bool $sendMail Sends a Mail to the administrator in case of success/failure - * * @return string Empty string if the update is successful, error messages otherwise * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function run(string $basePath, bool $force = false, bool $override = false, bool $verbose = false, bool $sendMail = true) + public static function run(string $basePath, bool $force = false, bool $override = false, bool $verbose = false, bool $sendMail = true): string { // In force mode, we release the dbupdate lock first // Necessary in case of an stuck update @@ -228,11 +229,10 @@ class Update * @param int $version the DB version number of the function * @param string $prefix the prefix of the function (update, pre_update) * @param bool $sendMail whether to send emails on success/failure - * @return bool true, if the update function worked * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function runUpdateFunction(int $version, string $prefix, bool $sendMail = true) + public static function runUpdateFunction(int $version, string $prefix, bool $sendMail = true): bool { $funcname = $prefix . '_' . $version; @@ -284,6 +284,7 @@ class Update * * @param int $update_id number of failed update * @param string $error_message error message + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function updateFailed(int $update_id, string $error_message) { diff --git a/src/Core/UserImport.php b/src/Core/UserImport.php index b6ecd74a24..339ce0b65b 100644 --- a/src/Core/UserImport.php +++ b/src/Core/UserImport.php @@ -86,7 +86,7 @@ class UserImport * @return array|bool * @throws \Exception */ - private static function dbImportAssoc($table, $arr) + private static function dbImportAssoc(string $table, array $arr) { if (isset($arr['id'])) { unset($arr['id']); @@ -105,10 +105,11 @@ class UserImport * Import account file exported from mod/uexport * * @param array $file array from $_FILES + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function importAccount($file) + public static function importAccount(array $file) { Logger::notice("Start user import from " . $file['tmp_name']); /* diff --git a/src/Core/Worker.php b/src/Core/Worker.php index bc52843e69..62fd321c24 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -60,7 +60,7 @@ class Worker * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function processQueue($run_cron, Process $process) + public static function processQueue(bool $run_cron, Process $process) { self::$up_start = microtime(true); @@ -169,7 +169,7 @@ class Worker * * @return boolean */ - public static function isReady() + public static function isReady(): bool { // Count active workers and compare them with a maximum value that depends on the load if (self::tooMuchWorkers()) { @@ -204,7 +204,7 @@ class Worker * @return boolean Returns "true" if tasks are existing * @throws \Exception */ - public static function entriesExists() + public static function entriesExists(): bool { $stamp = (float)microtime(true); $exists = DBA::exists('workerqueue', ["NOT `done` AND `pid` = 0 AND `next_try` < ?", DateTimeFormat::utcNow()]); @@ -218,7 +218,7 @@ class Worker * @return integer Number of deferred entries in the worker queue * @throws \Exception */ - private static function deferredEntries() + private static function deferredEntries(): int { $stamp = (float)microtime(true); $count = DBA::count('workerqueue', ["NOT `done` AND `pid` = 0 AND `retrial` > ?", 0]); @@ -233,7 +233,7 @@ class Worker * @return integer Number of non executed entries in the worker queue * @throws \Exception */ - private static function totalEntries() + private static function totalEntries(): int { $stamp = (float)microtime(true); $count = DBA::count('workerqueue', ['done' => false, 'pid' => 0]); @@ -248,7 +248,7 @@ class Worker * @return integer Number of active worker processes * @throws \Exception */ - private static function highestPriority() + private static function highestPriority(): int { $stamp = (float)microtime(true); $condition = ["`pid` = 0 AND NOT `done` AND `next_try` < ?", DateTimeFormat::utcNow()]; @@ -269,7 +269,7 @@ class Worker * @return integer Is there a process running with that priority? * @throws \Exception */ - private static function processWithPriorityActive($priority) + private static function processWithPriorityActive(int $priority): int { $condition = ["`priority` <= ? AND `pid` != 0 AND NOT `done`", $priority]; return DBA::exists('workerqueue', $condition); @@ -281,7 +281,7 @@ class Worker * @param mixed $file * @return bool */ - private static function validateInclude(&$file) + private static function validateInclude(&$file): bool { $orig_file = $file; @@ -321,7 +321,7 @@ class Worker * @return boolean "true" if further processing should be stopped * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function execute($queue) + public static function execute(array $queue): bool { $mypid = getmypid(); @@ -454,7 +454,7 @@ class Worker * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function execFunction($queue, $funcname, $argv, $method_call) + private static function execFunction(array $queue, string $funcname, array $argv, bool $method_call) { $a = DI::app(); @@ -543,7 +543,7 @@ class Worker * @return bool Are more than 3/4 of the maximum connections used? * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function maxConnectionsReached() + private static function maxConnectionsReached(): bool { // Fetch the max value from the config. This is needed when the system cannot detect the correct value by itself. $max = DI::config()->get("system", "max_connections"); @@ -627,7 +627,7 @@ class Worker * @return bool Are there too much workers running? * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function tooMuchWorkers() + private static function tooMuchWorkers(): bool { $queues = DI::config()->get("system", "worker_queues", 10); @@ -751,7 +751,7 @@ class Worker * @return integer Number of active worker processes * @throws \Exception */ - private static function activeWorkers() + private static function activeWorkers(): int { $stamp = (float)microtime(true); $count = DI::process()->countCommand('Worker.php'); @@ -766,7 +766,7 @@ class Worker * @return array List of worker process ids * @throws \Exception */ - private static function getWorkerPIDList() + private static function getWorkerPIDList(): array { $ids = []; $stamp = (float)microtime(true); @@ -787,7 +787,7 @@ class Worker /** * Returns waiting jobs for the current process id * - * @return array waiting workerqueue jobs + * @return array|bool waiting workerqueue jobs or FALSE on failture * @throws \Exception */ private static function getWaitingJobForPID() @@ -809,7 +809,7 @@ class Worker * @return array array with next jobs * @throws \Exception */ - private static function nextProcess(int $limit) + private static function nextProcess(int $limit): array { $priority = self::nextPriority(); if (empty($priority)) { @@ -844,7 +844,7 @@ class Worker /** * Returns the priority of the next workerqueue job * - * @return string priority + * @return string|bool priority or FALSE on failure * @throws \Exception */ private static function nextPriority() @@ -915,7 +915,7 @@ class Worker /** * Find and claim the next worker process for us * - * @return boolean Have we found something? + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function findWorkerProcesses() @@ -993,7 +993,7 @@ class Worker * @return array worker processes * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function workerProcess() + public static function workerProcess(): array { // There can already be jobs for us in the queue. $waiting = self::getWaitingJobForPID(); @@ -1003,7 +1003,7 @@ class Worker $stamp = (float)microtime(true); if (!DI::lock()->acquire(self::LOCK_PROCESS)) { - return false; + return []; } self::$lock_duration += (microtime(true) - $stamp); @@ -1011,7 +1011,9 @@ class Worker DI::lock()->release(self::LOCK_PROCESS); - return self::getWaitingJobForPID(); + // Prevents "Return value of Friendica\Core\Worker::workerProcess() must be of the type array, bool returned" + $process = self::getWaitingJobForPID(); + return (is_array($process) ? $process : []); } /** @@ -1097,7 +1099,7 @@ class Worker * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function spawnWorker($do_cron = false) + public static function spawnWorker(bool $do_cron = false) { if (Worker\Daemon::isMode() && DI::config()->get('system', 'worker_fork')) { self::forkProcess($do_cron); @@ -1231,7 +1233,7 @@ class Worker return $added; } - public static function countWorkersByCommand(string $command) + public static function countWorkersByCommand(string $command): int { return DBA::count('workerqueue', ['done' => false, 'pid' => 0, 'command' => $command]); } @@ -1244,7 +1246,7 @@ class Worker * @param integer $max_level maximum retrial level * @return integer the next retrial level value */ - private static function getNextRetrial($queue, $max_level) + private static function getNextRetrial(array $queue, int $max_level): int { $created = strtotime($queue['created']); $retrial_time = time() - $created; @@ -1314,9 +1316,10 @@ class Worker /** * Check if the system is inside the defined maintenance window * + * @param bool $check_last_execution Whether check last execution * @return boolean */ - public static function isInMaintenanceWindow(bool $check_last_execution = false) + public static function isInMaintenanceWindow(bool $check_last_execution = false): bool { // Calculate the seconds of the start end end of the maintenance window $start = strtotime(DI::config()->get('system', 'maintenance_start')) % 86400; diff --git a/src/DI.php b/src/DI.php index e34df7b669..e8fa90eb9b 100644 --- a/src/DI.php +++ b/src/DI.php @@ -65,11 +65,27 @@ abstract class DI /** * @return Database\Database */ - public static function dba() + public static function dba(): Database\Database { return self::$dice->create(Database\Database::class); } + /** + * @return \Friendica\Database\Definition\DbaDefinition + */ + public static function dbaDefinition(): Database\Definition\DbaDefinition + { + return self::$dice->create(Database\Definition\DbaDefinition::class); + } + + /** + * @return \Friendica\Database\Definition\ViewDefinition + */ + public static function viewDefinition(): Database\Definition\ViewDefinition + { + return self::$dice->create(Database\Definition\ViewDefinition::class); + } + // // "App" namespace instances // diff --git a/src/Database/DBA.php b/src/Database/DBA.php index a0eb1c3ece..9ce2b61473 100644 --- a/src/Database/DBA.php +++ b/src/Database/DBA.php @@ -42,7 +42,7 @@ class DBA */ const NULL_DATETIME = '0001-01-01 00:00:00'; - public static function connect() + public static function connect(): bool { return DI::dba()->connect(); } @@ -58,7 +58,7 @@ class DBA /** * Perform a reconnect of an existing database connection */ - public static function reconnect() + public static function reconnect(): bool { return DI::dba()->reconnect(); } @@ -77,7 +77,7 @@ class DBA * * @return string with either "pdo" or "mysqli" */ - public static function getDriver() + public static function getDriver(): string { return DI::dba()->getDriver(); } @@ -90,7 +90,7 @@ class DBA * * @return string */ - public static function serverInfo() + public static function serverInfo(): string { return DI::dba()->serverInfo(); } @@ -101,7 +101,7 @@ class DBA * @return string * @throws \Exception */ - public static function databaseName() + public static function databaseName(): string { return DI::dba()->databaseName(); } @@ -112,7 +112,7 @@ class DBA * @param string $str * @return string escaped string */ - public static function escape($str) + public static function escape(string $str): string { return DI::dba()->escape($str); } @@ -122,7 +122,7 @@ class DBA * * @return boolean is the database connected? */ - public static function connected() + public static function connected(): bool { return DI::dba()->connected(); } @@ -138,7 +138,7 @@ class DBA * @param string $sql An SQL string without the values * @return string The input SQL string modified if necessary. */ - public static function anyValueFallback($sql) + public static function anyValueFallback(string $sql): string { return DI::dba()->anyValueFallback($sql); } @@ -152,7 +152,7 @@ class DBA * @param string $sql An SQL string without the values * @return string The input SQL string modified if necessary. */ - public static function cleanQuery($sql) + public static function cleanQuery(string $sql): string { $search = ["\t", "\n", "\r", " "]; $replace = [' ', ' ', ' ', ' ']; @@ -169,7 +169,7 @@ class DBA * @param array $args Parameter array * @return array universalized parameter array */ - public static function getParam($args) + public static function getParam(array $args): array { unset($args[0]); @@ -192,7 +192,7 @@ class DBA * @return bool|object statement object or result object * @throws \Exception */ - public static function p($sql) + public static function p(string $sql) { $params = self::getParam(func_get_args()); @@ -208,8 +208,8 @@ class DBA * @return boolean Was the query successfull? False is returned only if an error occurred * @throws \Exception */ - public static function e($sql) { - + public static function e(string $sql): bool + { $params = self::getParam(func_get_args()); return DI::dba()->e($sql, $params); @@ -218,13 +218,12 @@ class DBA /** * Check if data exists * - * @param string|array $table Table name or array [schema => table] - * @param array $condition array of fields for condition - * + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $condition Array of fields for condition * @return boolean Are there rows for that condition? * @throws \Exception */ - public static function exists($table, $condition) + public static function exists(string $table, array $condition): bool { return DI::dba()->exists($table, $condition); } @@ -238,7 +237,7 @@ class DBA * @return array first row of query * @throws \Exception */ - public static function fetchFirst($sql) + public static function fetchFirst(string $sql) { $params = self::getParam(func_get_args()); @@ -250,7 +249,7 @@ class DBA * * @return int Number of rows */ - public static function affectedRows() + public static function affectedRows(): int { return DI::dba()->affectedRows(); } @@ -261,7 +260,7 @@ class DBA * @param object Statement object * @return int Number of columns */ - public static function columnCount($stmt) + public static function columnCount($stmt): int { return DI::dba()->columnCount($stmt); } @@ -271,7 +270,7 @@ class DBA * @param PDOStatement|mysqli_result|mysqli_stmt Statement object * @return int Number of rows */ - public static function numRows($stmt) + public static function numRows($stmt): int { return DI::dba()->numRows($stmt); } @@ -290,14 +289,13 @@ class DBA /** * Insert a row into a table * - * @param string|array $table Table name or array [schema => table] - * @param array $param parameter array - * @param int $duplicate_mode What to do on a duplicated entry - * + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $param parameter array + * @param int $duplicate_mode What to do on a duplicated entry * @return boolean was the insert successful? * @throws \Exception */ - public static function insert($table, array $param, int $duplicate_mode = Database::INSERT_DEFAULT) + public static function insert(string $table, array $param, int $duplicate_mode = Database::INSERT_DEFAULT): bool { return DI::dba()->insert($table, $param, $duplicate_mode); } @@ -306,13 +304,12 @@ class DBA * Inserts a row with the provided data in the provided table. * If the data corresponds to an existing row through a UNIQUE or PRIMARY index constraints, it updates the row instead. * - * @param string|array $table Table name or array [schema => table] - * @param array $param parameter array - * + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $param parameter array * @return boolean was the insert successful? * @throws \Exception */ - public static function replace($table, $param) + public static function replace(string $table, array $param): bool { return DI::dba()->replace($table, $param); } @@ -322,7 +319,7 @@ class DBA * * @return integer Last inserted id */ - public static function lastInsertId() + public static function lastInsertId(): int { return DI::dba()->lastInsertId(); } @@ -332,12 +329,11 @@ class DBA * * This function can be extended in the future to accept a table array as well. * - * @param string|array $table Table name or array [schema => table] - * + * @param string $table Table name in format schema.table (while scheme is optiona) * @return boolean was the lock successful? * @throws \Exception */ - public static function lock($table) + public static function lock(string $table): bool { return DI::dba()->lock($table); } @@ -348,7 +344,7 @@ class DBA * @return boolean was the unlock successful? * @throws \Exception */ - public static function unlock() + public static function unlock(): bool { return DI::dba()->unlock(); } @@ -358,7 +354,7 @@ class DBA * * @return boolean Was the command executed successfully? */ - public static function transaction() + public static function transaction(): bool { return DI::dba()->transaction(); } @@ -368,7 +364,7 @@ class DBA * * @return boolean Was the command executed successfully? */ - public static function commit() + public static function commit(): bool { return DI::dba()->commit(); } @@ -378,7 +374,7 @@ class DBA * * @return boolean Was the command executed successfully? */ - public static function rollback() + public static function rollback(): bool { return DI::dba()->rollback(); } @@ -386,13 +382,13 @@ class DBA /** * Delete a row from a table * - * @param string|array $table Table name - * @param array $conditions Field condition(s) + * @param string $table Table name + * @param array $conditions Field condition(s) * * @return boolean was the delete successful? * @throws \Exception */ - public static function delete($table, array $conditions, array $options = []) + public static function delete(string $table, array $conditions, array $options = []): bool { return DI::dba()->delete($table, $conditions, $options); } @@ -418,7 +414,7 @@ class DBA * Only set $old_fields to a boolean value when you are sure that you will update a single row. * When you set $old_fields to "true" then $fields must contain all relevant fields! * - * @param string|array $table Table name or array [schema => table] + * @param string $table Table name in format schema.table (while scheme is optiona) * @param array $fields contains the fields that are updated * @param array $condition condition array with the key values * @param array|boolean $old_fields array with the old field values that are about to be replaced (true = update on duplicate, false = don't update identical fields) @@ -427,7 +423,7 @@ class DBA * @return boolean was the update successfull? * @throws \Exception */ - public static function update($table, $fields, $condition, $old_fields = [], $params = []) + public static function update(string $table, array $fields, array $condition, $old_fields = [], array $params = []): bool { return DI::dba()->update($table, $fields, $condition, $old_fields, $params); } @@ -435,7 +431,7 @@ class DBA /** * Retrieve a single record from a table and returns it in an associative array * - * @param string|array $table Table name or array [schema => table] + * @param string|array $table Table name in format schema.table (while scheme is optiona) * @param array $fields * @param array $condition * @param array $params @@ -443,7 +439,7 @@ class DBA * @throws \Exception * @see self::select */ - public static function selectFirst($table, array $fields = [], array $condition = [], $params = []) + public static function selectFirst($table, array $fields = [], array $condition = [], array $params = []) { return DI::dba()->selectFirst($table, $fields, $condition, $params); } @@ -451,16 +447,16 @@ class DBA /** * Select rows from a table and fills an array with the data * - * @param string|array $table Table name or array [schema => table] - * @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 + * @param string $table Table name in format schema.table (while scheme is optiona) + * @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 * * @return array Data array * @throws \Exception * @see self::select */ - public static function selectToArray($table, array $fields = [], array $condition = [], array $params = []) + public static function selectToArray(string $table, array $fields = [], array $condition = [], array $params = []) { return DI::dba()->selectToArray($table, $fields, $condition, $params); } @@ -468,10 +464,10 @@ class DBA /** * Select rows from a table * - * @param string|array $table Table name or array [schema => table] - * @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 + * @param string $table Table name in format schema.table (while scheme is optiona) + * @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 * * @return boolean|object * @@ -488,7 +484,7 @@ class DBA * $data = DBA::select($table, $fields, $condition, $params); * @throws \Exception */ - public static function select($table, array $fields = [], array $condition = [], array $params = []) + public static function select(string $table, array $fields = [], array $condition = [], array $params = []) { return DI::dba()->select($table, $fields, $condition, $params); } @@ -496,9 +492,9 @@ class DBA /** * Counts the rows from a table satisfying the provided condition * - * @param string|array $table Table name or array [schema => table] - * @param array $condition array of fields for condition - * @param array $params Array of several parameters + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $condition array of fields for condition + * @param array $params Array of several parameters * * @return int * @@ -512,7 +508,7 @@ class DBA * $count = DBA::count($table, $condition); * @throws \Exception */ - public static function count($table, array $condition = [], array $params = []) + public static function count(string $table, array $condition = [], array $params = []): int { return DI::dba()->count($table, $condition, $params); } @@ -525,37 +521,30 @@ class DBA * - [table1, table2, ...] * - [schema1 => table1, schema2 => table2, table3, ...] * - * @param string|array $tables + * @param array $tables Table names * @return string */ - public static function buildTableString($tables) + public static function buildTableString(array $tables): string { - if (is_string($tables)) { - $tables = [$tables]; - } - - $quotedTables = []; - - foreach ($tables as $schema => $table) { - if (is_numeric($schema)) { - $quotedTables[] = self::quoteIdentifier($table); - } else { - $quotedTables[] = self::quoteIdentifier($schema) . '.' . self::quoteIdentifier($table); - } - } - - return implode(', ', $quotedTables); + // Quote each entry + return implode(',', array_map(['self', 'quoteIdentifier'], $tables)); } /** - * Escape an identifier (table or field name) + * Escape an identifier (table or field name) optional with a schema like (schema.)table * - * @param $identifier - * @return string + * @param $identifier Table, field name + * @return string Quotes table or field name */ - public static function quoteIdentifier($identifier) + public static function quoteIdentifier(string $identifier): string { - return '`' . str_replace('`', '``', $identifier) . '`'; + return implode( + '.', + array_map( + function (string $identifier) { return '`' . str_replace('`', '``', $identifier) . '`'; }, + explode('.', $identifier) + ) + ); } /** @@ -576,7 +565,7 @@ class DBA * @param array $condition * @return string */ - public static function buildCondition(array &$condition = []) + public static function buildCondition(array &$condition = []): string { $condition = self::collapseCondition($condition); @@ -600,7 +589,7 @@ class DBA * @param array $condition * @return array */ - public static function collapseCondition(array $condition) + public static function collapseCondition(array $condition): array { // Ensures an always true condition is returned if (count($condition) < 1) { @@ -675,7 +664,7 @@ class DBA * @return array A collapsed condition * @see DBA::collapseCondition() for the condition array formats */ - public static function mergeConditions(array ...$conditions) + public static function mergeConditions(array ...$conditions): array { if (count($conditions) == 1) { return current($conditions); @@ -724,7 +713,7 @@ class DBA * @param array $params * @return string */ - public static function buildParameter(array $params = []) + public static function buildParameter(array $params = []): string { $groupby_string = ''; if (!empty($params['group_by'])) { @@ -771,7 +760,7 @@ class DBA * * @return array Data array */ - public static function toArray($stmt, $do_close = true, int $count = 0) + public static function toArray($stmt, bool $do_close = true, int $count = 0): array { return DI::dba()->toArray($stmt, $do_close, $count); } @@ -783,7 +772,7 @@ class DBA * @param array $fields * @return array casted fields */ - public static function castFields(string $table, array $fields) + public static function castFields(string $table, array $fields): array { return DI::dba()->castFields($table, $fields); } @@ -793,7 +782,7 @@ class DBA * * @return string Error number (0 if no error) */ - public static function errorNo() + public static function errorNo(): int { return DI::dba()->errorNo(); } @@ -803,7 +792,7 @@ class DBA * * @return string Error message ('' if no error) */ - public static function errorMessage() + public static function errorMessage(): string { return DI::dba()->errorMessage(); } @@ -814,7 +803,7 @@ class DBA * @param object $stmt statement object * @return boolean was the close successful? */ - public static function close($stmt) + public static function close($stmt): bool { return DI::dba()->close($stmt); } @@ -827,7 +816,7 @@ class DBA * 'amount' => Number of concurrent database processes * @throws \Exception */ - public static function processlist() + public static function processlist(): array { return DI::dba()->processlist(); } @@ -847,10 +836,9 @@ class DBA * Checks if $array is a filled array with at least one entry. * * @param mixed $array A filled array with at least one entry - * * @return boolean Whether $array is a filled array or an object with rows */ - public static function isResult($array) + public static function isResult($array): bool { return DI::dba()->isResult($array); } @@ -862,7 +850,7 @@ class DBA * @param boolean $add_quotation add quotation marks for string values * @return void */ - public static function escapeArray(&$arr, $add_quotation = false) + public static function escapeArray(&$arr, bool $add_quotation = false) { DI::dba()->escapeArray($arr, $add_quotation); } diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 2638bafab7..441116d167 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -22,13 +22,12 @@ namespace Friendica\Database; use Exception; -use Friendica\Core\Hook; use Friendica\Core\Logger; -use Friendica\Core\Renderer; use Friendica\DI; use Friendica\Model\Item; use Friendica\Model\User; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Writer\DbaDefinitionSqlWriter; /** * This class contains functions that doesn't need to know if pdo, mysqli or whatever is used. @@ -42,13 +41,6 @@ class DBStructure const RENAME_COLUMN = 0; const RENAME_PRIMARY_KEY = 1; - /** - * Database structure definition loaded from config/dbstructure.config.php - * - * @var array - */ - private static $definition = []; - /** * Set a database version to trigger update functions * @@ -73,7 +65,7 @@ class DBStructure */ public static function dropTables(bool $execute) { - $postupdate = DI::config()->get("system", "post_update_version", PostUpdate::VERSION); + $postupdate = DI::config()->get('system', 'post_update_version', PostUpdate::VERSION); if ($postupdate < PostUpdate::VERSION) { echo DI::l10n()->t('The post update is at version %d, it has to be at %d to safely drop the tables.', $postupdate, PostUpdate::VERSION); return; @@ -84,7 +76,7 @@ class DBStructure 'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge', 'auth_codes', 'tokens', 'clients', 'profile_check', 'host']; - $tables = DBA::selectToArray(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_NAME'], + $tables = DBA::selectToArray('INFORMATION_SCHEMA.TABLES', ['TABLE_NAME'], ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']); if (empty($tables)) { @@ -119,13 +111,13 @@ class DBStructure public static function convertToInnoDB() { $tables = DBA::selectToArray( - ['information_schema' => 'tables'], + 'information_schema.tables', ['table_name'], ['engine' => 'MyISAM', 'table_schema' => DBA::databaseName()] ); $tables = array_merge($tables, DBA::selectToArray( - ['information_schema' => 'tables'], + 'information_schema.tables', ['table_name'], ['engine' => 'InnoDB', 'ROW_FORMAT' => ['COMPACT', 'REDUNDANT'], 'table_schema' => DBA::databaseName()] )); @@ -153,7 +145,7 @@ class DBStructure * * @return string Error message */ - private static function printUpdateError($message) + private static function printUpdateError(string $message): string { echo DI::l10n()->t("\nError %d occurred during database update:\n%s\n", DBA::errorNo(), DBA::errorMessage()); @@ -161,334 +153,15 @@ class DBStructure return DI::l10n()->t('Errors encountered performing database changes: ') . $message . EOL; } - public static function writeStructure() - { - $tables = []; - foreach (self::definition(null) as $name => $definition) { - $indexes = [[ - 'name' => 'Name', - 'fields' => 'Fields', - ], - [ - 'name' => '-', - 'fields' => '-', - ]]; - - $lengths = ['name' => 4, 'fields' => 6]; - foreach ($definition['indexes'] as $key => $value) { - $fieldlist = implode(', ', $value); - $indexes[] = ['name' => $key, 'fields' => $fieldlist]; - $lengths['name'] = max($lengths['name'], strlen($key)); - $lengths['fields'] = max($lengths['fields'], strlen($fieldlist)); - } - - array_walk_recursive($indexes, function(&$value, $key) use ($lengths) - { - $value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' '); - }); - - $foreign = []; - $fields = [[ - 'name' => 'Field', - 'comment' => 'Description', - 'type' => 'Type', - 'null' => 'Null', - 'primary' => 'Key', - 'default' => 'Default', - 'extra' => 'Extra', - ], - [ - 'name' => '-', - 'comment' => '-', - 'type' => '-', - 'null' => '-', - 'primary' => '-', - 'default' => '-', - 'extra' => '-', - ]]; - $lengths = [ - 'name' => 5, - 'comment' => 11, - 'type' => 4, - 'null' => 4, - 'primary' => 3, - 'default' => 7, - 'extra' => 5, - ]; - foreach ($definition['fields'] as $key => $value) { - $field = []; - $field['name'] = $key; - $field['comment'] = $value['comment'] ?? ''; - $field['type'] = $value['type']; - $field['null'] = ($value['not null'] ?? false) ? 'NO' : 'YES'; - $field['primary'] = ($value['primary'] ?? false) ? 'PRI' : ''; - $field['default'] = $value['default'] ?? 'NULL'; - $field['extra'] = $value['extra'] ?? ''; - - foreach ($field as $fieldname => $fieldvalue) { - $lengths[$fieldname] = max($lengths[$fieldname] ?? 0, strlen($fieldvalue)); - } - $fields[] = $field; - - if (!empty($value['foreign'])) { - $foreign[] = [ - 'field' => $key, - 'targettable' => array_keys($value['foreign'])[0], - 'targetfield' => array_values($value['foreign'])[0] - ]; - } - } - - array_walk_recursive($fields, function(&$value, $key) use ($lengths) - { - $value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' '); - }); - - $tables[] = ['name' => $name, 'comment' => $definition['comment']]; - $content = Renderer::replaceMacros(Renderer::getMarkupTemplate('structure.tpl'), [ - '$name' => $name, - '$comment' => $definition['comment'], - '$fields' => $fields, - '$indexes' => $indexes, - '$foreign' => $foreign, - ]); - $filename = DI::basePath() . '/doc/database/db_' . $name . '.md'; - file_put_contents($filename, $content); - } - asort($tables); - $content = Renderer::replaceMacros(Renderer::getMarkupTemplate('tables.tpl'), [ - '$tables' => $tables, - ]); - $filename = DI::basePath() . '/doc/database.md'; - file_put_contents($filename, $content); - } - - public static function printStructure($basePath) - { - $database = self::definition($basePath, false); - - echo "-- ------------------------------------------\n"; - echo "-- " . FRIENDICA_PLATFORM . " " . FRIENDICA_VERSION . " (" . FRIENDICA_CODENAME, ")\n"; - echo "-- DB_UPDATE_VERSION " . DB_UPDATE_VERSION . "\n"; - echo "-- ------------------------------------------\n\n\n"; - foreach ($database as $name => $structure) { - echo "--\n"; - echo "-- TABLE $name\n"; - echo "--\n"; - self::createTable($name, $structure, true, false); - - echo "\n"; - } - - View::printStructure($basePath); - } - - /** - * Loads the database structure definition from the static/dbstructure.config.php file. - * On first pass, defines DB_UPDATE_VERSION constant. - * - * @see static/dbstructure.config.php - * @param boolean $with_addons_structure Whether to tack on addons additional tables - * @param string $basePath The base path of this application - * @return array - * @throws Exception - */ - public static function definition($basePath, $with_addons_structure = true) - { - if (!self::$definition) { - if (empty($basePath)) { - $basePath = DI::app()->getBasePath(); - } - - $filename = $basePath . '/static/dbstructure.config.php'; - - if (!is_readable($filename)) { - throw new Exception('Missing database structure config file static/dbstructure.config.php'); - } - - $definition = require $filename; - - if (!$definition) { - throw new Exception('Corrupted database structure config file static/dbstructure.config.php'); - } - - self::$definition = $definition; - } else { - $definition = self::$definition; - } - - if ($with_addons_structure) { - Hook::callAll('dbstructure_definition', $definition); - } - - return $definition; - } - - /** - * Get field data for the given table - * - * @param string $table - * @param array $data data fields - * @return array fields for the given - */ - public static function getFieldsForTable(string $table, array $data = []) - { - $definition = DBStructure::definition('', false); - if (empty($definition[$table])) { - return []; - } - - $fieldnames = array_keys($definition[$table]['fields']); - - $fields = []; - - // Assign all field that are present in the table - foreach ($fieldnames as $field) { - if (isset($data[$field])) { - // Limit the length of varchar, varbinary, char and binrary fields - if (is_string($data[$field]) && preg_match("/char\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) { - $data[$field] = mb_substr($data[$field], 0, $result[1]); - } elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) { - $data[$field] = substr($data[$field], 0, $result[1]); - } - $fields[$field] = $data[$field]; - } - } - - return $fields; - } - - private static function createTable($name, $structure, $verbose, $action) - { - $r = true; - - $engine = ""; - $comment = ""; - $sql_rows = []; - $primary_keys = []; - $foreign_keys = []; - - foreach ($structure["fields"] as $fieldname => $field) { - $sql_rows[] = "`" . DBA::escape($fieldname) . "` " . self::FieldCommand($field); - if (!empty($field['primary'])) { - $primary_keys[] = $fieldname; - } - if (!empty($field['foreign'])) { - $foreign_keys[$fieldname] = $field; - } - } - - if (!empty($structure["indexes"])) { - foreach ($structure["indexes"] as $indexname => $fieldnames) { - $sql_index = self::createIndex($indexname, $fieldnames, ""); - if (!is_null($sql_index)) { - $sql_rows[] = $sql_index; - } - } - } - - foreach ($foreign_keys as $fieldname => $parameters) { - $sql_rows[] = self::foreignCommand($name, $fieldname, $parameters); - } - - if (isset($structure["engine"])) { - $engine = " ENGINE=" . $structure["engine"]; - } - - if (isset($structure["comment"])) { - $comment = " COMMENT='" . DBA::escape($structure["comment"]) . "'"; - } - - $sql = implode(",\n\t", $sql_rows); - - $sql = sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n\t", DBA::escape($name)) . $sql . - "\n)" . $engine . " DEFAULT COLLATE utf8mb4_general_ci" . $comment; - if ($verbose) { - echo $sql . ";\n"; - } - - if ($action) { - $r = DBA::e($sql); - } - - return $r; - } - - private static function FieldCommand($parameters, $create = true) - { - $fieldstruct = $parameters["type"]; - - if (isset($parameters["Collation"])) { - $fieldstruct .= " COLLATE " . $parameters["Collation"]; - } - - if (isset($parameters["not null"])) { - $fieldstruct .= " NOT NULL"; - } - - if (isset($parameters["default"])) { - if (strpos(strtolower($parameters["type"]), "int") !== false) { - $fieldstruct .= " DEFAULT " . $parameters["default"]; - } else { - $fieldstruct .= " DEFAULT '" . $parameters["default"] . "'"; - } - } - if (isset($parameters["extra"])) { - $fieldstruct .= " " . $parameters["extra"]; - } - - if (isset($parameters["comment"])) { - $fieldstruct .= " COMMENT '" . DBA::escape($parameters["comment"]) . "'"; - } - - /*if (($parameters["primary"] != "") && $create) - $fieldstruct .= " PRIMARY KEY";*/ - - return ($fieldstruct); - } - - private static function createIndex($indexname, $fieldnames, $method = "ADD") - { - $method = strtoupper(trim($method)); - if ($method != "" && $method != "ADD") { - throw new Exception("Invalid parameter 'method' in self::createIndex(): '$method'"); - } - - if (in_array($fieldnames[0], ["UNIQUE", "FULLTEXT"])) { - $index_type = array_shift($fieldnames); - $method .= " " . $index_type; - } - - $names = ""; - foreach ($fieldnames as $fieldname) { - if ($names != "") { - $names .= ","; - } - - if (preg_match('|(.+)\((\d+)\)|', $fieldname, $matches)) { - $names .= "`" . DBA::escape($matches[1]) . "`(" . intval($matches[2]) . ")"; - } else { - $names .= "`" . DBA::escape($fieldname) . "`"; - } - } - - if ($indexname == "PRIMARY") { - return sprintf("%s PRIMARY KEY(%s)", $method, $names); - } - - - $sql = sprintf("%s INDEX `%s` (%s)", $method, DBA::escape($indexname), $names); - return ($sql); - } - /** * Perform a database structure dryrun (means: just simulating) * + * @return string Empty string if the update is successful, error messages otherwise * @throws Exception */ - public static function dryRun() + public static function dryRun(): string { - self::update(DI::app()->getBasePath(), true, false); + return self::update(true, false); } /** @@ -500,13 +173,13 @@ class DBStructure * @return string Empty string if the update is successful, error messages otherwise * @throws Exception */ - public static function performUpdate(bool $enable_maintenance_mode = true, bool $verbose = false) + public static function performUpdate(bool $enable_maintenance_mode = true, bool $verbose = false): string { if ($enable_maintenance_mode) { DI::config()->set('system', 'maintenance', 1); } - $status = self::update(DI::app()->getBasePath(), $verbose, true); + $status = self::update($verbose, true); if ($enable_maintenance_mode) { DI::config()->set('system', 'maintenance', 0); @@ -519,20 +192,17 @@ class DBStructure /** * Updates DB structure from the installation and returns eventual errors messages * - * @param string $basePath The base path of this application - * * @return string Empty string if the update is successful, error messages otherwise * @throws Exception */ - public static function install(string $basePath) + public static function install(): string { - return self::update($basePath, false, true, true); + return self::update(false, true, true); } /** * Updates DB structure and returns eventual errors messages * - * @param string $basePath The base path of this application * @param bool $verbose * @param bool $action Whether to actually apply the update * @param bool $install Is this the initial update during the installation? @@ -541,7 +211,7 @@ class DBStructure * @return string Empty string if the update is successful, error messages otherwise * @throws Exception */ - private static function update($basePath, $verbose, $action, $install = false, array $tables = null, array $definition = null) + private static function update(bool $verbose, bool $action, bool $install = false, array $tables = null, array $definition = null): string { $in_maintenance_mode = DI::config()->get('system', 'maintenance'); @@ -579,7 +249,7 @@ class DBStructure // Get the definition if (is_null($definition)) { - $definition = self::definition($basePath); + $definition = DI::dbaDefinition()->getAll(); } // MySQL >= 5.7.4 doesn't support the IGNORE keyword in ALTER TABLE statements @@ -593,11 +263,17 @@ class DBStructure // Compare it foreach ($definition as $name => $structure) { $is_new_table = false; - $sql3 = ""; + $sql3 = ""; if (!isset($database[$name])) { - $r = self::createTable($name, $structure, $verbose, $action); - if (!DBA::isResult($r)) { - $errors .= self::printUpdateError($name); + $sql = DbaDefinitionSqlWriter::createTable($name, $structure, $verbose, $action); + if ($verbose) { + echo $sql; + } + if ($action) { + $r = DBA::e($sql); + if (!DBA::isResult($r)) { + $errors .= self::printUpdateError($name); + } } $is_new_table = true; } else { @@ -606,15 +282,15 @@ class DBStructure * or the definition differ from current status * and index name doesn't start with "local_" */ - foreach ($database[$name]["indexes"] as $indexname => $fieldnames) { - $current_index_definition = implode(",", $fieldnames); - if (isset($structure["indexes"][$indexname])) { - $new_index_definition = implode(",", $structure["indexes"][$indexname]); + foreach ($database[$name]["indexes"] as $indexName => $fieldNames) { + $current_index_definition = implode(",", $fieldNames); + if (isset($structure["indexes"][$indexName])) { + $new_index_definition = implode(",", $structure["indexes"][$indexName]); } else { $new_index_definition = "__NOT_SET__"; } - if ($current_index_definition != $new_index_definition && substr($indexname, 0, 6) != 'local_') { - $sql2 = self::dropIndex($indexname); + if ($current_index_definition != $new_index_definition && substr($indexName, 0, 6) != 'local_') { + $sql2 = DbaDefinitionSqlWriter::dropIndex($indexName); if ($sql3 == "") { $sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2; } else { @@ -623,9 +299,9 @@ class DBStructure } } // Compare the field structure field by field - foreach ($structure["fields"] as $fieldname => $parameters) { - if (!isset($database[$name]["fields"][$fieldname])) { - $sql2 = self::addTableField($fieldname, $parameters); + foreach ($structure["fields"] as $fieldName => $parameters) { + if (!isset($database[$name]["fields"][$fieldName])) { + $sql2 = DbaDefinitionSqlWriter::addTableField($fieldName, $parameters); if ($sql3 == "") { $sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2; } else { @@ -633,7 +309,7 @@ class DBStructure } } else { // Compare the field definition - $field_definition = $database[$name]["fields"][$fieldname]; + $field_definition = $database[$name]["fields"][$fieldName]; // Remove the relation data that is used for the referential integrity unset($parameters['relation']); @@ -651,9 +327,9 @@ class DBStructure } $current_field_definition = DBA::cleanQuery(implode(",", $field_definition)); - $new_field_definition = DBA::cleanQuery(implode(",", $parameters)); + $new_field_definition = DBA::cleanQuery(implode(",", $parameters)); if ($current_field_definition != $new_field_definition) { - $sql2 = self::modifyTableField($fieldname, $parameters); + $sql2 = DbaDefinitionSqlWriter::modifyTableField($fieldName, $parameters); if ($sql3 == "") { $sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2; } else { @@ -670,15 +346,15 @@ class DBStructure * Don't create keys if table is new */ if (!$is_new_table) { - foreach ($structure["indexes"] as $indexname => $fieldnames) { - if (isset($database[$name]["indexes"][$indexname])) { - $current_index_definition = implode(",", $database[$name]["indexes"][$indexname]); + foreach ($structure["indexes"] as $indexName => $fieldNames) { + if (isset($database[$name]["indexes"][$indexName])) { + $current_index_definition = implode(",", $database[$name]["indexes"][$indexName]); } else { $current_index_definition = "__NOT_SET__"; } - $new_index_definition = implode(",", $fieldnames); + $new_index_definition = implode(",", $fieldNames); if ($current_index_definition != $new_index_definition) { - $sql2 = self::createIndex($indexname, $fieldnames); + $sql2 = DbaDefinitionSqlWriter::createIndex($indexName, $fieldNames); if ($sql2 != "") { if ($sql3 == "") { @@ -694,17 +370,17 @@ class DBStructure // Foreign keys // Compare the field structure field by field - foreach ($structure["fields"] as $fieldname => $parameters) { + foreach ($structure["fields"] as $fieldName => $parameters) { if (empty($parameters['foreign'])) { continue; } - $constraint = self::getConstraintName($name, $fieldname, $parameters); + $constraint = self::getConstraintName($name, $fieldName, $parameters); unset($existing_foreign_keys[$constraint]); if (empty($database[$name]['foreign_keys'][$constraint])) { - $sql2 = self::addForeignKey($name, $fieldname, $parameters); + $sql2 = DbaDefinitionSqlWriter::addForeignKey($fieldName, $parameters); if ($sql3 == "") { $sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2; @@ -715,7 +391,7 @@ class DBStructure } foreach ($existing_foreign_keys as $param) { - $sql2 = self::dropForeignKey($param['CONSTRAINT_NAME']); + $sql2 = DbaDefinitionSqlWriter::dropForeignKey($param['CONSTRAINT_NAME']); if ($sql3 == "") { $sql3 = "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2; @@ -767,9 +443,9 @@ class DBStructure // Now have a look at the field collations // Compare the field structure field by field - foreach ($structure["fields"] as $fieldname => $parameters) { + foreach ($structure["fields"] as $fieldName => $parameters) { // Compare the field definition - $field_definition = ($database[$name]["fields"][$fieldname] ?? '') ?: ['Collation' => '']; + $field_definition = ($database[$name]["fields"][$fieldName] ?? '') ?: ['Collation' => '']; // Define the default collation if not given if (!isset($parameters['Collation']) && !empty($field_definition['Collation'])) { @@ -779,7 +455,7 @@ class DBStructure } if ($field_definition['Collation'] != $parameters['Collation']) { - $sql2 = self::modifyTableField($fieldname, $parameters); + $sql2 = DbaDefinitionSqlWriter::modifyTableField($fieldName, $parameters); if (($sql3 == "") || (substr($sql3, -2, 2) == "; ")) { $sql3 .= "ALTER" . $ignore . " TABLE `" . $name . "` " . $sql2; } else { @@ -826,23 +502,29 @@ class DBStructure return $errors; } - private static function tableStructure($table) + /** + * Returns an array with table structure information + * + * @param string $table Name of table + * @return array Table structure information + */ + private static function tableStructure(string $table): array { // This query doesn't seem to be executable as a prepared statement $indexes = DBA::toArray(DBA::p("SHOW INDEX FROM " . DBA::quoteIdentifier($table))); - $fields = DBA::selectToArray(['INFORMATION_SCHEMA' => 'COLUMNS'], + $fields = DBA::selectToArray('INFORMATION_SCHEMA.COLUMNS', ['COLUMN_NAME', 'COLUMN_TYPE', 'IS_NULLABLE', 'COLUMN_DEFAULT', 'EXTRA', 'COLUMN_KEY', 'COLLATION_NAME', 'COLUMN_COMMENT'], ["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?", DBA::databaseName(), $table]); - $foreign_keys = DBA::selectToArray(['INFORMATION_SCHEMA' => 'KEY_COLUMN_USAGE'], + $foreign_keys = DBA::selectToArray('INFORMATION_SCHEMA.KEY_COLUMN_USAGE', ['COLUMN_NAME', 'CONSTRAINT_NAME', 'REFERENCED_TABLE_NAME', 'REFERENCED_COLUMN_NAME'], ["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `REFERENCED_TABLE_SCHEMA` IS NOT NULL", DBA::databaseName(), $table]); - $table_status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'], + $table_status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES', ['ENGINE', 'TABLE_COLLATION', 'TABLE_COMMENT'], ["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?", DBA::databaseName(), $table]); @@ -909,65 +591,20 @@ class DBStructure } } - return ["fields" => $fielddata, "indexes" => $indexdata, - "foreign_keys" => $foreigndata, "table_status" => $table_status]; + return [ + 'fields' => $fielddata, + 'indexes' => $indexdata, + 'foreign_keys' => $foreigndata, + 'table_status' => $table_status + ]; } - private static function dropIndex($indexname) - { - $sql = sprintf("DROP INDEX `%s`", DBA::escape($indexname)); - return ($sql); - } - - private static function addTableField($fieldname, $parameters) - { - $sql = sprintf("ADD `%s` %s", DBA::escape($fieldname), self::FieldCommand($parameters)); - return ($sql); - } - - private static function modifyTableField($fieldname, $parameters) - { - $sql = sprintf("MODIFY `%s` %s", DBA::escape($fieldname), self::FieldCommand($parameters, false)); - return ($sql); - } - - private static function getConstraintName(string $tablename, string $fieldname, array $parameters) + private static function getConstraintName(string $tableName, string $fieldName, array $parameters): string { $foreign_table = array_keys($parameters['foreign'])[0]; $foreign_field = array_values($parameters['foreign'])[0]; - return $tablename . "-" . $fieldname. "-" . $foreign_table. "-" . $foreign_field; - } - - private static function foreignCommand(string $tablename, string $fieldname, array $parameters) { - $foreign_table = array_keys($parameters['foreign'])[0]; - $foreign_field = array_values($parameters['foreign'])[0]; - - $sql = "FOREIGN KEY (`" . $fieldname . "`) REFERENCES `" . $foreign_table . "` (`" . $foreign_field . "`)"; - - if (!empty($parameters['foreign']['on update'])) { - $sql .= " ON UPDATE " . strtoupper($parameters['foreign']['on update']); - } else { - $sql .= " ON UPDATE RESTRICT"; - } - - if (!empty($parameters['foreign']['on delete'])) { - $sql .= " ON DELETE " . strtoupper($parameters['foreign']['on delete']); - } else { - $sql .= " ON DELETE CASCADE"; - } - - return $sql; - } - - private static function addForeignKey(string $tablename, string $fieldname, array $parameters) - { - return sprintf("ADD %s", self::foreignCommand($tablename, $fieldname, $parameters)); - } - - private static function dropForeignKey(string $constraint) - { - return sprintf("DROP FOREIGN KEY `%s`", $constraint); + return $tableName . '-' . $fieldName. '-' . $foreign_table. '-' . $foreign_field; } /** @@ -983,7 +620,7 @@ class DBStructure * @return boolean Was the renaming successful? * @throws Exception */ - public static function rename($table, $columns, $type = self::RENAME_COLUMN) + public static function rename(string $table, array $columns, int $type = self::RENAME_COLUMN): bool { if (empty($table) || empty($columns)) { return false; @@ -1019,7 +656,7 @@ class DBStructure return false; } - $sql .= ";"; + $sql .= ';'; $stmt = DBA::p($sql); @@ -1043,7 +680,7 @@ class DBStructure * @return boolean Does the table exist? * @throws Exception */ - public static function existsColumn($table, $columns = []) + public static function existsColumn(string $table, array $columns = []): bool { if (empty($table)) { return false; @@ -1079,39 +716,33 @@ class DBStructure /** * Check if a foreign key exists for the given table field * - * @param string $table - * @param string $field - * @return boolean + * @param string $table Table name + * @param string $field Field name + * @return boolean Wether a foreign key exists */ - public static function existsForeignKeyForField(string $table, string $field) + public static function existsForeignKeyForField(string $table, string $field): bool { - return DBA::exists(['INFORMATION_SCHEMA' => 'KEY_COLUMN_USAGE'], + return DBA::exists('INFORMATION_SCHEMA.KEY_COLUMN_USAGE', ["`TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ? AND `REFERENCED_TABLE_SCHEMA` IS NOT NULL", DBA::databaseName(), $table, $field]); } + /** - * Check if a table exists - * - * @param string|array $table Table name + * Check if a table exists * + * @param string $table Single table name (please loop yourself) * @return boolean Does the table exist? * @throws Exception */ - public static function existsTable($table) + public static function existsTable(string $table): bool { if (empty($table)) { return false; } - if (is_array($table)) { - $condition = ['table_schema' => key($table), 'table_name' => current($table)]; - } else { - $condition = ['table_schema' => DBA::databaseName(), 'table_name' => $table]; - } + $condition = ['table_schema' => DBA::databaseName(), 'table_name' => $table]; - $result = DBA::exists(['information_schema' => 'tables'], $condition); - - return $result; + return DBA::exists('information_schema.tables', $condition); } /** @@ -1122,7 +753,7 @@ class DBStructure * @return array An array of the table columns * @throws Exception */ - public static function getColumns($table) + public static function getColumns(string $table): array { $stmtColumns = DBA::p("SHOW COLUMNS FROM `" . $table . "`"); return DBA::toArray($stmtColumns); @@ -1130,6 +761,9 @@ class DBStructure /** * Check if initial database values do exist - or create them + * + * @param bool $verbose Whether to output messages + * @return void */ public static function checkInitialValues(bool $verbose = false) { @@ -1163,9 +797,9 @@ class DBStructure if (self::existsTable('user') && !DBA::exists('user', ['uid' => 0])) { $user = [ - "verified" => true, - "page-flags" => User::PAGE_FLAGS_SOAPBOX, - "account-type" => User::ACCOUNT_TYPE_RELAY, + 'verified' => true, + 'page-flags' => User::PAGE_FLAGS_SOAPBOX, + 'account-type' => User::ACCOUNT_TYPE_RELAY, ]; DBA::insert('user', $user); $lastid = DBA::lastInsertId(); @@ -1265,12 +899,14 @@ class DBStructure * * @return boolean */ - private static function isUpdating() + private static function isUpdating(): bool { $isUpdate = false; - $processes = DBA::select(['information_schema' => 'processlist'], ['info'], - ['db' => DBA::databaseName(), 'command' => ['Query', 'Execute']]); + $processes = DBA::select('information_schema.processlist', ['info'], [ + 'db' => DBA::databaseName(), + 'command' => ['Query', 'Execute'] + ]); while ($process = DBA::fetch($processes)) { $parts = explode(' ', $process['info']); diff --git a/src/Database/Database.php b/src/Database/Database.php index 671425f9d1..3276e90e52 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -23,9 +23,12 @@ namespace Friendica\Database; use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\System; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; use Friendica\Network\HTTPException\ServiceUnavailableException; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; +use InvalidArgumentException; use mysqli; use mysqli_result; use mysqli_stmt; @@ -63,7 +66,7 @@ class Database protected $server_info = ''; /** @var PDO|mysqli */ protected $connection; - protected $driver; + protected $driver = ''; protected $pdo_emulate_prepares = false; private $error = false; private $errorno = 0; @@ -72,23 +75,29 @@ class Database protected $in_retrial = false; protected $testmode = false; private $relation = []; + /** @var DbaDefinition */ + protected $dbaDefinition; + /** @var ViewDefinition */ + protected $viewDefinition; - public function __construct(Cache $configCache, Profiler $profiler, LoggerInterface $logger) + public function __construct(Cache $configCache, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, LoggerInterface $logger) { // We are storing these values for being able to perform a reconnect - $this->configCache = $configCache; - $this->profiler = $profiler; - $this->logger = $logger; + $this->configCache = $configCache; + $this->profiler = $profiler; + $this->logger = $logger; + $this->dbaDefinition = $dbaDefinition; + $this->viewDefinition = $viewDefinition; $this->connect(); - - if ($this->isConnected()) { - // Loads DB_UPDATE_VERSION constant - DBStructure::definition($configCache->get('system', 'basepath'), false); - } } - public function connect() + /** + * Tries to connect to database + * + * @return bool Success + */ + public function connect(): bool { if (!is_null($this->connection) && $this->connected()) { return $this->connected; @@ -175,7 +184,7 @@ class Database // No suitable SQL driver was found. if (!$this->connected) { - $this->driver = null; + $this->driver = ''; $this->connection = null; } @@ -227,7 +236,7 @@ class Database } } - $this->driver = null; + $this->driver = ''; $this->connected = false; } @@ -255,7 +264,7 @@ class Database * * @return string with either "pdo" or "mysqli" */ - public function getDriver() + public function getDriver(): string { return $this->driver; } @@ -266,9 +275,9 @@ class Database * This function discriminate between the deprecated mysql API and the current * object-oriented mysqli API. Example of returned string: 5.5.46-0+deb8u1 * - * @return string + * @return string Database server information */ - public function serverInfo() + public function serverInfo(): string { if ($this->server_info == '') { switch ($this->driver) { @@ -286,10 +295,10 @@ class Database /** * Returns the selected database name * - * @return string + * @return string Database name * @throws \Exception */ - public function databaseName() + public function databaseName(): string { $ret = $this->p("SELECT DATABASE() AS `db`"); $data = $this->toArray($ret); @@ -300,10 +309,10 @@ class Database * Analyze a database query and log this if some conditions are met. * * @param string $query The database query that will be analyzed - * + * @return void * @throws \Exception */ - private function logIndex($query) + private function logIndex(string $query) { if (!$this->configCache->get('system', 'db_log_index')) { @@ -359,11 +368,10 @@ class Database * Removes every not allowlisted character from the identifier string * * @param string $identifier - * * @return string sanitized identifier * @throws \Exception */ - private function sanitizeIdentifier($identifier) + private function sanitizeIdentifier(string $identifier): string { return preg_replace('/[^A-Za-z0-9_\-]+/', '', $identifier); } @@ -383,11 +391,21 @@ class Database } } - public function isConnected() + /** + * Returns connected flag + * + * @return bool Whether connection to database was success + */ + public function isConnected(): bool { return $this->connected; } + /** + * Checks connection status + * + * @return bool Whether connection to database was success + */ public function connected() { $connected = false; @@ -424,7 +442,7 @@ class Database * * @return string The input SQL string modified if necessary. */ - public function anyValueFallback($sql) + public function anyValueFallback(string $sql): string { $server_info = $this->serverInfo(); if (version_compare($server_info, '5.7.5', '<') || @@ -442,7 +460,7 @@ class Database * * @return string The replaced SQL query */ - private function replaceParameters($sql, $args) + private function replaceParameters(string $sql, array $args): string { $offset = 0; foreach ($args as $param => $value) { @@ -476,7 +494,7 @@ class Database * @return bool|object statement object or result object * @throws \Exception */ - public function p($sql) + public function p(string $sql) { $this->profiler->startRecording('database'); @@ -541,7 +559,7 @@ class Database if (!$retval = $this->connection->query($this->replaceParameters($sql, $args))) { $errorInfo = $this->connection->errorInfo(); $this->error = $errorInfo[2]; - $this->errorno = $errorInfo[1]; + $this->errorno = (int) $errorInfo[1]; $retval = false; $is_error = true; break; @@ -554,7 +572,7 @@ class Database if (!$stmt = $this->connection->prepare($sql)) { $errorInfo = $this->connection->errorInfo(); $this->error = $errorInfo[2]; - $this->errorno = $errorInfo[1]; + $this->errorno = (int) $errorInfo[1]; $retval = false; $is_error = true; break; @@ -574,7 +592,7 @@ class Database if (!$stmt->execute()) { $errorInfo = $stmt->errorInfo(); $this->error = $errorInfo[2]; - $this->errorno = $errorInfo[1]; + $this->errorno = (int) $errorInfo[1]; $retval = false; $is_error = true; } else { @@ -709,7 +727,7 @@ class Database } $this->error = $error; - $this->errorno = $errorno; + $this->errorno = (int) $errorno; } $this->profiler->stopRecording(); @@ -741,8 +759,9 @@ class Database * @return boolean Was the query successfull? False is returned only if an error occurred * @throws \Exception */ - public function e($sql) + public function e(string $sql): bool { + $retval = false; $this->profiler->startRecording('database_write'); @@ -804,13 +823,14 @@ class Database /** * Check if data exists * - * @param string|array $table Table name or array [schema => table] - * @param array $condition array of fields for condition + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $condition Array of fields for condition * * @return boolean Are there rows for that condition? * @throws \Exception + * @todo Please unwrap the DBStructure::existsTable() call so this method has one behavior only: checking existence on records */ - public function exists($table, $condition) + public function exists(string $table, array $condition): bool { if (empty($table)) { return false; @@ -850,10 +870,10 @@ class Database * * @param string $sql SQL statement * - * @return array first row of query + * @return array|bool first row of query or false on failure * @throws \Exception */ - public function fetchFirst($sql) + public function fetchFirst(string $sql) { $params = DBA::getParam(func_get_args()); @@ -875,7 +895,7 @@ class Database * * @return int Number of rows */ - public function affectedRows() + public function affectedRows(): int { return $this->affected_rows; } @@ -887,7 +907,7 @@ class Database * * @return int Number of columns */ - public function columnCount($stmt) + public function columnCount($stmt): int { if (!is_object($stmt)) { return 0; @@ -908,7 +928,7 @@ class Database * * @return int Number of rows */ - public function numRows($stmt) + public function numRows($stmt): int { if (!is_object($stmt)) { return 0; @@ -927,7 +947,7 @@ class Database * * @param bool|PDOStatement|mysqli_stmt $stmt statement object * - * @return array|false current row + * @return array|bool Current row or false on failure */ public function fetch($stmt) { @@ -987,14 +1007,14 @@ class Database /** * Insert a row into a table. Field value objects will be cast as string. * - * @param string|array $table Table name or array [schema => table] - * @param array $param parameter array - * @param int $duplicate_mode What to do on a duplicated entry + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $param parameter array + * @param int $duplicate_mode What to do on a duplicated entry * * @return boolean was the insert successful? * @throws \Exception */ - public function insert($table, array $param, int $duplicate_mode = self::INSERT_DEFAULT) + public function insert(string $table, array $param, int $duplicate_mode = self::INSERT_DEFAULT): bool { if (empty($table) || empty($param)) { $this->logger->info('Table and fields have to be set'); @@ -1003,7 +1023,7 @@ class Database $param = $this->castFields($table, $param); - $table_string = DBA::buildTableString($table); + $table_string = DBA::buildTableString([$table]); $fields_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], array_keys($param))); @@ -1038,13 +1058,12 @@ class Database * Inserts a row with the provided data in the provided table. * If the data corresponds to an existing row through a UNIQUE or PRIMARY index constraints, it updates the row instead. * - * @param string|array $table Table name or array [schema => table] - * @param array $param parameter array - * + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $param parameter array * @return boolean was the insert successful? * @throws \Exception */ - public function replace($table, array $param) + public function replace(string $table, array $param): bool { if (empty($table) || empty($param)) { $this->logger->info('Table and fields have to be set'); @@ -1053,7 +1072,7 @@ class Database $param = $this->castFields($table, $param); - $table_string = DBA::buildTableString($table); + $table_string = DBA::buildTableString([$table]); $fields_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], array_keys($param))); @@ -1069,7 +1088,7 @@ class Database * * @return integer Last inserted id */ - public function lastInsertId() + public function lastInsertId(): int { switch ($this->driver) { case self::PDO: @@ -1087,12 +1106,11 @@ class Database * * This function can be extended in the future to accept a table array as well. * - * @param string|array $table Table name or array [schema => table] - * + * @param string $table Table name in format schema.table (while scheme is optiona) * @return boolean was the lock successful? * @throws \Exception */ - public function lock($table) + public function lock(string $table): bool { // See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html if ($this->driver == self::PDO) { @@ -1102,7 +1120,7 @@ class Database $this->connection->autocommit(false); } - $success = $this->e("LOCK TABLES " . DBA::buildTableString($table) . " WRITE"); + $success = $this->e("LOCK TABLES " . DBA::buildTableString([$table]) . " WRITE"); if ($this->driver == self::PDO) { $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares); @@ -1126,7 +1144,7 @@ class Database * @return boolean was the unlock successful? * @throws \Exception */ - public function unlock() + public function unlock(): bool { // See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html $this->performCommit(); @@ -1177,7 +1195,12 @@ class Database return true; } - protected function performCommit() + /** + * Performs the commit + * + * @return boolean Was the command executed successfully? + */ + protected function performCommit(): bool { switch ($this->driver) { case self::PDO: @@ -1199,7 +1222,7 @@ class Database * * @return boolean Was the command executed successfully? */ - public function commit() + public function commit(): bool { if (!$this->performCommit()) { return false; @@ -1213,7 +1236,7 @@ class Database * * @return boolean Was the command executed successfully? */ - public function rollback() + public function rollback(): bool { $ret = false; @@ -1230,6 +1253,7 @@ class Database $ret = $this->connection->rollback(); break; } + $this->in_transaction = false; return $ret; } @@ -1243,14 +1267,14 @@ class Database * @return boolean was the delete successful? * @throws \Exception */ - public function delete($table, array $conditions) + public function delete(string $table, array $conditions): bool { if (empty($table) || empty($conditions)) { $this->logger->info('Table and conditions have to be set'); return false; } - $table_string = DBA::buildTableString($table); + $table_string = DBA::buildTableString([$table]); $condition_string = DBA::buildCondition($conditions); @@ -1280,7 +1304,7 @@ class Database * Only set $old_fields to a boolean value when you are sure that you will update a single row. * When you set $old_fields to "true" then $fields must contain all relevant fields! * - * @param string|array $table Table name or array [schema => table] + * @param string $table Table name in format schema.table (while scheme is optiona) * @param array $fields contains the fields that are updated * @param array $condition condition array with the key values * @param array|boolean $old_fields array with the old field values that are about to be replaced (true = update on duplicate, false = don't update identical fields) @@ -1288,8 +1312,9 @@ class Database * * @return boolean was the update successfull? * @throws \Exception + * @todo Implement "bool $update_on_duplicate" to avoid mixed type for $old_fields */ - public function update($table, $fields, $condition, $old_fields = [], $params = []) + public function update(string $table, array $fields, array $condition, $old_fields = [], array $params = []) { if (empty($table) || empty($fields) || empty($condition)) { $this->logger->info('Table, fields and condition have to be set'); @@ -1322,7 +1347,7 @@ class Database $fields = $this->castFields($table, $fields); - $table_string = DBA::buildTableString($table); + $table_string = DBA::buildTableString([$table]); $condition_string = DBA::buildCondition($condition); @@ -1345,16 +1370,16 @@ class Database /** * Retrieve a single record from a table and returns it in an associative array * - * @param string|array $table - * @param array $fields - * @param array $condition - * @param array $params + * @param string $table Table name in format schema.table (while scheme is optiona) + * @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 * * @return bool|array * @throws \Exception * @see $this->select */ - public function selectFirst($table, array $fields = [], array $condition = [], $params = []) + public function selectFirst(string $table, array $fields = [], array $condition = [], array $params = []) { $params['limit'] = 1; $result = $this->select($table, $fields, $condition, $params); @@ -1371,16 +1396,15 @@ class Database /** * Select rows from a table and fills an array with the data * - * @param string|array $table Table name or array [schema => table] - * @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 - * + * @param string $table Table name in format schema.table (while scheme is optiona) + * @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 * @return array Data array * @throws \Exception * @see self::select */ - public function selectToArray($table, array $fields = [], array $condition = [], array $params = []) + public function selectToArray(string $table, array $fields = [], array $condition = [], array $params = []) { return $this->toArray($this->select($table, $fields, $condition, $params)); } @@ -1390,9 +1414,9 @@ class Database * * @param array $fields * @param array $options - * @return array + * @return array Escaped fields */ - private function escapeFields(array $fields, array $options) + private function escapeFields(array $fields, array $options): array { // In the case of a "GROUP BY" we have to add all the ORDER fields to the fieldlist. // This needs to done to apply the "ANY_VALUE(...)" treatment from below to them. @@ -1446,14 +1470,14 @@ class Database * * $data = DBA::select($table, $fields, $condition, $params); * - * @param string|array $table Table name or array [schema => table] - * @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 + * @param string $table Table name in format schema.table (while scheme is optiona) + * @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 * @return boolean|object * @throws \Exception */ - public function select($table, array $fields = [], array $condition = [], array $params = []) + public function select(string $table, array $fields = [], array $condition = [], array $params = []) { if (empty($table)) { return false; @@ -1466,7 +1490,7 @@ class Database $select_string = '*'; } - $table_string = DBA::buildTableString($table); + $table_string = DBA::buildTableString([$table]); $condition_string = DBA::buildCondition($condition); @@ -1486,11 +1510,11 @@ class Database /** * Counts the rows from a table satisfying the provided condition * - * @param string|array $table Table name or array [schema => table] - * @param array $condition Array of fields for condition - * @param array $params Array of several parameters + * @param string $table Table name in format schema.table (while scheme is optiona) + * @param array $condition Array of fields for condition + * @param array $params Array of several parameters * - * @return int + * @return int Count of rows * * Example: * $table = "post"; @@ -1502,13 +1526,13 @@ class Database * $count = DBA::count($table, $condition); * @throws \Exception */ - public function count($table, array $condition = [], array $params = []) + public function count(string $table, array $condition = [], array $params = []): int { if (empty($table)) { - return false; + throw new InvalidArgumentException('Parameter "table" cannot be empty.'); } - $table_string = DBA::buildTableString($table); + $table_string = DBA::buildTableString([$table]); $condition_string = DBA::buildCondition($condition); @@ -1541,7 +1565,7 @@ class Database * * @return array Data array */ - public function toArray($stmt, $do_close = true, int $count = 0) + public function toArray($stmt, bool $do_close = true, int $count = 0): array { if (is_bool($stmt)) { return []; @@ -1569,7 +1593,8 @@ class Database * @param array $fields * @return array casted fields */ - public function castFields(string $table, array $fields) { + public function castFields(string $table, array $fields): array + { // When there is no data, we don't need to do something if (empty($fields)) { return $fields; @@ -1587,15 +1612,15 @@ class Database $types = []; - $tables = DBStructure::definition('', false); + $tables = $this->dbaDefinition->getAll(); if (empty($tables[$table])) { // When a matching table wasn't found we check if it is a view - $views = View::definition('', false); + $views = $this->viewDefinition->getAll(); if (empty($views[$table])) { return $fields; } - foreach(array_keys($fields) as $field) { + foreach (array_keys($fields) as $field) { if (!empty($views[$table]['fields'][$field])) { $viewdef = $views[$table]['fields'][$field]; if (!empty($tables[$viewdef[0]]['fields'][$viewdef[1]]['type'])) { @@ -1632,7 +1657,7 @@ class Database * * @return string Error number (0 if no error) */ - public function errorNo() + public function errorNo(): int { return $this->errorno; } @@ -1642,7 +1667,7 @@ class Database * * @return string Error message ('' if no error) */ - public function errorMessage() + public function errorMessage(): string { return $this->error; } @@ -1654,7 +1679,7 @@ class Database * * @return boolean was the close successful? */ - public function close($stmt) + public function close($stmt): bool { $this->profiler->startRecording('database'); @@ -1696,38 +1721,39 @@ class Database * 'amount' => Number of concurrent database processes * @throws \Exception */ - public function processlist() + public function processlist(): array { - $ret = $this->p("SHOW PROCESSLIST"); + $ret = $this->p('SHOW PROCESSLIST'); $data = $this->toArray($ret); $processes = 0; $states = []; foreach ($data as $process) { - $state = trim($process["State"]); + $state = trim($process['State']); // Filter out all non blocking processes - if (!in_array($state, ["", "init", "statistics", "updating"])) { + if (!in_array($state, ['', 'init', 'statistics', 'updating'])) { ++$states[$state]; ++$processes; } } - $statelist = ""; + $statelist = ''; foreach ($states as $state => $usage) { - if ($statelist != "") { - $statelist .= ", "; + if ($statelist != '') { + $statelist .= ', '; } - $statelist .= $state . ": " . $usage; + $statelist .= $state . ': ' . $usage; } - return (["list" => $statelist, "amount" => $processes]); + return (['list' => $statelist, 'amount' => $processes]); } /** * Fetch a database variable * * @param string $name - * @return string content + * @return string|null content or null if inexistent + * @throws \Exception */ public function getVariable(string $name) { @@ -1739,10 +1765,9 @@ class Database * Checks if $array is a filled array with at least one entry. * * @param mixed $array A filled array with at least one entry - * * @return boolean Whether $array is a filled array or an object with rows */ - public function isResult($array) + public function isResult($array): bool { // It could be a return value from an update statement if (is_bool($array)) { @@ -1762,10 +1787,9 @@ class Database * @param mixed $value Array value * @param string $key Array key * @param boolean $add_quotation add quotation marks for string values - * * @return void */ - private function escapeArrayCallback(&$value, $key, $add_quotation) + private function escapeArrayCallback(&$value, string $key, bool $add_quotation) { if (!$add_quotation) { if (is_bool($value)) { @@ -1790,10 +1814,9 @@ class Database * * @param mixed $arr Array with values to be escaped * @param boolean $add_quotation add quotation marks for string values - * * @return void */ - public function escapeArray(&$arr, $add_quotation = false) + public function escapeArray(&$arr, bool $add_quotation = false) { array_walk($arr, [$this, 'escapeArrayCallback'], $add_quotation); } @@ -1801,13 +1824,14 @@ class Database /** * Replaces a string in the provided fields of the provided table * - * @param string $table_name + * @param string $table Table name * @param array $fields List of field names in the provided table - * @param string $search - * @param string $replace + * @param string $search String to search for + * @param string $replace String to replace with + * @return void * @throws \Exception */ - public function replaceInTableFields(string $table_name, array $fields, string $search, string $replace) + public function replaceInTableFields(string $table, array $fields, string $search, string $replace) { $search = $this->escape($search); $replace = $this->escape($replace); @@ -1820,9 +1844,10 @@ class Database $upds = implode(', ', $upd); - $r = $this->e(sprintf("UPDATE %s SET %s;", $table_name, $upds)); + $r = $this->e(sprintf("UPDATE %s SET %s;", DBA::quoteIdentifier($table), $upds)); + if (!$this->isResult($r)) { - throw new \RuntimeException("Failed updating `$table_name`: " . $this->errorMessage()); + throw new \RuntimeException("Failed updating `$table`: " . $this->errorMessage()); } } } diff --git a/src/Database/Definition/DbaDefinition.php b/src/Database/Definition/DbaDefinition.php new file mode 100644 index 0000000000..27eb175229 --- /dev/null +++ b/src/Database/Definition/DbaDefinition.php @@ -0,0 +1,126 @@ +. + * + */ + +namespace Friendica\Database\Definition; + +use Exception; +use Friendica\Core\Hook; + +/** + * Stores the whole database definition + */ +class DbaDefinition +{ + /** @var string The relative path of the db structure config file */ + const DBSTRUCTURE_RELATIVE_PATH = '/static/dbstructure.config.php'; + + /** @var array The complete DB definition as an array */ + protected $definition; + + /** @var string */ + protected $configFile; + + /** + * @param string $basePath The basepath of the dbstructure file (loads relative path in case of null) + * + * @throws Exception in case the config file isn't available/readable + */ + public function __construct(string $basePath) + { + $this->configFile = $basePath . static::DBSTRUCTURE_RELATIVE_PATH; + + if (!is_readable($this->configFile)) { + throw new Exception('Missing database structure config file static/dbstructure.config.php at basePath=' . $basePath); + } + } + + /** + * @return array Returns the whole Definition as an array + */ + public function getAll(): array + { + return $this->definition; + } + + /** + * Truncate field data for the given table + * + * @param string $table Name of the table to load field definitions for + * @param array $data data fields + * + * @return array fields for the given + */ + public function truncateFieldsForTable(string $table, array $data): array + { + $definition = $this->definition; + if (empty($definition[$table])) { + return []; + } + + $fieldNames = array_keys($definition[$table]['fields']); + + $fields = []; + + // Assign all field that are present in the table + foreach ($fieldNames as $field) { + if (isset($data[$field])) { + // Limit the length of varchar, varbinary, char and binrary fields + if (is_string($data[$field]) && preg_match("/char\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) { + $data[$field] = mb_substr($data[$field], 0, $result[1]); + } elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) { + $data[$field] = substr($data[$field], 0, $result[1]); + } + $fields[$field] = $data[$field]; + } + } + + return $fields; + } + + /** + * Loads the database structure definition from the static/dbstructure.config.php file. + * On first pass, defines DB_UPDATE_VERSION constant. + * + * @param bool $withAddonStructure Whether to tack on addons additional tables + * + * @throws Exception in case the definition cannot be found + * + * @see static/dbstructure.config.php + * + * @return self The current instance + */ + public function load(bool $withAddonStructure = false): self + { + $definition = require $this->configFile; + + if (!$definition) { + throw new Exception('Corrupted database structure config file static/dbstructure.config.php'); + } + + if ($withAddonStructure) { + Hook::callAll('dbstructure_definition', $definition); + } + + $this->definition = $definition; + + return $this; + } +} diff --git a/src/Database/Definition/ViewDefinition.php b/src/Database/Definition/ViewDefinition.php new file mode 100644 index 0000000000..1971f0cce2 --- /dev/null +++ b/src/Database/Definition/ViewDefinition.php @@ -0,0 +1,91 @@ +. + * + */ + +namespace Friendica\Database\Definition; + +use Exception; +use Friendica\Core\Hook; + +/** + * Stores the whole View definitions + */ +class ViewDefinition +{ + /** @var string the relative path to the database view config file */ + const DBSTRUCTURE_RELATIVE_PATH = '/static/dbview.config.php'; + + /** @var array The complete view definition as an array */ + protected $definition; + + /** @var string */ + protected $configFile; + + /** + * @param string $basePath The basepath of the dbview file (loads relative path in case of null) + * + * @throws Exception in case the config file isn't available/readable + */ + public function __construct(string $basePath) + { + $this->configFile = $basePath . static::DBSTRUCTURE_RELATIVE_PATH; + + if (!is_readable($this->configFile)) { + throw new Exception('Missing database structure config file static/dbview.config.php at basePath=' . $basePath); + } + } + + /** + * @return array Returns the whole Definition as an array + */ + public function getAll(): array + { + return $this->definition; + } + + /** + * Loads the database structure definition from the static/dbview.config.php file. + * On first pass, defines DB_UPDATE_VERSION constant. + * + * @param bool $withAddonStructure Whether to tack on addons additional tables + * + * @throws Exception in case the definition cannot be found + * + * @see static/dbview.config.php + * + * @return self The current instance + */ + public function load(bool $withAddonStructure = false): self + { + $definition = require $this->configFile; + + if (!$definition) { + throw new Exception('Corrupted database structure config file static/dbstructure.config.php'); + } + + if ($withAddonStructure) { + Hook::callAll('dbview_definition', $definition); + } + + $this->definition = $definition; + + return $this; + } +} diff --git a/src/Database/PostUpdate.php b/src/Database/PostUpdate.php index 6d744a1ba1..26eef2c94f 100644 --- a/src/Database/PostUpdate.php +++ b/src/Database/PostUpdate.php @@ -133,7 +133,7 @@ class PostUpdate } $max_item_delivery_data = DBA::selectFirst('item-delivery-data', ['iid'], ['queue_count > 0 OR queue_done > 0'], ['order' => ['iid']]); - $max_iid = $max_item_delivery_data['iid']; + $max_iid = $max_item_delivery_data['iid'] ?? 0; Logger::info('Start update1297 with max iid: ' . $max_iid); @@ -538,7 +538,7 @@ class PostUpdate private static function update1347() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1347) { + if (DI::config()->get('system', 'post_update_version') >= 1347) { return true; } @@ -547,7 +547,7 @@ class PostUpdate return true; } - $id = DI::config()->get("system", "post_update_version_1347_id", 0); + $id = DI::config()->get('system', 'post_update_version_1347_id', 0); Logger::info('Start', ['item' => $id]); @@ -582,12 +582,12 @@ class PostUpdate } DBA::close($items); - DI::config()->set("system", "post_update_version_1347_id", $id); + DI::config()->set('system', 'post_update_version_1347_id', $id); Logger::info('Processed', ['rows' => $rows, 'last' => $id]); if ($start_id == $id) { - DI::config()->set("system", "post_update_version", 1347); + DI::config()->set('system', 'post_update_version', 1347); Logger::info('Done'); return true; } @@ -605,11 +605,11 @@ class PostUpdate private static function update1348() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1348) { + if (DI::config()->get('system', 'post_update_version') >= 1348) { return true; } - $id = DI::config()->get("system", "post_update_version_1348_id", 0); + $id = DI::config()->get('system', 'post_update_version_1348_id', 0); Logger::info('Start', ['contact' => $id]); @@ -635,12 +635,12 @@ class PostUpdate } DBA::close($contacts); - DI::config()->set("system", "post_update_version_1348_id", $id); + DI::config()->set('system', 'post_update_version_1348_id', $id); Logger::info('Processed', ['rows' => $rows, 'last' => $id]); if ($start_id == $id) { - DI::config()->set("system", "post_update_version", 1348); + DI::config()->set('system', 'post_update_version', 1348); Logger::info('Done'); return true; } @@ -658,11 +658,11 @@ class PostUpdate private static function update1349() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1349) { + if (DI::config()->get('system', 'post_update_version') >= 1349) { return true; } - $id = DI::config()->get("system", "post_update_version_1349_id", ''); + $id = DI::config()->get('system', 'post_update_version_1349_id', ''); Logger::info('Start', ['apcontact' => $id]); @@ -688,12 +688,12 @@ class PostUpdate } DBA::close($apcontacts); - DI::config()->set("system", "post_update_version_1349_id", $id); + DI::config()->set('system', 'post_update_version_1349_id', $id); Logger::info('Processed', ['rows' => $rows, 'last' => $id]); if ($start_id == $id) { - DI::config()->set("system", "post_update_version", 1349); + DI::config()->set('system', 'post_update_version', 1349); Logger::info('Done'); return true; } @@ -711,7 +711,7 @@ class PostUpdate private static function update1383() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1383) { + if (DI::config()->get('system', 'post_update_version') >= 1383) { return true; } @@ -737,7 +737,7 @@ class PostUpdate } DBA::close($photos); - DI::config()->set("system", "post_update_version", 1383); + DI::config()->set('system', 'post_update_version', 1383); Logger::info('Done', ['deleted' => $deleted]); return true; } @@ -752,7 +752,7 @@ class PostUpdate private static function update1384() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1384) { + if (DI::config()->get('system', 'post_update_version') >= 1384) { return true; } @@ -782,7 +782,7 @@ class PostUpdate Logger::info('Processed', ['rows' => $rows]); if ($rows <= 100) { - DI::config()->set("system", "post_update_version", 1384); + DI::config()->set('system', 'post_update_version', 1384); Logger::info('Done'); return true; } @@ -800,12 +800,12 @@ class PostUpdate private static function update1400() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1400) { + if (DI::config()->get('system', 'post_update_version') >= 1400) { return true; } if (!DBStructure::existsTable('item')) { - DI::config()->set("system", "post_update_version", 1400); + DI::config()->set('system', 'post_update_version', 1400); return true; } @@ -829,7 +829,7 @@ class PostUpdate Logger::info('Processed', ['rows' => $rows]); if ($rows <= 100) { - DI::config()->set("system", "post_update_version", 1400); + DI::config()->set('system', 'post_update_version', 1400); Logger::info('Done'); return true; } @@ -847,7 +847,7 @@ class PostUpdate private static function update1424() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1424) { + if (DI::config()->get('system', 'post_update_version') >= 1424) { return true; } @@ -871,7 +871,7 @@ class PostUpdate Logger::info('Processed', ['rows' => $rows]); if ($rows <= 100) { - DI::config()->set("system", "post_update_version", 1424); + DI::config()->set('system', 'post_update_version', 1424); Logger::info('Done'); return true; } @@ -889,7 +889,7 @@ class PostUpdate private static function update1425() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1425) { + if (DI::config()->get('system', 'post_update_version') >= 1425) { return true; } @@ -918,7 +918,7 @@ class PostUpdate Logger::info('Processed', ['rows' => $rows]); if ($rows <= 100) { - DI::config()->set("system", "post_update_version", 1425); + DI::config()->set('system', 'post_update_version', 1425); Logger::info('Done'); return true; } @@ -936,7 +936,7 @@ class PostUpdate private static function update1426() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1426) { + if (DI::config()->get('system', 'post_update_version') >= 1426) { return true; } @@ -965,7 +965,7 @@ class PostUpdate Logger::info('Processed', ['rows' => $rows]); if ($rows <= 100) { - DI::config()->set("system", "post_update_version", 1426); + DI::config()->set('system', 'post_update_version', 1426); Logger::info('Done'); return true; } @@ -983,7 +983,7 @@ class PostUpdate private static function update1427() { // Was the script completed? - if (DI::config()->get("system", "post_update_version") >= 1427) { + if (DI::config()->get('system', 'post_update_version') >= 1427) { return true; } @@ -1012,7 +1012,7 @@ class PostUpdate Logger::info('Processed', ['rows' => $rows]); if ($rows <= 100) { - DI::config()->set("system", "post_update_version", 1427); + DI::config()->set('system', 'post_update_version', 1427); Logger::info('Done'); return true; } diff --git a/src/Database/View.php b/src/Database/View.php index a31151c211..d64e544cc0 100644 --- a/src/Database/View.php +++ b/src/Database/View.php @@ -21,136 +21,44 @@ namespace Friendica\Database; -use Exception; -use Friendica\Core\Hook; use Friendica\DI; +use Friendica\Util\Writer\ViewDefinitionSqlWriter; class View { /** - * view definition loaded from static/dbview.config.php + * Creates a view * - * @var array + * @param bool $verbose Whether to show SQL statements + * @param bool $action Whether to execute SQL statements + * @return void */ - private static $definition = []; - - /** - * Loads the database structure definition from the static/dbview.config.php file. - * On first pass, defines DB_UPDATE_VERSION constant. - * - * @see static/dbview.config.php - * @param boolean $with_addons_structure Whether to tack on addons additional tables - * @param string $basePath The base path of this application - * @return array - * @throws Exception - */ - public static function definition($basePath = '', $with_addons_structure = true) - { - if (!self::$definition) { - if (empty($basePath)) { - $basePath = DI::app()->getBasePath(); - } - - $filename = $basePath . '/static/dbview.config.php'; - - if (!is_readable($filename)) { - throw new Exception('Missing database view config file static/dbview.config.php'); - } - - $definition = require $filename; - - if (!$definition) { - throw new Exception('Corrupted database view config file static/dbview.config.php'); - } - - self::$definition = $definition; - } else { - $definition = self::$definition; - } - - if ($with_addons_structure) { - Hook::callAll('dbview_definition', $definition); - } - - return $definition; - } - public static function create(bool $verbose, bool $action) { // Delete previously used views that aren't used anymore - foreach(['post-view', 'post-thread-view'] as $view) { + foreach (['post-view', 'post-thread-view'] as $view) { if (self::isView($view)) { $sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($view)); if (!empty($sql) && $verbose) { echo $sql . ";\n"; } - + if (!empty($sql) && $action) { DBA::e($sql); } } } - $definition = self::definition(); + $definition = DI::viewDefinition()->getAll(); foreach ($definition as $name => $structure) { - self::createview($name, $structure, $verbose, $action); - } - } - - public static function printStructure($basePath) - { - $database = self::definition($basePath, false); - - foreach ($database as $name => $structure) { - echo "--\n"; - echo "-- VIEW $name\n"; - echo "--\n"; - self::createView($name, $structure, true, false); - - echo "\n"; - } - } - - private static function createview($name, $structure, $verbose, $action) - { - $r = true; - - $sql_rows = []; - foreach ($structure["fields"] as $fieldname => $origin) { - if (is_string($origin)) { - $sql_rows[] = $origin . " AS `" . DBA::escape($fieldname) . "`"; - } elseif (is_array($origin) && (sizeof($origin) == 2)) { - $sql_rows[] = "`" . DBA::escape($origin[0]) . "`.`" . DBA::escape($origin[1]) . "` AS `" . DBA::escape($fieldname) . "`"; + if (self::isView($name)) { + DBA::e(sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($name))); + } elseif (self::isTable($name)) { + DBA::e(sprintf("DROP TABLE IF EXISTS `%s`", DBA::escape($name))); } + DBA::e(ViewDefinitionSqlWriter::createView($name, $structure)); } - - if (self::isView($name)) { - $sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($name)); - } elseif (self::isTable($name)) { - $sql = sprintf("DROP TABLE IF EXISTS `%s`", DBA::escape($name)); - } - - if (!empty($sql) && $verbose) { - echo $sql . ";\n"; - } - - if (!empty($sql) && $action) { - DBA::e($sql); - } - - $sql = sprintf("CREATE VIEW `%s` AS SELECT \n\t", DBA::escape($name)) . - implode(",\n\t", $sql_rows) . "\n\t" . $structure['query']; - - if ($verbose) { - echo $sql . ";\n"; - } - - if ($action) { - $r = DBA::e($sql); - } - - return $r; } /** @@ -159,9 +67,9 @@ class View * @param string $view * @return boolean "true" if it's a view */ - private static function isView(string $view) + private static function isView(string $view): bool { - $status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_TYPE'], + $status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES', ['TABLE_TYPE'], ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $view]); if (empty($status['TABLE_TYPE'])) { @@ -177,9 +85,9 @@ class View * @param string $table * @return boolean "true" if it's a table */ - private static function isTable(string $table) + private static function isTable(string $table): bool { - $status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_TYPE'], + $status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES', ['TABLE_TYPE'], ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $table]); if (empty($status['TABLE_TYPE'])) { diff --git a/src/Factory/Api/Mastodon/Account.php b/src/Factory/Api/Mastodon/Account.php index d0c654fc21..a3555302d6 100644 --- a/src/Factory/Api/Mastodon/Account.php +++ b/src/Factory/Api/Mastodon/Account.php @@ -57,12 +57,17 @@ class Account extends BaseFactory * @throws HTTPException\InternalServerErrorException * @throws ImagickException|HTTPException\NotFoundException */ - public function createFromContactId(int $contactId, $uid = 0): \Friendica\Object\Api\Mastodon\Account + public function createFromContactId(int $contactId, int $uid = 0): \Friendica\Object\Api\Mastodon\Account { $contact = Contact::getById($contactId, ['uri-id']); + if (empty($contact)) { throw new HTTPException\NotFoundException('Contact ' . $contactId . ' not found'); } + if (empty($contact['uri-id'])) { + throw new HTTPException\NotFoundException('Contact ' . $contactId . ' has no uri-id set'); + } + return self::createFromUriId($contact['uri-id'], $uid); } @@ -74,7 +79,7 @@ class Account extends BaseFactory * @throws HTTPException\InternalServerErrorException * @throws ImagickException|HTTPException\NotFoundException */ - public function createFromUriId(int $contactUriId, $uid = 0): \Friendica\Object\Api\Mastodon\Account + public function createFromUriId(int $contactUriId, int $uid = 0): \Friendica\Object\Api\Mastodon\Account { $account = DBA::selectFirst('account-user-view', [], ['uri-id' => $contactUriId, 'uid' => [0, $uid]], ['order' => ['id' => true]]); if (empty($account)) { diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 5d58944150..0fc9281dbe 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -190,7 +190,7 @@ class Status extends BaseFactory */ public function createFromMailId(int $id): \Friendica\Object\Api\Mastodon\Status { - $item = ActivityPub\Transmitter::ItemArrayFromMail($id, true); + $item = ActivityPub\Transmitter::getItemArrayFromMail($id, true); if (empty($item)) { $this->mstdnErrorFactory->RecordNotFound(); } diff --git a/src/Factory/Api/Twitter/Status.php b/src/Factory/Api/Twitter/Status.php index ed138e2bdb..123fd3dcf0 100644 --- a/src/Factory/Api/Twitter/Status.php +++ b/src/Factory/Api/Twitter/Status.php @@ -70,6 +70,7 @@ class Status extends BaseFactory /** * @param int $uriId Uri-ID of the item * @param int $uid Item user + * @param bool $include_entities Whether to include entities * * @return \Friendica\Object\Api\Twitter\Status * @throws HTTPException\InternalServerErrorException @@ -90,12 +91,13 @@ class Status extends BaseFactory /** * @param int $uriId Uri-ID of the item * @param int $uid Item user + * @param bool $include_entities Whether to include entities * * @return \Friendica\Object\Api\Twitter\Status * @throws HTTPException\InternalServerErrorException * @throws ImagickException|HTTPException\NotFoundException */ - public function createFromUriId(int $uriId, $uid = 0, $include_entities = false): \Friendica\Object\Api\Twitter\Status + public function createFromUriId(int $uriId, int $uid = 0, bool $include_entities = false): \Friendica\Object\Api\Twitter\Status { $fields = ['parent-uri-id', 'uri-id', 'uid', 'author-id', 'author-link', 'author-network', 'owner-id', 'causer-id', 'starred', 'app', 'title', 'body', 'raw-body', 'created', 'network','post-reason', 'language', 'gravity', @@ -110,6 +112,7 @@ class Status extends BaseFactory /** * @param array $item item array * @param int $uid Item user + * @param bool $include_entities Whether to include entities * * @return \Friendica\Object\Api\Twitter\Status * @throws HTTPException\InternalServerErrorException diff --git a/src/Factory/Api/Twitter/User.php b/src/Factory/Api/Twitter/User.php index 6dd19ede3a..f7040cefa9 100644 --- a/src/Factory/Api/Twitter/User.php +++ b/src/Factory/Api/Twitter/User.php @@ -51,7 +51,7 @@ class User extends BaseFactory * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public function createFromContactId(int $contactId, $uid = 0, $skip_status = true, $include_user_entities = true) + public function createFromContactId(int $contactId, int $uid = 0, bool $skip_status = true, bool $include_user_entities = true) { $cdata = Contact::getPublicAndUserContactID($contactId, $uid); if (!empty($cdata)) { @@ -78,7 +78,7 @@ class User extends BaseFactory return new \Friendica\Object\Api\Twitter\User($publicContact, $apcontact, $userContact, $status, $include_user_entities); } - public function createFromUserId(int $uid, $skip_status = true, $include_user_entities = true) + public function createFromUserId(int $uid, bool $skip_status = true, bool $include_user_entities = true) { return $this->createFromContactId(Contact::getPublicIdByUserId($uid), $uid, $skip_status, $include_user_entities); } diff --git a/src/LegacyModule.php b/src/LegacyModule.php index 22d393ef9e..7d9cf20283 100644 --- a/src/LegacyModule.php +++ b/src/LegacyModule.php @@ -57,7 +57,7 @@ class LegacyModule extends BaseModule * @param string $file_path * @throws \Exception */ - private function setModuleFile($file_path) + private function setModuleFile(string $file_path) { if (!is_readable($file_path)) { throw new \Exception(DI::l10n()->t('Legacy module file not found: %s', $file_path)); @@ -87,7 +87,7 @@ class LegacyModule extends BaseModule * @return string * @throws \Exception */ - private function runModuleFunction(string $function_suffix) + private function runModuleFunction(string $function_suffix): string { $function_name = $this->moduleName . '_' . $function_suffix; diff --git a/src/Model/APContact.php b/src/Model/APContact.php index 5363ab6e25..baa364e940 100644 --- a/src/Model/APContact.php +++ b/src/Model/APContact.php @@ -48,7 +48,7 @@ class APContact * @param string $addr Address * @return array webfinger data */ - private static function fetchWebfingerData(string $addr) + private static function fetchWebfingerData(string $addr): array { $addr_parts = explode('@', $addr); if (count($addr_parts) != 2) { @@ -116,15 +116,16 @@ class APContact * @return array profile array * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException + * @todo Rewrite parameter $update to avoid true|false|null (boolean is binary, null adds a third case) */ - public static function getByURL($url, $update = null) + public static function getByURL(string $url, $update = null): array { if (empty($url) || Network::isUrlBlocked($url)) { Logger::info('Domain is blocked', ['url' => $url]); return []; } - $fetched_contact = false; + $fetched_contact = []; if (empty($update)) { if (is_null($update)) { @@ -222,14 +223,14 @@ class APContact $apcontact['type'] = str_replace('as:', '', JsonLD::fetchElement($compacted, '@type')); $apcontact['following'] = JsonLD::fetchElement($compacted, 'as:following', '@id'); $apcontact['followers'] = JsonLD::fetchElement($compacted, 'as:followers', '@id'); - $apcontact['inbox'] = JsonLD::fetchElement($compacted, 'ldp:inbox', '@id'); + $apcontact['inbox'] = (JsonLD::fetchElement($compacted, 'ldp:inbox', '@id') ?? ''); self::unarchiveInbox($apcontact['inbox'], false); $apcontact['outbox'] = JsonLD::fetchElement($compacted, 'as:outbox', '@id'); $apcontact['sharedinbox'] = ''; if (!empty($compacted['as:endpoints'])) { - $apcontact['sharedinbox'] = JsonLD::fetchElement($compacted['as:endpoints'], 'as:sharedInbox', '@id'); + $apcontact['sharedinbox'] = (JsonLD::fetchElement($compacted['as:endpoints'], 'as:sharedInbox', '@id') ?? ''); self::unarchiveInbox($apcontact['sharedinbox'], true); } @@ -243,9 +244,10 @@ class APContact $apcontact['name'] = $apcontact['nick']; } - $apcontact['about'] = HTML::toBBCode(JsonLD::fetchElement($compacted, 'as:summary', '@value')); + $apcontact['about'] = HTML::toBBCode(JsonLD::fetchElement($compacted, 'as:summary', '@value') ?? ''); $ims = JsonLD::fetchElementArray($compacted, 'vcard:hasInstantMessage'); + if (!empty($ims)) { foreach ($ims as $link) { if (substr($link, 0, 5) == 'xmpp:') { @@ -466,7 +468,7 @@ class APContact } // Limit the length on incoming fields - $apcontact = DBStructure::getFieldsForTable('apcontact', $apcontact); + $apcontact = DI::dbaDefinition()->truncateFieldsForTable('apcontact', $apcontact); if (DBA::exists('apcontact', ['url' => $apcontact['url']])) { DBA::update('apcontact', $apcontact, ['url' => $apcontact['url']]); @@ -527,8 +529,9 @@ class APContact * * @param string $url inbox url * @param boolean $shared Shared Inbox + * @return void */ - private static function unarchiveInbox($url, $shared) + private static function unarchiveInbox(string $url, bool $shared) { if (empty($url)) { return; diff --git a/src/Model/Attach.php b/src/Model/Attach.php index 9009126868..55ab81a8ae 100644 --- a/src/Model/Attach.php +++ b/src/Model/Attach.php @@ -23,7 +23,6 @@ namespace Friendica\Model; use Friendica\Core\System; use Friendica\Database\DBA; -use Friendica\Database\DBStructure; use Friendica\DI; use Friendica\Core\Storage\Exception\InvalidClassStorageException; use Friendica\Core\Storage\Exception\ReferenceStorageException; @@ -44,9 +43,9 @@ class Attach * @return array field list * @throws \Exception */ - private static function getFields() + private static function getFields(): array { - $allfields = DBStructure::definition(DI::app()->getBasePath(), false); + $allfields = DI::dbaDefinition()->getAll(); $fields = array_keys($allfields['attach']['fields']); array_splice($fields, array_search('data', $fields), 1); return $fields; @@ -59,7 +58,7 @@ class Attach * @param array $conditions Array of fields for conditions * @param array $params Array of several parameters * - * @return array + * @return array|bool * * @throws \Exception * @see \Friendica\Database\DBA::selectToArray @@ -102,7 +101,7 @@ class Attach * @return boolean * @throws \Exception */ - public static function exists(array $conditions) + public static function exists(array $conditions): bool { return DBA::exists('attach', $conditions); } @@ -117,7 +116,7 @@ class Attach * @throws \Exception * @see \Friendica\Database\DBA::select */ - public static function getById($id) + public static function getById(int $id) { return self::selectFirst([], ['id' => $id]); } @@ -132,7 +131,7 @@ class Attach * @throws \Exception * @see \Friendica\Database\DBA::select */ - public static function getByIdWithPermission($id) + public static function getByIdWithPermission(int $id) { $r = self::selectFirst(['uid'], ['id' => $id]); if ($r === false) { @@ -156,10 +155,10 @@ class Attach * * @param array $item Attachment data. Needs at least 'id', 'backend-class', 'backend-ref' * - * @return string file data + * @return string|null file data or null on failure * @throws \Exception */ - public static function getData($item) + public static function getData(array $item) { if (!empty($item['data'])) { return $item['data']; @@ -195,10 +194,10 @@ class Attach * @param string $deny_cid Permissions, denied contacts.optional, default = '' * @param string $deny_gid Permissions, denied greoup.optional, default = '' * - * @return boolean/integer Row id on success, False on errors + * @return boolean|integer Row id on success, False on errors * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function store($data, $uid, $filename, $filetype = '' , $filesize = null, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') + public static function store(string $data, int $uid, string $filename, string $filetype = '' , int $filesize = null, string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '') { if ($filetype === '') { $filetype = Mimetype::getContentType($filename); @@ -241,17 +240,17 @@ class Attach /** * Store new file metadata in db and binary in default backend from existing file * - * @param $src - * @param $uid - * @param string $filename + * @param string $src Source file name + * @param int $uid User id + * @param string $filename Optional file name * @param string $allow_cid * @param string $allow_gid * @param string $deny_cid * @param string $deny_gid - * @return boolean True on success + * @return boolean|int Insert id or false on failure * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function storeFile($src, $uid, $filename = '', $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') + public static function storeFile(string $src, int $uid, string $filename = '', string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '') { if ($filename === '') { $filename = basename($src); @@ -276,7 +275,7 @@ class Attach * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @see \Friendica\Database\DBA::update */ - public static function update($fields, $conditions, Image $img = null, array $old_fields = []) + public static function update(array $fields, array $conditions, Image $img = null, array $old_fields = []): bool { if (!is_null($img)) { // get items to update @@ -311,7 +310,7 @@ class Attach * @throws \Exception * @see \Friendica\Database\DBA::delete */ - public static function delete(array $conditions, array $options = []) + public static function delete(array $conditions, array $options = []): bool { // get items to delete data info $items = self::selectToArray(['backend-class','backend-ref'], $conditions); diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 3ed2785cfa..5d1e92f4bc 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -119,7 +119,7 @@ class Contact * @return array * @throws \Exception */ - public static function selectToArray(array $fields = [], array $condition = [], array $params = []) + public static function selectToArray(array $fields = [], array $condition = [], array $params = []): array { return DBA::selectToArray('contact', $fields, $condition, $params); } @@ -128,7 +128,7 @@ class Contact * @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 - * @return array + * @return array|bool * @throws \Exception */ public static function selectFirst(array $fields = [], array $condition = [], array $params = []) @@ -148,7 +148,7 @@ class Contact * @return int id of the created contact * @throws \Exception */ - public static function insert(array $fields, int $duplicate_mode = Database::INSERT_DEFAULT) + public static function insert(array $fields, int $duplicate_mode = Database::INSERT_DEFAULT): int { if (!empty($fields['baseurl']) && empty($fields['gsid'])) { $fields['gsid'] = GServer::getID($fields['baseurl'], true); @@ -187,6 +187,7 @@ class Contact * * @return boolean was the update successfull? * @throws \Exception + * @todo Let's get rid of boolean type of $old_fields */ public static function update(array $fields, array $condition, $old_fields = []) { @@ -204,7 +205,7 @@ class Contact * @return array|boolean Contact record if it exists, false otherwise * @throws \Exception */ - public static function getById($id, $fields = []) + public static function getById(int $id, array $fields = []) { return DBA::selectFirst('contact', $fields, ['id' => $id]); } @@ -217,7 +218,7 @@ class Contact * @return array|boolean Contact record if it exists, false otherwise * @throws \Exception */ - public static function getByUriId($uri_id, $fields = []) + public static function getByUriId(int $uri_id, array $fields = []) { return DBA::selectFirst('contact', $fields, ['uri-id' => $uri_id], ['order' => ['uid']]); } @@ -231,7 +232,7 @@ class Contact * @param integer $uid User ID of the contact * @return array contact array */ - public static function getByURL(string $url, $update = null, array $fields = [], int $uid = 0) + public static function getByURL(string $url, $update = null, array $fields = [], int $uid = 0): array { if ($update || is_null($update)) { $cid = self::getIdForURL($url, $uid, $update); @@ -302,7 +303,7 @@ class Contact * @param array $fields Field list * @return array contact array */ - public static function getByURLForUser(string $url, int $uid = 0, $update = false, array $fields = []) + public static function getByURLForUser(string $url, int $uid = 0, $update = false, array $fields = []): array { if ($uid != 0) { $contact = self::getByURL($url, $update, $fields, $uid); @@ -333,7 +334,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isFollower($cid, $uid) + public static function isFollower(int $cid, int $uid): bool { if (Contact\User::isBlocked($cid, $uid)) { return false; @@ -358,7 +359,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isFollowerByURL($url, $uid) + public static function isFollowerByURL(string $url, uid $uid): bool { $cid = self::getIdForURL($url, $uid); @@ -370,16 +371,16 @@ class Contact } /** - * Tests if the given user follow the given contact + * Tests if the given user shares with the given contact * * @param int $cid Either public contact id or user's contact id * @param int $uid User ID * - * @return boolean is the contact url being followed? + * @return boolean is the contact sharing with given user? * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isSharing($cid, $uid) + public static function isSharing(int $cid, int $uid): bool { if (Contact\User::isBlocked($cid, $uid)) { return false; @@ -404,7 +405,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isSharingByURL($url, $uid) + public static function isSharingByURL(string $url, int $uid): bool { $cid = self::getIdForURL($url, $uid); @@ -425,7 +426,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getBasepath($url, $dont_update = false) + public static function getBasepath(string $url, bool $dont_update = false): string { $contact = DBA::selectFirst('contact', ['id', 'baseurl'], ['uid' => 0, 'nurl' => Strings::normaliseLink($url)]); if (!DBA::isResult($contact)) { @@ -459,7 +460,7 @@ class Contact * * @return boolean Is it the same server? */ - public static function isLocal($url) + public static function isLocal(string $url): bool { if (!parse_url($url, PHP_URL_SCHEME)) { $addr_parts = explode('@', $url); @@ -473,10 +474,9 @@ class Contact * Check if the given contact ID is on the same server * * @param string $url The contact link - * * @return boolean Is it the same server? */ - public static function isLocalById(int $cid) + public static function isLocalById(int $cid): bool { $contact = DBA::selectFirst('contact', ['url', 'baseurl'], ['id' => $cid]); if (!DBA::isResult($contact)) { @@ -500,7 +500,7 @@ class Contact * @return integer|boolean Public contact id for given user id * @throws \Exception */ - public static function getPublicIdByUserId($uid) + public static function getPublicIdByUserId(int $uid) { $self = DBA::selectFirst('contact', ['url'], ['self' => true, 'uid' => $uid]); if (!DBA::isResult($self)) { @@ -519,7 +519,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getPublicAndUserContactID($cid, $uid) + public static function getPublicAndUserContactID(int $cid, int $uid): array { // We have to use the legacy function as long as the post update hasn't finished if (DI::config()->get('system', 'post_update_version') < 1427) { @@ -555,12 +555,11 @@ class Contact * * @param int $cid Either public contact id or user's contact id * @param int $uid User ID - * * @return array with public and user's contact id * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function legacyGetPublicAndUserContactID($cid, $uid) + private static function legacyGetPublicAndUserContactID(int $cid, int $uid): array { if (empty($uid) || empty($cid)) { return []; @@ -596,12 +595,11 @@ class Contact * @param int $cid A contact ID * @param int $uid The User ID * @param array $fields The selected fields for the contact - * * @return array The contact details * * @throws \Exception */ - public static function getContactForUser($cid, $uid, array $fields = []) + public static function getContactForUser(int $cid, int $uid, array $fields = []): array { $contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => $uid]); @@ -619,7 +617,7 @@ class Contact * @return bool Operation success * @throws HTTPException\InternalServerErrorException */ - public static function createSelfFromUserId($uid) + public static function createSelfFromUserId(int $uid): bool { $user = DBA::selectFirst('user', ['uid', 'username', 'nickname', 'pubkey', 'prvkey'], ['uid' => $uid, 'account_expired' => false]); @@ -676,12 +674,12 @@ class Contact /** * Updates the self-contact for the provided user id * - * @param int $uid - * @param boolean $update_avatar Force the avatar update - * @return bool "true" if updated + * @param int $uid + * @param bool $update_avatar Force the avatar update + * @return bool "true" if updated * @throws HTTPException\InternalServerErrorException */ - public static function updateSelfFromUserID($uid, $update_avatar = false) + 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', 'xmpp', 'matrix', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl', 'unsearchable', @@ -794,9 +792,10 @@ class Contact * Marks a contact for removal * * @param int $id contact id + * @return void * @throws HTTPException\InternalServerErrorException */ - public static function remove($id) + public static function remove(int $id) { // We want just to make sure that we don't delete our "self" contact $contact = DBA::selectFirst('contact', ['uri-id', 'photo', 'thumb', 'micro', 'uid'], ['id' => $id, 'self' => false]); @@ -821,6 +820,7 @@ class Contact * Unfollow the remote contact * * @param array $contact Target user-specific contact (uid != 0) array + * @return void * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ @@ -850,6 +850,7 @@ class Contact * The local relationship is updated immediately, the eventual remote server is messaged in the background. * * @param array $contact User-specific contact array (uid != 0) to revoke the follow from + * @return void * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ @@ -877,6 +878,7 @@ class Contact * Completely severs a relationship with a contact * * @param array $contact User-specific contact (uid != 0) array + * @return void * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ @@ -924,7 +926,7 @@ class Contact * up or some other transient event and that there's a possibility we could recover from it. * * @param array $contact contact to mark for archival - * @return null + * @return void * @throws HTTPException\InternalServerErrorException */ public static function markForArchival(array $contact) @@ -977,7 +979,7 @@ class Contact * @see Contact::markForArchival() * * @param array $contact contact to be unmarked for archival - * @return null + * @return void * @throws \Exception */ public static function unmarkForArchival(array $contact) @@ -1024,7 +1026,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function photoMenu(array $contact, $uid = 0) + public static function photoMenu(array $contact, int $uid = 0): array { $pm_url = ''; $status_link = ''; @@ -1167,7 +1169,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getIdForURL($url, $uid = 0, $update = null, $default = []) + public static function getIdForURL(string $url, int $uid = 0, $update = null, array $default = []): int { $contact_id = 0; @@ -1179,7 +1181,7 @@ class Contact $contact = self::getByURL($url, false, ['id', 'network', 'uri-id'], $uid); if (!empty($contact)) { - $contact_id = $contact["id"]; + $contact_id = $contact['id']; if (empty($update) && (!empty($contact['uri-id']) || is_bool($update))) { Logger::debug('Contact found', ['url' => $url, 'uid' => $uid, 'update' => $update, 'cid' => $contact_id]); @@ -1196,10 +1198,10 @@ class Contact $data = []; if (empty($default['network']) || $update) { - $data = Probe::uri($url, "", $uid); + $data = Probe::uri($url, '', $uid); // Take the default values when probing failed - if (!empty($default) && !in_array($data["network"], array_merge(Protocol::NATIVE_SUPPORT, [Protocol::PUMPIO]))) { + if (!empty($default) && !in_array($data['network'], array_merge(Protocol::NATIVE_SUPPORT, [Protocol::PUMPIO]))) { $data = array_merge($data, $default); } } elseif (!empty($default['network'])) { @@ -1311,7 +1313,7 @@ class Contact * @return boolean Is the contact archived? * @throws HTTPException\InternalServerErrorException */ - public static function isArchived(int $cid) + public static function isArchived(int $cid): bool { if ($cid == 0) { return false; @@ -1351,11 +1353,10 @@ class Contact * Checks if the contact is blocked * * @param int $cid contact id - * * @return boolean Is the contact blocked? * @throws HTTPException\InternalServerErrorException */ - public static function isBlocked($cid) + public static function isBlocked(int $cid): bool { if ($cid == 0) { return false; @@ -1377,11 +1378,10 @@ class Contact * Checks if the contact is hidden * * @param int $cid contact id - * * @return boolean Is the contact hidden? * @throws \Exception */ - public static function isHidden($cid) + public static function isHidden(int $cid): bool { if ($cid == 0) { return false; @@ -1405,7 +1405,7 @@ class Contact * @return string posts in HTML * @throws \Exception */ - public static function getPostsFromUrl($contact_url, $thread_mode = false, $update = 0, $parent = 0, bool $only_media = false) + public static function getPostsFromUrl(string $contact_url, bool $thread_mode = false, int $update = 0, int $parent = 0, bool $only_media = false): string { return self::getPostsFromId(self::getIdForURL($contact_url), $thread_mode, $update, $parent, $only_media); } @@ -1421,7 +1421,7 @@ class Contact * @return string posts in HTML * @throws \Exception */ - public static function getPostsFromId($cid, $thread_mode = false, $update = 0, $parent = 0, bool $only_media = false) + public static function getPostsFromId(int $cid, bool $thread_mode = false, int $update = 0, int $parent = 0, bool $only_media = false): string { $contact = DBA::selectFirst('contact', ['contact-type', 'network'], ['id' => $cid]); if (!DBA::isResult($contact)) { @@ -1526,7 +1526,7 @@ class Contact * @param int $type type of contact or account * @return string */ - public static function getAccountType(int $type) + public static function getAccountType(int $type): string { switch ($type) { case self::TYPE_ORGANISATION: @@ -1552,11 +1552,11 @@ class Contact /** * Blocks a contact * - * @param int $cid - * @return bool - * @throws \Exception + * @param int $cid Contact id to block + * @param string $reason Block reason + * @return bool Whether it was successful */ - public static function block($cid, $reason = null) + public static function block(int $cid, string $reason = null): bool { $return = self::update(['blocked' => true, 'block_reason' => $reason], ['id' => $cid]); @@ -1566,11 +1566,10 @@ class Contact /** * Unblocks a contact * - * @param int $cid - * @return bool - * @throws \Exception + * @param int $cid Contact id to unblock + * @return bool Whether it was successfull */ - public static function unblock($cid) + public static function unblock(int $cid): bool { $return = self::update(['blocked' => false, 'block_reason' => null], ['id' => $cid]); @@ -1580,7 +1579,7 @@ class Contact /** * Ensure that cached avatar exist * - * @param integer $cid + * @param integer $cid Contact id */ public static function checkAvatarCache(int $cid) { @@ -1620,7 +1619,7 @@ class Contact * @param bool $no_update Don't perfom an update if no cached avatar was found * @return string photo path */ - private static function getAvatarPath(array $contact, string $size, $no_update = false) + private static function getAvatarPath(array $contact, string $size, bool $no_update = false): string { $contact = self::checkAvatarCacheByArray($contact, $no_update); @@ -1654,7 +1653,7 @@ class Contact * @param bool $no_update Don't perfom an update if no cached avatar was found * @return string photo path */ - public static function getPhoto(array $contact, bool $no_update = false) + public static function getPhoto(array $contact, bool $no_update = false): string { return self::getAvatarPath($contact, Proxy::SIZE_SMALL, $no_update); } @@ -1666,7 +1665,7 @@ class Contact * @param bool $no_update Don't perfom an update if no cached avatar was found * @return string photo path */ - public static function getThumb(array $contact, bool $no_update = false) + public static function getThumb(array $contact, bool $no_update = false): string { return self::getAvatarPath($contact, Proxy::SIZE_THUMB, $no_update); } @@ -1678,7 +1677,7 @@ class Contact * @param bool $no_update Don't perfom an update if no cached avatar was found * @return string photo path */ - public static function getMicro(array $contact, bool $no_update = false) + public static function getMicro(array $contact, bool $no_update = false): string { return self::getAvatarPath($contact, Proxy::SIZE_MICRO, $no_update); } @@ -1690,7 +1689,7 @@ class Contact * @param bool $no_update Don't perfom an update if no cached avatar was found * @return array contact array with avatar cache fields */ - private static function checkAvatarCacheByArray(array $contact, bool $no_update = false) + private static function checkAvatarCacheByArray(array $contact, bool $no_update = false): array { $update = false; $contact_fields = []; @@ -1796,7 +1795,7 @@ class Contact * @param string $size Size of the avatar picture * @return string avatar URL */ - public static function getDefaultAvatar(array $contact, string $size) + public static function getDefaultAvatar(array $contact, string $size): string { switch ($size) { case Proxy::SIZE_MICRO: @@ -1958,7 +1957,7 @@ class Contact * @param string $updated Contact update date * @return string avatar link */ - public static function getAvatarUrlForId(int $cid, string $size = '', string $updated = '', string $guid = ''):string + public static function getAvatarUrlForId(int $cid, string $size = '', string $updated = '', string $guid = ''): string { // We have to fetch the "updated" variable when it wasn't provided // The parameter can be provided to improve performance @@ -1999,7 +1998,7 @@ class Contact * @param string $size One of the Proxy::SIZE_* constants * @return string avatar link */ - public static function getAvatarUrlForUrl(string $url, int $uid, string $size = ''):string + 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]; @@ -2015,7 +2014,7 @@ class Contact * @param string $updated Contact update date * @return string header link */ - public static function getHeaderUrlForId(int $cid, string $size = '', string $updated = '', string $guid = ''):string + public static function getHeaderUrlForId(int $cid, string $size = '', string $updated = '', string $guid = ''): string { // We have to fetch the "updated" variable when it wasn't provided // The parameter can be provided to improve performance @@ -2312,6 +2311,8 @@ class Contact } /** + * Updates contact record by provided id and optional network + * * @param integer $id contact id * @param string $network Optional network we are probing for * @return boolean @@ -2335,13 +2336,15 @@ class Contact } /** + * Updates contact record by provided id and probed data + * * @param integer $id contact id * @param array $ret Probed data * @return boolean * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function updateFromProbeArray(int $id, array $ret) + private static function updateFromProbeArray(int $id, array $ret): bool { /* Warning: Never ever fetch the public key via Probe::uri and write it into the contacts. @@ -2552,12 +2555,14 @@ class Contact } /** + * Updates contact record by provided URL + * * @param integer $url contact url * @return integer Contact id * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function updateFromProbeByURL($url) + public static function updateFromProbeByURL(string $url): int { $id = self::getIdForURL($url); @@ -2578,7 +2583,7 @@ class Contact * @param string $network Network of that contact * @return string with protocol */ - public static function getProtocol($url, $network) + public static function getProtocol(string $url, string $network): string { if ($network != Protocol::DFRN) { return $network; @@ -2614,7 +2619,7 @@ class Contact * @throws HTTPException\NotFoundException * @throws \ImagickException */ - public static function createFromProbeForUser(int $uid, $url, $network = '') + public static function createFromProbeForUser(int $uid, string $url, string $network = ''): array { $result = ['cid' => -1, 'success' => false, 'message' => '']; @@ -2803,7 +2808,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function addRelationship(array $importer, array $contact, array $datarray, $sharing = false, $note = '') + public static function addRelationship(array $importer, array $contact, array $datarray, bool $sharing = false, string $note = '') { // Should always be set if (empty($datarray['author-id'])) { @@ -2945,6 +2950,7 @@ class Contact * Update the local relationship when a local user loses a follower * * @param array $contact User-specific contact (uid != 0) array + * @return void * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ @@ -3030,7 +3036,7 @@ class Contact * @return array * @throws \Exception */ - public static function pruneUnavailable(array $contact_ids) + public static function pruneUnavailable(array $contact_ids): array { if (empty($contact_ids)) { return []; @@ -3058,7 +3064,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function magicLink($contact_url, $url = '') + public static function magicLink(string $contact_url, string $url = ''): string { if (!Session::isAuthenticated()) { return $url ?: $contact_url; // Equivalent to: ($url != '') ? $url : $contact_url; @@ -3085,7 +3091,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function magicLinkById($cid, $url = '') + public static function magicLinkById(int $cid, string $url = ''): string { $contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'uid'], ['id' => $cid]); @@ -3102,7 +3108,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function magicLinkByContact($contact, $url = '') + public static function magicLinkByContact(array $contact, string $url = ''): string { $destination = $url ?: $contact['url']; // Equivalent to ($url != '') ? $url : $contact['url']; @@ -3143,7 +3149,7 @@ class Contact * * @return boolean "true" if it is a forum */ - public static function isForum($contactid) + public static function isForum(int $contactid): bool { $fields = ['contact-type']; $condition = ['id' => $contactid]; @@ -3162,7 +3168,7 @@ class Contact * @param array $contact * @return bool */ - public static function canReceivePrivateMessages(array $contact) + public static function canReceivePrivateMessages(array $contact): bool { $protocol = $contact['network'] ?? $contact['protocol'] ?? Protocol::PHANTOM; $self = $contact['self'] ?? false; @@ -3180,7 +3186,7 @@ class Contact * @return array with search results * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function searchByName(string $search, string $mode = '', int $uid = 0) + public static function searchByName(string $search, string $mode = '', int $uid = 0): array { if (empty($search)) { return []; @@ -3223,7 +3229,7 @@ class Contact * @param array $urls * @return array result "count", "added" and "updated" */ - public static function addByUrls(array $urls) + public static function addByUrls(array $urls): array { $added = 0; $updated = 0; @@ -3256,7 +3262,7 @@ class Contact * @return array The profile array * @throws Exception */ - public static function getRandomContact() + public static function getRandomContact(): array { $contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'uid'], [ "`uid` = ? AND `network` = ? AND NOT `failed` AND `last-item` > ?", diff --git a/src/Model/Contact/Group.php b/src/Model/Contact/Group.php index 2b7096a9a8..0f0b4965cd 100644 --- a/src/Model/Contact/Group.php +++ b/src/Model/Contact/Group.php @@ -36,7 +36,7 @@ class Group * @return array * @throws \Exception */ - public static function getById(int $gid) + public static function getById(int $gid): array { $return = []; diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index d68555eb3e..ed520f25ff 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -174,7 +174,7 @@ class Relation * @param array $rel * @return array contact list */ - private static function getContacts(int $uid, array $rel) + private static function getContacts(int $uid, array $rel): array { $list = []; $profile = Profile::getByUID($uid); @@ -182,8 +182,15 @@ class Relation return $list; } - $condition = ['rel' => $rel, 'uid' => $uid, 'self' => false, 'deleted' => false, - 'hidden' => false, 'archive' => false, 'pending' => false]; + $condition = [ + 'rel' => $rel, + 'uid' => $uid, + 'self' => false, + 'deleted' => false, + 'hidden' => false, + 'archive' => false, + 'pending' => false, + ]; $condition = DBA::mergeConditions($condition, ["`url` IN (SELECT `url` FROM `apcontact`)"]); $contacts = DBA::select('contact', ['url'], $condition); while ($contact = DBA::fetch($contacts)) { @@ -201,7 +208,7 @@ class Relation * @param array $contact Contact array * @return boolean True if contact is discoverable */ - public static function isDiscoverable(string $url, array $contact = []) + public static function isDiscoverable(string $url, array $contact = []): bool { $contact_discovery = DI::config()->get('system', 'contact_discovery'); @@ -254,12 +261,14 @@ class Relation } /** - * @param int $uid user + * Returns an array of suggested contacts for given user id + * + * @param int $uid User id * @param int $start optional, default 0 * @param int $limit optional, default 80 * @return array */ - static public function getSuggestions(int $uid, int $start = 0, int $limit = 80) + static public function getSuggestions(int $uid, int $start = 0, int $limit = 80): array { $cid = Contact::getPublicIdByUserId($uid); $totallimit = $start + $limit; @@ -272,20 +281,25 @@ class Relation // The query returns contacts where contacts interacted with whom the given user follows. // Contacts who already are in the user's contact table are ignored. - $results = DBA::select('contact', [], - ["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` IN + $results = DBA::select('contact', [], ["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ?) AND NOT `cid` IN (SELECT `id` FROM `contact` WHERE `uid` = ? AND `nurl` IN (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?)))) AND NOT `hidden` AND `network` IN (?, ?, ?, ?)", - $cid, 0, $uid, Contact::FRIEND, Contact::SHARING, - Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus], - ['order' => ['last-item' => true], 'limit' => $totallimit] + $cid, + 0, + $uid, Contact::FRIEND, Contact::SHARING, + Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, + ], [ + 'order' => ['last-item' => true], + 'limit' => $totallimit, + ] ); while ($contact = DBA::fetch($results)) { $contacts[$contact['id']] = $contact; } + DBA::close($results); Logger::info('Contacts of contacts who are followed by the given user', ['uid' => $uid, 'cid' => $cid, 'count' => count($contacts)]); @@ -365,12 +379,12 @@ class Relation * @return int * @throws Exception */ - public static function countFollows(int $cid, array $condition = []) + public static function countFollows(int $cid, array $condition = []): int { - $condition = DBA::mergeConditions($condition, - ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`)', - $cid] - ); + $condition = DBA::mergeConditions($condition, [ + '`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`)', + $cid, + ]); return DI::dba()->count('contact', $condition); } @@ -556,7 +570,7 @@ class Relation * @param int $count * @param int $offset * @param bool $shuffle - * @return array + * @return array|bool Array on success, false on failure * @throws Exception */ public static function listCommon(int $sourceId, int $targetId, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) @@ -581,7 +595,7 @@ class Relation * @return int * @throws Exception */ - public static function countCommonFollows(int $sourceId, int $targetId, array $condition = []) + public static function countCommonFollows(int $sourceId, int $targetId, array $condition = []): int { $condition = DBA::mergeConditions($condition, ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`) @@ -601,7 +615,7 @@ class Relation * @param int $count * @param int $offset * @param bool $shuffle - * @return array + * @return array|bool Array on success, false on failure * @throws Exception */ public static function listCommonFollows(int $sourceId, int $targetId, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) @@ -626,7 +640,7 @@ class Relation * @return int * @throws Exception */ - public static function countCommonFollowers(int $sourceId, int $targetId, array $condition = []) + public static function countCommonFollowers(int $sourceId, int $targetId, array $condition = []): int { $condition = DBA::mergeConditions($condition, ["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ? AND `follows`) @@ -646,7 +660,7 @@ class Relation * @param int $count * @param int $offset * @param bool $shuffle - * @return array + * @return array|bool Array on success, false on failure * @throws Exception */ public static function listCommonFollowers(int $sourceId, int $targetId, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) diff --git a/src/Model/Contact/User.php b/src/Model/Contact/User.php index 665b95624d..1452369e5e 100644 --- a/src/Model/Contact/User.php +++ b/src/Model/Contact/User.php @@ -28,6 +28,7 @@ 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; use PDOException; @@ -82,11 +83,11 @@ class User /** * Apply changes from contact update data to user-contact table * - * @param array $fields - * @param array $condition - * @return void - * @throws PDOException - * @throws Exception + * @param array $fields + * @param array $condition + * @return void + * @throws PDOException + * @throws Exception */ public static function updateByContactUpdate(array $fields, array $condition) { @@ -106,7 +107,7 @@ class User DBA::close($contacts); } - DBA::commit(); + DBA::commit(); } /** @@ -129,7 +130,7 @@ class User $fields['rel'] = Contact::SELF; } - return DBStructure::getFieldsForTable('user-contact', $fields); + return DI::dbaDefinition()->truncateFieldsForTable('user-contact', $fields); } /** @@ -138,9 +139,10 @@ class User * @param int $cid Either public contact id or user's contact id * @param int $uid User ID * @param boolean $blocked Is the contact blocked or unblocked? + * @return void * @throws \Exception */ - public static function setBlocked($cid, $uid, $blocked) + public static function setBlocked(int $cid, int $uid, bool $blocked) { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { @@ -170,7 +172,7 @@ class User * @return boolean is the contact id blocked for the given user? * @throws \Exception */ - public static function isBlocked($cid, $uid) + public static function isBlocked(int $cid, int $uid): bool { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { @@ -182,7 +184,7 @@ class User if (!empty($cdata['public'])) { $public_contact = DBA::selectFirst('user-contact', ['blocked'], ['cid' => $cdata['public'], 'uid' => $uid]); if (DBA::isResult($public_contact)) { - $public_blocked = $public_contact['blocked']; + $public_blocked = (bool) $public_contact['blocked']; } } @@ -191,7 +193,7 @@ class User if (!empty($cdata['user'])) { $user_contact = DBA::selectFirst('contact', ['blocked'], ['id' => $cdata['user'], 'pending' => false]); if (DBA::isResult($user_contact)) { - $user_blocked = $user_contact['blocked']; + $user_blocked = (bool) $user_contact['blocked']; } } @@ -208,9 +210,10 @@ class User * @param int $cid Either public contact id or user's contact id * @param int $uid User ID * @param boolean $ignored Is the contact ignored or unignored? + * @return void * @throws \Exception */ - public static function setIgnored($cid, $uid, $ignored) + public static function setIgnored(int $cid, int $uid, bool $ignored) { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { @@ -229,11 +232,10 @@ class User * * @param int $cid Either public contact id or user's contact id * @param int $uid User ID - * * @return boolean is the contact id ignored for the given user? * @throws \Exception */ - public static function isIgnored($cid, $uid) + public static function isIgnored(int $cid, int $uid): bool { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { @@ -245,7 +247,7 @@ class User if (!empty($cdata['public'])) { $public_contact = DBA::selectFirst('user-contact', ['ignored'], ['cid' => $cdata['public'], 'uid' => $uid]); if (DBA::isResult($public_contact)) { - $public_ignored = $public_contact['ignored']; + $public_ignored = (bool) $public_contact['ignored']; } } @@ -254,7 +256,7 @@ class User if (!empty($cdata['user'])) { $user_contact = DBA::selectFirst('contact', ['readonly'], ['id' => $cdata['user'], 'pending' => false]); if (DBA::isResult($user_contact)) { - $user_ignored = $user_contact['readonly']; + $user_ignored = (bool) $user_contact['readonly']; } } @@ -271,9 +273,10 @@ class User * @param int $cid Either public contact id or user's contact id * @param int $uid User ID * @param boolean $collapsed are the contact's posts collapsed or uncollapsed? + * @return void * @throws \Exception */ - public static function setCollapsed($cid, $uid, $collapsed) + public static function setCollapsed(int $cid, int $uid, bool $collapsed) { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { @@ -288,16 +291,15 @@ class User * * @param int $cid Either public contact id or user's contact id * @param int $uid User ID - * * @return boolean is the contact id blocked for the given user? * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isCollapsed($cid, $uid) + public static function isCollapsed(int $cid, int $uid): bool { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { - return; + return false; } $collapsed = false; @@ -305,7 +307,7 @@ class User if (!empty($cdata['public'])) { $public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $cdata['public'], 'uid' => $uid]); if (DBA::isResult($public_contact)) { - $collapsed = $public_contact['collapsed']; + $collapsed = (bool) $public_contact['collapsed']; } } @@ -318,9 +320,10 @@ class User * @param int $cid Either public contact id or user's contact id * @param int $uid User ID * @param boolean $blocked Is the user blocked or unblocked by the contact? + * @return void * @throws \Exception */ - public static function setIsBlocked($cid, $uid, $blocked) + public static function setIsBlocked(int $cid, int $uid, bool $blocked) { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { @@ -335,11 +338,10 @@ class User * * @param int $cid Either public contact id or user's contact id * @param int $uid User ID - * * @return boolean Is the user blocked or unblocked by the contact? * @throws \Exception */ - public static function isIsBlocked($cid, $uid) + public static function isIsBlocked(int $cid, int $uid): bool { $cdata = Contact::getPublicAndUserContactID($cid, $uid); if (empty($cdata)) { diff --git a/src/Model/Conversation.php b/src/Model/Conversation.php index 1403b30be2..7d8b8058f1 100644 --- a/src/Model/Conversation.php +++ b/src/Model/Conversation.php @@ -62,7 +62,7 @@ class Conversation */ const RELAY = 3; - public static function getByItemUri($item_uri) + public static function getByItemUri(string $item_uri) { return DBA::selectFirst('conversation', [], ['item-uri' => $item_uri]); } @@ -74,7 +74,7 @@ class Conversation * @return array Item array with removed conversation data * @throws \Exception */ - public static function insert(array $arr) + public static function insert(array $arr): array { if (in_array(($arr['network'] ?? '') ?: Protocol::PHANTOM, [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, Protocol::TWITTER]) && !empty($arr['uri'])) { diff --git a/src/Model/Event.php b/src/Model/Event.php index dac00ceceb..74bf3bd9c0 100644 --- a/src/Model/Event.php +++ b/src/Model/Event.php @@ -41,7 +41,7 @@ use Friendica\Util\XML; class Event { - public static function getHTML(array $event, $simple = false, $uriid = 0) + public static function getHTML(array $event, bool $simple = false, int $uriid = 0): string { if (empty($event)) { return ''; @@ -127,7 +127,7 @@ class Event * @param array $event Array which contains the event data. * @return string The event as a bbcode formatted string. */ - private static function getBBCode(array $event) + private static function getBBCode(array $event): string { $o = ''; @@ -157,11 +157,10 @@ class Event /** * Extract bbcode formatted event data from a string. * - * @params: string $s The string which should be parsed for event data. - * @param $text + * @param string $text The string which should be parsed for event data. * @return array The array with the event information. */ - public static function fromBBCode($text) + public static function fromBBCode(string $text): array { $ev = []; @@ -195,13 +194,13 @@ class Event return $ev; } - public static function sortByDate($event_list) + public static function sortByDate(array $event_list): array { usort($event_list, ['self', 'compareDatesCallback']); return $event_list; } - private static function compareDatesCallback($event_a, $event_b) + private static function compareDatesCallback(array $event_a, array $event_b) { $date_a = DateTimeFormat::local($event_a['start']); $date_b = DateTimeFormat::local($event_b['start']); @@ -223,7 +222,7 @@ class Event * @return void * @throws \Exception */ - public static function delete($event_id) + public static function delete(int $event_id) { if ($event_id == 0) { return; @@ -242,14 +241,14 @@ class Event * @return int The new event id. * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function store($arr) + public static function store(array $arr): int { $event = []; $event['id'] = intval($arr['id'] ?? 0); $event['uid'] = intval($arr['uid'] ?? 0); $event['cid'] = intval($arr['cid'] ?? 0); $event['guid'] = ($arr['guid'] ?? '') ?: System::createUUID(); - $event['uri'] = ($arr['uri'] ?? '') ?: Item::newURI($event['uid'], $event['guid']); + $event['uri'] = ($arr['uri'] ?? '') ?: Item::newURI($event['guid']); $event['uri-id'] = ItemURI::insert(['uri' => $event['uri'], 'guid' => $event['guid']]); $event['type'] = ($arr['type'] ?? '') ?: 'event'; $event['summary'] = $arr['summary'] ?? ''; @@ -317,7 +316,7 @@ class Event return $event['id']; } - public static function getItemArrayForId(int $event_id, array $item = []):array + public static function getItemArrayForId(int $event_id, array $item = []): array { if (empty($event_id)) { return $item; @@ -374,7 +373,7 @@ class Event return $item; } - public static function getItemArrayForImportedId(int $event_id, array $item = []):array + public static function getItemArrayForImportedId(int $event_id, array $item = []): array { if (empty($event_id)) { return $item; @@ -404,7 +403,7 @@ class Event * @return array Array with translations strings. * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getStrings() + public static function getStrings(): array { // First day of the week (0 = Sunday). $firstDay = DI::pConfig()->get(local_user(), 'system', 'first_day_of_week', 0); @@ -477,7 +476,7 @@ class Event * * @todo We should replace this with a separate update function if there is some time left. */ - private static function removeDuplicates(array $dates) + private static function removeDuplicates(array $dates): array { $dates2 = []; @@ -500,7 +499,7 @@ class Event * @return array Query result * @throws \Exception */ - public static function getListById($owner_uid, $event_id, $sql_extra = '') + public static function getListById(int $owner_uid, int $event_id, string $sql_extra = ''): array { $return = []; @@ -536,7 +535,7 @@ class Event * @return array Query results. * @throws \Exception */ - public static function getListByDate($owner_uid, $event_params, $sql_extra = '') + public static function getListByDate(int $owner_uid, array $event_params, string $sql_extra = ''): array { $return = []; @@ -570,7 +569,7 @@ class Event * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function prepareListForTemplate(array $event_result) + public static function prepareListForTemplate(array $event_result): array { $event_list = []; @@ -651,12 +650,12 @@ class Event * @param array $events Query result for events. * @param string $format The output format (ical/csv). * - * @param $timezone + * @param string $timezone Timezone (missing parameter!) * @return string Content according to selected export format. * * @todo Implement timezone support */ - private static function formatListForExport(array $events, $format) + private static function formatListForExport(array $events, string $format): string { $o = ''; @@ -757,7 +756,7 @@ class Event * @return array Query results. * @throws \Exception */ - private static function getListByUserId($uid = 0) + private static function getListByUserId(int $uid = 0): array { $return = []; @@ -797,7 +796,7 @@ class Event * @throws \Exception * @todo Respect authenticated users with events_by_uid(). */ - public static function exportListByUserId($uid, $format = 'ical') + public static function exportListByUserId(int $uid, string $format = 'ical'): array { $process = false; @@ -845,7 +844,8 @@ class Event * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getItemHTML(array $item) { + public static function getItemHTML(array $item): string + { $same_date = false; $finish = false; @@ -933,10 +933,11 @@ class Event * @return array The array with the location data. * 'name' => The name of the location,
* 'address' => The address of the location,
- * 'coordinates' => Latitude‎ and longitude‎ (e.g. '48.864716,2.349014').
+ * 'coordinates' => Latitude and longitude (e.g. '48.864716,2.349014').
* @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function locationToArray($s = '') { + private static function locationToArray(string $s = ''): array + { if ($s == '') { return []; } @@ -981,7 +982,7 @@ class Event * @return bool * @throws \Exception */ - public static function createBirthday($contact, $birthday) + public static function createBirthday(array $contact, string $birthday): bool { // Check for duplicates $condition = [ @@ -1011,8 +1012,7 @@ class Event 'type' => 'birthday', ]; - self::store($values); - - return true; + // Check if self::store() was success + return (self::store($values) > 0); } } diff --git a/src/Model/FContact.php b/src/Model/FContact.php index 6812f5fd09..cc6b2d2a7a 100644 --- a/src/Model/FContact.php +++ b/src/Model/FContact.php @@ -40,7 +40,7 @@ class FContact * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getByURL($handle, $update = null) + public static function getByURL(string $handle, $update = null): array { $person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'addr' => $handle]); if (!DBA::isResult($person)) { @@ -90,7 +90,7 @@ class FContact * @param array $arr The fcontact data * @throws \Exception */ - public static function updateFromProbeArray($arr) + public static function updateFromProbeArray(array $arr) { $uriid = ItemURI::insert(['uri' => $arr['url'], 'guid' => $arr['guid']]); @@ -103,17 +103,27 @@ class FContact $posts = Post::countPosts(['author-id' => $contact['id'], 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]]); } - $fields = ['name' => $arr["name"], 'photo' => $arr["photo"], - 'request' => $arr["request"], 'nick' => $arr["nick"], - 'addr' => strtolower($arr["addr"]), 'guid' => $arr["guid"], - 'batch' => $arr["batch"], 'notify' => $arr["notify"], - 'poll' => $arr["poll"], 'confirm' => $arr["confirm"], - 'alias' => $arr["alias"], 'pubkey' => $arr["pubkey"], - 'uri-id' => $uriid, 'interacting_count' => $interacting ?? 0, - 'interacted_count' => $interacted ?? 0, 'post_count' => $posts ?? 0, - 'updated' => DateTimeFormat::utcNow()]; + $fields = [ + 'name' => $arr['name'], + 'photo' => $arr['photo'], + 'request' => $arr['request'], + 'nick' => $arr['nick'], + 'addr' => strtolower($arr['addr']), + 'guid' => $arr['guid'], + 'batch' => $arr['batch'], + 'notify' => $arr['notify'], + 'poll' => $arr['poll'], + 'confirm' => $arr['confirm'], + 'alias' => $arr['alias'], + 'pubkey' => $arr['pubkey'], + 'uri-id' => $uriid, + 'interacting_count' => $interacting ?? 0, + 'interacted_count' => $interacted ?? 0, + 'post_count' => $posts ?? 0, + 'updated' => DateTimeFormat::utcNow(), + ]; - $condition = ['url' => $arr["url"], 'network' => $arr["network"]]; + $condition = ['url' => $arr['url'], 'network' => $arr['network']]; DBA::update('fcontact', $fields, $condition, true); } @@ -122,12 +132,11 @@ class FContact * get a url (scheme://domain.tld/u/user) from a given Diaspora* * fcontact guid * - * @param mixed $fcontact_guid Hexadecimal string guid - * - * @return string the contact url or null + * @param string $fcontact_guid Hexadecimal string guid + * @return string|null the contact url or null * @throws \Exception */ - public static function getUrlByGuid($fcontact_guid) + public static function getUrlByGuid(string $fcontact_guid) { Logger::info('fcontact', ['guid' => $fcontact_guid]); diff --git a/src/Model/FileTag.php b/src/Model/FileTag.php index ec89c96c69..f8b4f59aad 100644 --- a/src/Model/FileTag.php +++ b/src/Model/FileTag.php @@ -35,10 +35,9 @@ class FileTag * URL encode <, >, left and right brackets * * @param string $s String to be URL encoded. - * * @return string The URL encoded string. */ - private static function encode($s) + private static function encode(string $s): string { return str_replace(['<', '>', '[', ']'], ['%3c', '%3e', '%5b', '%5d'], $s); } @@ -47,10 +46,9 @@ class FileTag * URL decode <, >, left and right brackets * * @param string $s The URL encoded string to be decoded - * * @return string The decoded string. */ - private static function decode($s) + private static function decode(string $s): string { return str_replace(['%3c', '%3e', '%5b', '%5d'], ['<', '>', '[', ']'], $s); } @@ -62,10 +60,9 @@ class FileTag * * @param array $array A list of tags. * @param string $type Optional file type. - * * @return string A list of file tags. */ - public static function arrayToFile(array $array, string $type = 'file') + public static function arrayToFile(array $array, string $type = 'file'): string { $tag_list = ''; if ($type == 'file') { @@ -92,10 +89,9 @@ class FileTag * * @param string $file File tags * @param string $type Optional file type. - * * @return array List of tag names. */ - public static function fileToArray(string $file, string $type = 'file') + public static function fileToArray(string $file, string $type = 'file'): array { $matches = []; $return = []; diff --git a/src/Model/GServer.php b/src/Model/GServer.php index 3ea07dbc6f..1986e47831 100644 --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@ -30,7 +30,6 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\Database; use Friendica\Database\DBA; -use Friendica\Database\DBStructure; use Friendica\DI; use Friendica\Module\Register; use Friendica\Network\HTTPClient\Client\HttpClientAccept; @@ -110,7 +109,7 @@ class GServer * * @param string $url * @param boolean $no_check Don't check if the server hadn't been found - * @return int gserver id + * @return int|null gserver id or NULL on empty URL or failed check */ public static function getID(string $url, bool $no_check = false) { @@ -170,7 +169,7 @@ class GServer * * @return boolean 'true' if server seems vital */ - public static function reachable(string $profile, string $server = '', string $network = '', bool $force = false) + public static function reachable(string $profile, string $server = '', string $network = '', bool $force = false): bool { if ($server == '') { $contact = Contact::getByURL($profile, null, ['baseurl']); @@ -246,7 +245,7 @@ class GServer * * @return boolean 'true' if server seems vital */ - public static function check(string $server_url, string $network = '', bool $force = false, bool $only_nodeinfo = false) + public static function check(string $server_url, string $network = '', bool $force = false, bool $only_nodeinfo = false): bool { $server_url = self::cleanURL($server_url); if ($server_url == '') { @@ -258,7 +257,7 @@ class GServer if ($gserver['created'] <= DBA::NULL_DATETIME) { $fields = ['created' => DateTimeFormat::utcNow()]; $condition = ['nurl' => Strings::normaliseLink($server_url)]; - DBA::update('gserver', $fields, $condition); + self::update($fields, $condition); } if (!$force && (strtotime($gserver['next_contact']) > time())) { @@ -283,7 +282,7 @@ class GServer $gserver = DBA::selectFirst('gserver', [], ['nurl' => Strings::normaliseLink($url)]); if (DBA::isResult($gserver)) { $next_update = self::getNextUpdateDate(false, $gserver['created'], $gserver['last_contact']); - DBA::update('gserver', ['url' => $url, 'failed' => true, 'last_failure' => DateTimeFormat::utcNow(), + self::update(['url' => $url, 'failed' => true, 'last_failure' => DateTimeFormat::utcNow(), 'next_contact' => $next_update, 'network' => Protocol::PHANTOM, 'detection-method' => null], ['nurl' => Strings::normaliseLink($url)]); Logger::info('Set failed status for existing server', ['url' => $url]); @@ -301,7 +300,7 @@ class GServer * @param string $url * @return string cleaned URL */ - public static function cleanURL(string $url) + public static function cleanURL(string $url): string { $url = trim($url, '/'); $url = str_replace('/index.php', '', $url); @@ -324,7 +323,7 @@ class GServer * * @return boolean 'true' if server could be detected */ - public static function detect(string $url, string $network = '', bool $only_nodeinfo = false) + public static function detect(string $url, string $network = '', bool $only_nodeinfo = false): bool { Logger::info('Detect server type', ['server' => $url]); @@ -559,16 +558,13 @@ class GServer $serverdata['last_contact'] = DateTimeFormat::utcNow(); $serverdata['failed'] = false; - // Limit the length on incoming fields - $serverdata = DBStructure::getFieldsForTable('gserver', $serverdata); - $gserver = DBA::selectFirst('gserver', ['network'], ['nurl' => Strings::normaliseLink($url)]); if (!DBA::isResult($gserver)) { $serverdata['created'] = DateTimeFormat::utcNow(); $ret = DBA::insert('gserver', $serverdata); $id = DBA::lastInsertId(); } else { - $ret = DBA::update('gserver', $serverdata, ['nurl' => $serverdata['nurl']]); + $ret = self::update($serverdata, ['nurl' => $serverdata['nurl']]); $gserver = DBA::selectFirst('gserver', ['id'], ['nurl' => $serverdata['nurl']]); if (DBA::isResult($gserver)) { $id = $gserver['id']; @@ -582,14 +578,14 @@ class GServer $max_users = max($apcontacts, $contacts); if ($max_users > $serverdata['registered-users']) { Logger::info('Update registered users', ['id' => $id, 'url' => $serverdata['nurl'], 'registered-users' => $max_users]); - DBA::update('gserver', ['registered-users' => $max_users], ['id' => $id]); + self::update(['registered-users' => $max_users], ['id' => $id]); } if (empty($serverdata['active-month-users'])) { $contacts = DBA::count('contact', ["`uid` = ? AND `gsid` = ? AND NOT `failed` AND `last-item` > ?", 0, $id, DateTimeFormat::utc('now - 30 days')]); if ($contacts > 0) { Logger::info('Update monthly users', ['id' => $id, 'url' => $serverdata['nurl'], 'monthly-users' => $contacts]); - DBA::update('gserver', ['active-month-users' => $contacts], ['id' => $id]); + self::update(['active-month-users' => $contacts], ['id' => $id]); } } @@ -597,7 +593,7 @@ class GServer $contacts = DBA::count('contact', ["`uid` = ? AND `gsid` = ? AND NOT `failed` AND `last-item` > ?", 0, $id, DateTimeFormat::utc('now - 180 days')]); if ($contacts > 0) { Logger::info('Update halfyear users', ['id' => $id, 'url' => $serverdata['nurl'], 'halfyear-users' => $contacts]); - DBA::update('gserver', ['active-halfyear-users' => $contacts], ['id' => $id]); + self::update(['active-halfyear-users' => $contacts], ['id' => $id]); } } } @@ -618,6 +614,7 @@ class GServer * Fetch relay data from a given server url * * @param string $server_url address of the server + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function discoverRelay(string $server_url) @@ -650,7 +647,7 @@ class GServer if (($gserver['relay-subscribe'] != $data['subscribe']) || ($gserver['relay-scope'] != $data['scope'])) { $fields = ['relay-subscribe' => $data['subscribe'], 'relay-scope' => $data['scope']]; - DBA::update('gserver', $fields, ['id' => $gserver['id']]); + self::update($fields, ['id' => $gserver['id']]); } DBA::delete('gserver-tag', ['gserver-id' => $gserver['id']]); @@ -714,7 +711,6 @@ class GServer * Fetch server data from '/statistics.json' on the given server * * @param string $url URL of the given server - * * @return array server data */ private static function fetchStatistics(string $url, array $serverdata) @@ -809,7 +805,7 @@ class GServer * @return array Server data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function fetchNodeinfo(string $url, ICanHandleHttpResponses $httpResult) + private static function fetchNodeinfo(string $url, ICanHandleHttpResponses $httpResult): array { if (!$httpResult->isSuccess()) { return []; @@ -860,7 +856,7 @@ class GServer * @return array Server data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function parseNodeinfo1(string $nodeinfo_url) + private static function parseNodeinfo1(string $nodeinfo_url): array { $curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON); if (!$curlResult->isSuccess()) { @@ -957,7 +953,7 @@ class GServer * @return array Server data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function parseNodeinfo2(string $nodeinfo_url) + private static function parseNodeinfo2(string $nodeinfo_url): array { $curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON); if (!$curlResult->isSuccess()) { @@ -969,8 +965,11 @@ class GServer return []; } - $server = ['detection-method' => self::DETECT_NODEINFO_2, - 'register_policy' => Register::CLOSED]; + $server = [ + 'detection-method' => self::DETECT_NODEINFO_2, + 'register_policy' => Register::CLOSED, + 'platform' => 'unknown', + ]; if (!empty($nodeinfo['openRegistrations'])) { $server['register_policy'] = Register::OPEN; @@ -1155,10 +1154,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - private static function fetchSiteinfo(string $url, array $serverdata) + private static function fetchSiteinfo(string $url, array $serverdata): array { $curlResult = DI::httpClient()->get($url . '/siteinfo.json', HttpClientAccept::JSON); if (!$curlResult->isSuccess()) { @@ -1276,10 +1274,9 @@ class GServer * Checks if the server contains a valid host meta file * * @param string $url URL of the given server - * * @return boolean 'true' if the server seems to be vital */ - private static function validHostMeta(string $url) + private static function validHostMeta(string $url): bool { $xrd_timeout = DI::config()->get('system', 'xrd_timeout'); $curlResult = DI::httpClient()->get($url . '/.well-known/host-meta', HttpClientAccept::XRD_XML, [HttpClientOptions::TIMEOUT => $xrd_timeout]); @@ -1322,10 +1319,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - private static function detectNetworkViaContacts(string $url, array $serverdata) + private static function detectNetworkViaContacts(string $url, array $serverdata): array { $contacts = []; @@ -1374,10 +1370,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - private static function checkPoCo(string $url, array $serverdata) + private static function checkPoCo(string $url, array $serverdata): array { $serverdata['poco'] = ''; @@ -1406,10 +1401,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - public static function checkMastodonDirectory(string $url, array $serverdata) + public static function checkMastodonDirectory(string $url, array $serverdata): array { $curlResult = DI::httpClient()->get($url . '/api/v1/directory?limit=1', HttpClientAccept::JSON); if (!$curlResult->isSuccess()) { @@ -1436,7 +1430,7 @@ class GServer * * @return array server data */ - private static function detectPeertube(string $url, array $serverdata) + private static function detectPeertube(string $url, array $serverdata): array { $curlResult = DI::httpClient()->get($url . '/api/v1/config', HttpClientAccept::JSON); if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) { @@ -1512,7 +1506,15 @@ class GServer return $serverdata; } - private static function fetchWeeklyUsage(string $url, array $serverdata) { + /** + * Fetches weekly usage data + * + * @param string $url URL of the given server + * @param array $serverdata array with server data + * @return array server data + */ + private static function fetchWeeklyUsage(string $url, array $serverdata): array + { $curlResult = DI::httpClient()->get($url . '/api/v1/instance/activity', HttpClientAccept::JSON); if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) { return $serverdata; @@ -1548,10 +1550,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - private static function detectMastodonAlikes(string $url, array $serverdata) + private static function detectMastodonAlikes(string $url, array $serverdata): array { $curlResult = DI::httpClient()->get($url . '/api/v1/instance', HttpClientAccept::JSON); if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) { @@ -1620,10 +1621,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - private static function detectHubzilla(string $url, array $serverdata) + private static function detectHubzilla(string $url, array $serverdata): array { $curlResult = DI::httpClient()->get($url . '/api/statusnet/config.json', HttpClientAccept::JSON); if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) { @@ -1697,10 +1697,9 @@ class GServer * Converts input value to a boolean value * * @param string|integer $val - * * @return boolean */ - private static function toBoolean($val) + private static function toBoolean($val): bool { if (($val == 'true') || ($val == 1)) { return true; @@ -1716,10 +1715,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - private static function detectGNUSocial(string $url, array $serverdata) + private static function detectGNUSocial(string $url, array $serverdata): array { // Test for GNU Social $curlResult = DI::httpClient()->get($url . '/api/gnusocial/version.json', HttpClientAccept::JSON); @@ -1771,10 +1769,9 @@ class GServer * * @param string $url URL of the given server * @param array $serverdata array with server data - * * @return array server data */ - private static function detectFriendica(string $url, array $serverdata) + private static function detectFriendica(string $url, array $serverdata): array { // There is a bug in some versions of Friendica that will return an ActivityStream actor when the content type "application/json" is requested. // Because of this me must not use ACCEPT_JSON here. @@ -1849,7 +1846,7 @@ class GServer * * @return array server data */ - private static function analyseRootBody($curlResult, array $serverdata) + private static function analyseRootBody($curlResult, array $serverdata): array { if (empty($curlResult->getBody())) { return $serverdata; @@ -2008,7 +2005,7 @@ class GServer * * @return array server data */ - private static function analyseRootHeader($curlResult, array $serverdata) + private static function analyseRootHeader($curlResult, array $serverdata): array { if ($curlResult->getHeader('server') == 'Mastodon') { $serverdata['platform'] = 'mastodon'; @@ -2062,7 +2059,7 @@ class GServer Worker::add(PRIORITY_LOW, 'UpdateServerDirectory', $gserver); $fields = ['last_poco_query' => DateTimeFormat::utcNow()]; - DBA::update('gserver', $fields, ['nurl' => $gserver['nurl']]); + self::update($fields, ['nurl' => $gserver['nurl']]); if (--$no_of_queries == 0) { break; @@ -2180,17 +2177,17 @@ class GServer } Logger::info('Protocol for server', ['protocol' => $protocol, 'old' => $old, 'id' => $gsid, 'url' => $gserver['url'], 'callstack' => System::callstack(20)]); - DBA::update('gserver', ['protocol' => $protocol], ['id' => $gsid]); + self::update(['protocol' => $protocol], ['id' => $gsid]); } /** * Fetch the protocol of the given server * * @param int $gsid Server id - * @return int + * @return ?int One of Post\DeliveryData protocol constants or null if unknown or gserver is missing * @throws Exception */ - public static function getProtocol(int $gsid) + public static function getProtocol(int $gsid): ?int { if (empty($gsid)) { return null; @@ -2203,4 +2200,19 @@ class GServer return null; } + + /** + * Enforces gserver table field maximum sizes to avoid "Data too long" database errors + * + * @param array $fields + * @param array $condition + * @return bool + * @throws Exception + */ + public static function update(array $fields, array $condition): bool + { + $fields = DI::dbaDefinition()->truncateFieldsForTable('gserver', $fields); + + return DBA::update('gserver', $fields, $condition); + } } diff --git a/src/Model/Group.php b/src/Model/Group.php index fa41d26467..268680a165 100644 --- a/src/Model/Group.php +++ b/src/Model/Group.php @@ -39,7 +39,14 @@ class Group const FOLLOWERS = '~'; const MUTUALS = '&'; - public static function getByUserId($uid, $includesDeleted = false) + /** + * Fetches group record by user id and maybe includes deleted groups as well + * + * @param int $uid User id to fetch group(s) for + * @param bool $includesDeleted Whether deleted groups should be included + * @return array|bool Array on success, bool on error + */ + public static function getByUserId(int $uid, bool $includesDeleted = false) { $conditions = ['uid' => $uid, 'cid' => null]; @@ -51,15 +58,18 @@ class Group } /** - * @param int $group_id + * Checks whether given group id is found in database + * + * @param int $group_id Groupd it + * @param int $uid Optional user id * @return bool * @throws \Exception */ - public static function exists($group_id, $uid = null) + public static function exists(int $group_id, int $uid = null): bool { $condition = ['id' => $group_id, 'deleted' => false]; - if (isset($uid)) { + if (!is_null($uid)) { $condition = [ 'uid' => $uid ]; @@ -73,12 +83,12 @@ class Group * * Note: If we found a deleted group with the same name, we restore it * - * @param int $uid - * @param string $name - * @return boolean + * @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 * @throws \Exception */ - public static function create($uid, $name) + public static function create(int $uid, string $name) { $return = false; if (!empty($uid) && !empty($name)) { @@ -114,7 +124,7 @@ class Group * @return bool Was the update successful? * @throws \Exception */ - public static function update($id, $name) + public static function update(int $id, string $name): bool { return DBA::update('group', ['name' => $name], ['id' => $id]); } @@ -122,11 +132,11 @@ class Group /** * Get a list of group ids a contact belongs to * - * @param int $cid - * @return array + * @param int $cid Contact id + * @return array Group ids * @throws \Exception */ - public static function getIdsByContactId($cid) + public static function getIdsByContactId(int $cid): array { $return = []; @@ -185,12 +195,12 @@ class Group * * Returns false if no group has been found. * - * @param int $uid - * @param string $name - * @return int|boolean + * @param int $uid User id + * @param string $name Group name + * @return int|boolean Groups' id number or false on error * @throws \Exception */ - public static function getIdByName($uid, $name) + public static function getIdByName(int $uid, string $name) { if (!$uid || !strlen($name)) { return false; @@ -211,7 +221,7 @@ class Group * @return boolean * @throws \Exception */ - public static function remove($gid) + public static function remove(int $gid): bool { if (!$gid) { return false; @@ -314,13 +324,14 @@ class Group * Adds contacts to a group * * @param int $gid - * @param array $contacts + * @param array $contacts Array with contact ids + * @return void * @throws \Exception */ public static function addMembers(int $gid, array $contacts) { if (!$gid || !$contacts) { - return false; + return; } // @TODO Backward compatibility with user contacts, remove by version 2022.03 @@ -342,8 +353,9 @@ class Group /** * Removes contacts from a group * - * @param int $gid - * @param array $contacts + * @param int $gid Group id + * @param array $contacts Contact ids + * @return bool * @throws \Exception */ public static function removeMembers(int $gid, array $contacts) @@ -369,19 +381,20 @@ class Group $contactIds[] = $cdata['user']; } - DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $contactIds]); + // Return status of deletion + return DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $contactIds]); } /** * Returns the combined list of contact ids from a group id list * - * @param int $uid - * @param array $group_ids - * @param boolean $check_dead + * @param int $uid User id + * @param array $group_ids Groups ids + * @param boolean $check_dead Whether check "dead" records (?) * @return array * @throws \Exception */ - public static function expand($uid, array $group_ids, $check_dead = false) + public static function expand(int $uid, array $group_ids, bool $check_dead = false): array { if (!is_array($group_ids) || !count($group_ids)) { return []; @@ -454,13 +467,13 @@ class Group /** * Returns a templated group selection list * - * @param int $uid + * @param int $uid User id * @param int $gid An optional pre-selected group * @param string $label An optional label of the list * @return string * @throws \Exception */ - public static function displayGroupSelection($uid, $gid = 0, $label = '') + public static function displayGroupSelection(int $uid, int $gid = 0, string $label = ''): string { $display_groups = [ [ @@ -502,12 +515,12 @@ class Group * '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 $group_id - * @param int $cid - * @return string + * @param string|int $group_id Distinct group id or 'everyone' + * @param int $cid Contact id + * @return string Sidebar widget HTML code * @throws \Exception */ - public static function sidebarWidget($every = 'contact', $each = 'group', $editmode = 'standard', $group_id = '', $cid = 0) + public static function sidebarWidget(string $every = 'contact', string $each = 'group', string $editmode = 'standard', $group_id = '', int $cid = 0) { if (!local_user()) { return ''; @@ -589,7 +602,7 @@ class Group * @param integer $id Contact ID * @return integer Group IO */ - public static function getIdForForum(int $id) + public static function getIdForForum(int $id): int { Logger::info('Get id for forum id', ['id' => $id]); $contact = Contact::getById($id, ['uid', 'name', 'contact-type', 'manually-approve']); @@ -617,6 +630,7 @@ class Group * Fetch the followers of a given contact id and store them as group members * * @param integer $id Contact ID + * @return void */ public static function updateMembersForForum(int $id) { diff --git a/src/Model/Item.php b/src/Model/Item.php index 4b42ad0e13..01ea942c86 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -96,8 +96,8 @@ class Item 'event-created', 'event-edited', 'event-start', 'event-finish', 'event-summary', 'event-desc', 'event-location', 'event-type', 'event-nofinish', 'event-ignore', 'event-id', - "question-id", "question-multiple", "question-voters", "question-end-time", - "has-categories", "has-media", + 'question-id', 'question-multiple', 'question-voters', 'question-end-time', + 'has-categories', 'has-media', 'delivery_queue_count', 'delivery_queue_done', 'delivery_queue_failed' ]; @@ -226,7 +226,7 @@ class Item foreach ($notify_items as $notify_item) { $post = Post::selectFirst(['uri-id', 'uid'], ['id' => $notify_item]); - Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, (int)$post['uri-id'], (int)$post['uid']); + Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::POST, (int)$post['uri-id'], (int)$post['uid']); } return $rows; @@ -237,9 +237,10 @@ class Item * * @param array $condition The condition for finding the item entries * @param integer $priority Priority for the notification + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function markForDeletion($condition, $priority = PRIORITY_HIGH) + public static function markForDeletion(array $condition, int $priority = PRIORITY_HIGH) { $items = Post::select(['id'], $condition); while ($item = Post::fetch($items)) { @@ -253,9 +254,10 @@ class Item * * @param array $condition The condition for finding the item entries * @param integer $uid User who wants to delete this item + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function deleteForUser($condition, $uid) + public static function deleteForUser(array $condition, int $uid) { if ($uid == 0) { return; @@ -282,11 +284,10 @@ class Item * * @param integer $item_id * @param integer $priority Priority for the notification - * * @return boolean success * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function markForDeletionById($item_id, $priority = PRIORITY_HIGH) + public static function markForDeletionById(int $item_id, int $priority = PRIORITY_HIGH): bool { Logger::info('Mark item for deletion by id', ['id' => $item_id, 'callstack' => System::callstack()]); // locate item to be deleted @@ -331,7 +332,7 @@ class Item // If item has attachments, drop them $attachments = Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT]); foreach($attachments as $attachment) { - if (preg_match("|attach/(\d+)|", $attachment['url'], $matches)) { + if (preg_match('|attach/(\d+)|', $attachment['url'], $matches)) { Attach::delete(['id' => $matches[1], 'uid' => $item['uid']]); } } @@ -360,7 +361,7 @@ class Item // send the notification upstream/downstream if ($priority) { - Worker::add(['priority' => $priority, 'dont_fork' => true], "Notifier", Delivery::DELETION, (int)$item['uri-id'], (int)$item['uid']); + Worker::add(['priority' => $priority, 'dont_fork' => true], 'Notifier', Delivery::DELETION, (int)$item['uri-id'], (int)$item['uid']); } } elseif ($item['uid'] != 0) { Post\User::update($item['uri-id'], $item['uid'], ['hidden' => true]); @@ -372,7 +373,14 @@ class Item return true; } - public static function guid($item, $notify) + /** + * Get guid from given item record + * + * @param array $item Item record + * @param bool Whether to notify (?) + * @return string Guid + */ + public static function guid(array $item, bool $notify): string { if (!empty($item['guid'])) { return trim($item['guid']); @@ -425,7 +433,13 @@ class Item return $guid; } - private static function contactId($item) + /** + * Returns contact id from given item record + * + * @param array $item Item record + * @return int Contact id + */ + private static function contactId(array $item): int { if (!empty($item['contact-id']) && DBA::exists('contact', ['self' => true, 'id' => $item['contact-id']])) { return $item['contact-id']; @@ -451,17 +465,17 @@ class Item * @param array $item The item fields that are to be inserted * @throws \Exception */ - private static function spool($orig_item) + private static function spool(array $item) { // Now we store the data in the spool directory // We use "microtime" to keep the arrival order and "mt_rand" to avoid duplicates $file = 'item-' . round(microtime(true) * 10000) . '-' . mt_rand() . '.msg'; $spoolpath = System::getSpoolPath(); - if ($spoolpath != "") { + if ($spoolpath != '') { $spool = $spoolpath . '/' . $file; - file_put_contents($spool, json_encode($orig_item)); + file_put_contents($spool, json_encode($item)); Logger::warning("Item wasn't stored - Item was spooled into file", ['file' => $file]); } } @@ -469,10 +483,10 @@ class Item /** * Check if the item array is a duplicate * - * @param array $item + * @param array $item Item record * @return boolean is it a duplicate? */ - private static function isDuplicate(array $item) + private static function isDuplicate(array $item): bool { // Checking if there is already an item with the same guid $condition = ['guid' => $item['guid'], 'network' => $item['network'], 'uid' => $item['uid']]; @@ -521,10 +535,10 @@ class Item /** * Check if the item array is valid * - * @param array $item + * @param array $item Item record * @return boolean item is valid */ - public static function isValid(array $item) + public static function isValid(array $item): bool { // When there is no content then we don't post it if (($item['body'] . $item['title'] == '') && (empty($item['uri-id']) || !Post\Media::existsByURIId($item['uri-id']))) { @@ -591,10 +605,10 @@ class Item /** * Check if the item array is too old * - * @param array $item + * @param array $item Item record * @return boolean item is too old */ - public static function isTooOld(array $item) + public static function isTooOld(array $item): bool { // check for create date and expire time $expire_interval = DI::config()->get('system', 'dbclean-expire-days', 0); @@ -623,15 +637,20 @@ class Item /** * Return the id of the given item array if it has been stored before * - * @param array $item - * @return integer item id + * @param array $item Item record + * @return integer Item id or zero on error */ - private static function getDuplicateID(array $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 (?, ?, ?, ?)", - $item['uri-id'], $item['uid'], - Protocol::ACTIVITYPUB, Protocol::DIASPORA, Protocol::DFRN, Protocol::OSTATUS]; + $condition = ['`uri-id` = ? AND `uid` = ? AND `network` IN (?, ?, ?, ?)', + $item['uri-id'], + $item['uid'], + Protocol::ACTIVITYPUB, + Protocol::DIASPORA, + Protocol::DFRN, + Protocol::OSTATUS + ]; $existing = Post::selectFirst(['id', 'network'], $condition); if (DBA::isResult($existing)) { // We only log the entries with a different user id than 0. Otherwise we would have too many false positives @@ -640,12 +659,12 @@ class Item 'uri-id' => $item['uri-id'], 'uid' => $item['uid'], 'network' => $item['network'], - 'existing_id' => $existing["id"], - 'existing_network' => $existing["network"] + 'existing_id' => $existing['id'], + 'existing_network' => $existing['network'] ]); } - return $existing["id"]; + return $existing['id']; } } return 0; @@ -658,7 +677,7 @@ class Item * @return array item array with parent data * @throws \Exception */ - private static function getTopLevelParent(array $item) + private static function getTopLevelParent(array $item): array { $fields = ['uid', 'uri', 'parent-uri', 'id', 'deleted', 'uri-id', 'parent-uri-id', @@ -709,7 +728,7 @@ class Item * @param array $item * @return integer gravity */ - private static function getGravity(array $item) + private static function getGravity(array $item): int { $activity = DI::activity(); @@ -724,11 +743,20 @@ class Item } elseif ($activity->match($item['verb'], Activity::ANNOUNCE)) { return GRAVITY_ACTIVITY; } + Logger::info('Unknown gravity for verb', ['verb' => $item['verb']]); return GRAVITY_UNKNOWN; // Should not happen } - public static function insert(array $item, int $notify = 0, bool $post_local = true) + /** + * Inserts item record + * + * @param array $item Item array to be inserted + * @param int $notify Notification (type?) + * @param bool $post_local (???) + * @return int Zero means error, otherwise primary key (id) is being returned + */ + public static function insert(array $item, int $notify = 0, bool $post_local = true): int { $orig_item = $item; @@ -752,7 +780,7 @@ class Item $uid = intval($item['uid']); $item['guid'] = self::guid($item, $notify); - $item['uri'] = substr(trim($item['uri'] ?? '') ?: self::newURI($item['uid'], $item['guid']), 0, 255); + $item['uri'] = substr(trim($item['uri'] ?? '') ?: self::newURI($item['guid']), 0, 255); // Store URI data $item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]); @@ -869,7 +897,7 @@ class Item Contact::checkAvatarCache($item['owner-id']); // The contact-id should be set before "self::insert" was called - but there seems to be issues sometimes - $item["contact-id"] = self::contactId($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)) { @@ -944,8 +972,8 @@ class Item $item['thr-parent-id'] = ItemURI::getIdByURI($item['thr-parent']); // Is this item available in the global items (with uid=0)? - if ($item["uid"] == 0) { - $item["global"] = true; + if ($item['uid'] == 0) { + $item['global'] = true; // Set the global flag on all items if this was a global item entry Post::update(['global' => true], ['uri-id' => $item['uri-id']]); @@ -954,8 +982,8 @@ class Item } // ACL settings - if (!empty($item["allow_cid"] . $item["allow_gid"] . $item["deny_cid"] . $item["deny_gid"])) { - $item["private"] = self::PRIVATE; + if (!empty($item['allow_cid'] . $item['allow_gid'] . $item['deny_cid'] . $item['deny_gid'])) { + $item['private'] = self::PRIVATE; } if ($notify && $post_local) { @@ -1323,7 +1351,7 @@ class Item * @param string $signed_text Original text (for Diaspora signatures), JSON encoded. * @throws \Exception */ - public static function distribute($itemid, $signed_text = '') + public static function distribute(int $itemid, string $signed_text = '') { $condition = ["`id` IN (SELECT `parent` FROM `post-user-view` WHERE `id` = ?)", $itemid]; $parent = Post::selectFirst(['owner-id'], $condition); @@ -1417,7 +1445,7 @@ class Item * @param integer $source_uid User id of the source post * @return integer stored item id */ - public static function storeForUserByUriId(int $uri_id, int $uid, array $fields = [], int $source_uid = 0) + public static function storeForUserByUriId(int $uri_id, int $uid, array $fields = [], int $source_uid = 0): int { if ($uid == $source_uid) { Logger::warning('target UID must not be be equal to the source UID', ['uri-id' => $uri_id, 'uid' => $uid]); @@ -1525,7 +1553,7 @@ class Item * @return integer stored item id * @throws \Exception */ - private static function storeForUser(array $item, int $uid) + private static function storeForUser(array $item, int $uid): int { if (Post::exists(['uri-id' => $item['uri-id'], 'uid' => $uid])) { if (!empty($item['event-id'])) { @@ -1613,7 +1641,7 @@ class Item * @param integer $itemid Item ID that should be added * @throws \Exception */ - private static function addShadow($itemid) + private static function addShadow(int $itemid) { $fields = ['uid', 'private', 'visible', 'deleted', 'network', 'uri-id']; $condition = ['id' => $itemid, 'gravity' => GRAVITY_PARENT]; @@ -1676,7 +1704,7 @@ class Item * @param integer $itemid Item ID that should be added * @throws \Exception */ - private static function addShadowPost($itemid) + private static function addShadowPost(int $itemid) { $item = Post::selectFirst(self::ITEM_FIELDLIST, ['id' => $itemid]); if (!DBA::isResult($item)) { @@ -1740,7 +1768,7 @@ class Item * @return string detected language * @throws \Text_LanguageDetect_Exception */ - private static function getLanguage(array $item) + private static function getLanguage(array $item): string { if (!empty($item['language'])) { return $item['language']; @@ -1784,7 +1812,7 @@ class Item return ''; } - public static function getLanguageMessage(array $item) + public static function getLanguageMessage(array $item): string { $iso639 = new \Matriphe\ISO639\ISO639; @@ -1802,38 +1830,37 @@ class Item * Posts that are created on this system are using System::createUUID. * Received ActivityPub posts are using Processor::getGUIDByURL. * - * @param string $uri uri of an item entry - * @param string $host hostname for the GUID prefix - * @return string unique guid + * @param string $uri uri of an item entry + * @param string|null $host hostname for the GUID prefix + * @return string Unique guid */ - public static function guidFromUri($uri, $host) + public static function guidFromUri(string $uri, string $host = null): string { // Our regular guid routine is using this kind of prefix as well // We have to avoid that different routines could accidentally create the same value $parsed = parse_url($uri); // Remove the scheme to make sure that "https" and "http" doesn't make a difference - unset($parsed["scheme"]); + unset($parsed['scheme']); // Glue it together to be able to make a hash from it - $host_id = implode("/", $parsed); + $host_id = implode('/', $parsed); // Use a mixture of several hashes to provide some GUID like experience - return hash("crc32", $host) . '-'. hash('joaat', $host_id) . '-'. hash('fnv164', $host_id); + return hash('crc32', $host) . '-'. hash('joaat', $host_id) . '-'. hash('fnv164', $host_id); } /** * generate an unique URI * - * @param integer $uid User id - * @param string $guid An existing GUID (Otherwise it will be generated) + * @param string $guid An existing GUID (Otherwise it will be generated) * * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function newURI($uid, $guid = "") + public static function newURI(string $guid = ''): string { - if ($guid == "") { + if ($guid == '') { $guid = System::createUUID(); } @@ -1850,7 +1877,7 @@ class Item * @param array $arr Contains the just posted item record * @throws \Exception */ - private static function updateContact($arr) + private static function updateContact(array $arr) { // Unarchive the author $contact = DBA::selectFirst('contact', [], ['id' => $arr["author-id"]]); @@ -1897,7 +1924,7 @@ class Item } } - public static function setHashtags($body) + public static function setHashtags(string $body): string { $body = BBCode::performWithEscapedTags($body, ['noparse', 'pre', 'code', 'img'], function ($body) { $tags = BBCode::getTags($body); @@ -1971,7 +1998,7 @@ class Item * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function tagDeliver($uid, $item_id) + private static function tagDeliver(int $uid, int $item_id): bool { $mention = false; @@ -2066,7 +2093,7 @@ class Item self::performActivity($item['id'], 'announce', $item['uid']); } - public static function isRemoteSelf($contact, &$datarray) + public static function isRemoteSelf(array $contact, array &$datarray): bool { if (!$contact['remote_self']) { return false; @@ -2122,7 +2149,7 @@ class Item $old_uri_id = $datarray["uri-id"] ?? 0; $datarray["guid"] = System::createUUID(); unset($datarray["plink"]); - $datarray["uri"] = self::newURI($contact['uid'], $datarray["guid"]); + $datarray["uri"] = self::newURI($datarray["guid"]); $datarray["uri-id"] = ItemURI::getIdByURI($datarray["uri"]); $datarray["extid"] = Protocol::DFRN; $urlpart = parse_url($datarray2['author-link']); @@ -2160,7 +2187,7 @@ class Item * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function fixPrivatePhotos($s, $uid, $item = null, $cid = 0) + public static function fixPrivatePhotos(string $s, int $uid, array $item = null, int $cid = 0): string { if (DI::config()->get('system', 'disable_embedded')) { return $s; @@ -2254,13 +2281,14 @@ class Item return $new_body; } - private static function hasPermissions($obj) + private static function hasPermissions(array $obj) { return !empty($obj['allow_cid']) || !empty($obj['allow_gid']) || !empty($obj['deny_cid']) || !empty($obj['deny_gid']); } - private static function samePermissions($uid, $obj1, $obj2) + // @TODO $uid is unused parameter + private static function samePermissions($uid, array $obj1, array $obj2): bool { // first part is easy. Check that these are exactly the same. if (($obj1['allow_cid'] == $obj2['allow_cid']) @@ -2288,7 +2316,7 @@ class Item * @return array * @throws \Exception */ - public static function enumeratePermissions(array $obj, bool $check_dead = false) + public static function enumeratePermissions(array $obj, bool $check_dead = false): array { $aclFormater = DI::aclFormatter(); @@ -2376,7 +2404,7 @@ class Item Logger::notice('User ' . $uid . ": expired $expired items; expire items: $expire_items, expire notes: $expire_notes, expire starred: $expire_starred, expire photos: $expire_photos"); } - public static function firstPostDate($uid, $wall = false) + public static function firstPostDate(int $uid, bool $wall = false) { $user = User::getById($uid, ['register_date']); if (empty($user)) { @@ -2417,7 +2445,7 @@ class Item * array $arr * 'post_id' => ID of posted item */ - public static function performActivity(int $item_id, string $verb, int $uid, string $allow_cid = null, string $allow_gid = null, string $deny_cid = null, string $deny_gid = null) + public static function performActivity(int $item_id, string $verb, int $uid, string $allow_cid = null, string $allow_gid = null, string $deny_cid = null, string $deny_gid = null): bool { if (empty($uid)) { return false; @@ -2562,7 +2590,7 @@ class Item $new_item = [ 'guid' => System::createUUID(), - 'uri' => self::newURI($item['uid']), + 'uri' => self::newURI(), 'uid' => $item['uid'], 'contact-id' => $owner['id'], 'wall' => $item['wall'], @@ -2611,7 +2639,7 @@ class Item * @param integer $owner_id User ID for which the permissions should be fetched * @return array condition */ - public static function getPermissionsConditionArrayByUserId(int $owner_id) + public static function getPermissionsConditionArrayByUserId(int $owner_id): array { $local_user = local_user(); $remote_user = Session::getRemoteContactID($owner_id); @@ -2643,7 +2671,7 @@ class Item * @param string $table * @return string */ - public static function getPermissionsSQLByUserId(int $owner_id, string $table = '') + public static function getPermissionsSQLByUserId(int $owner_id, string $table = ''): string { $local_user = local_user(); $remote_user = Session::getRemoteContactID($owner_id); @@ -2691,7 +2719,7 @@ class Item * @param \Friendica\Core\L10n $l10n * @return string */ - public static function postType(array $item, \Friendica\Core\L10n $l10n) + public static function postType(array $item, \Friendica\Core\L10n $l10n): string { if (!empty($item['event-id'])) { return $l10n->t('event'); @@ -2757,10 +2785,10 @@ class Item * Given an item array, convert the body element from bbcode to html and add smilie icons. * If attach is true, also add icons for item attachments. * - * @param array $item - * @param boolean $attach - * @param boolean $is_preview - * @param boolean $only_cache + * @param array $item Record from item table + * @param boolean $attach If true, add icons for item attachments as well + * @param boolean $is_preview Whether this is a preview + * @param boolean $only_cache Whether only cached HTML should be updated * @return string item body html * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException @@ -2769,7 +2797,7 @@ class Item * @hook prepare_body ('item'=>item array, 'html'=>body string, 'is_preview'=>boolean, 'filter_reasons'=>string array) after first bbcode to html * @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author) */ - public static function prepareBody(array &$item, $attach = false, $is_preview = false, $only_cache = false) + public static function prepareBody(array &$item, bool $attach = false, bool $is_preview = false, bool $only_cache = false): string { $a = DI::app(); Hook::callAll('prepare_body_init', $item); @@ -2802,7 +2830,8 @@ class Item $shared_uri_id = 0; $shared_links = []; } - $attachments = Post\Media::splitAttachments($item['uri-id'], $item['guid'] ?? '', $shared_links, $item['has-media']); + + $attachments = Post\Media::splitAttachments($item['uri-id'], $item['guid'] ?? '', $shared_links, $item['has-media'] ?? false); $item['body'] = self::replaceVisualAttachments($attachments, $item['body'] ?? ''); $item['body'] = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", "\n", $item['body']); @@ -2811,7 +2840,7 @@ class Item $s = $item["rendered-html"]; if ($only_cache) { - return; + return ''; } // Compile eventual content filter reasons @@ -2891,7 +2920,7 @@ class Item * @param int $type * @return bool */ - public static function containsLink(string $body, string $url, int $type = 0) + public static function containsLink(string $body, string $url, int $type = 0): bool { // Make sure that for example site parameters aren't used when testing if the link is contained in the body $urlparts = parse_url($url); @@ -2924,7 +2953,7 @@ class Item * @param string $body * @return string modified body */ - private static function replaceVisualAttachments(array $attachments, string $body) + private static function replaceVisualAttachments(array $attachments, string $body): string { DI::profiler()->startRecording('rendering'); @@ -2955,7 +2984,7 @@ class Item * @param string $content * @return string modified content */ - private static function addVisualAttachments(array $attachments, array $item, string $content, bool $shared) + private static function addVisualAttachments(array $attachments, array $item, string $content, bool $shared): string { DI::profiler()->startRecording('rendering'); $leading = ''; @@ -3047,7 +3076,7 @@ class Item * @param array $ignore_links A list of URLs to ignore * @return string modified content */ - private static function addLinkAttachment(int $uriid, array $attachments, string $body, string $content, bool $shared, array $ignore_links) + private static function addLinkAttachment(int $uriid, array $attachments, string $body, string $content, bool $shared, array $ignore_links): string { DI::profiler()->startRecording('rendering'); // Don't show a preview when there is a visual attachment (audio or video) @@ -3161,7 +3190,7 @@ class Item * @param string $content * @return string modified content */ - private static function addNonVisualAttachments(array $attachments, array $item, string $content) + private static function addNonVisualAttachments(array $attachments, array $item, string $content): string { DI::profiler()->startRecording('rendering'); $trailing = ''; @@ -3193,7 +3222,7 @@ class Item return $content; } - private static function addQuestions(array $item, string $content) + private static function addQuestions(array $item, string $content): string { DI::profiler()->startRecording('rendering'); if (!empty($item['question-id'])) { @@ -3244,7 +3273,7 @@ class Item * @return boolean|array False if item has not plink, otherwise array('href'=>plink url, 'title'=>translated title) * @throws \Exception */ - public static function getPlink($item) + public static function getPlink(array $item) { if (!empty($item['plink']) && Network::isValidHttpUrl($item['plink'])) { $plink = $item['plink']; @@ -3291,7 +3320,7 @@ class Item * * @return boolean "true" when it is a forum post */ - public static function isForumPost(int $uri_id) + public static function isForumPost(int $uri_id): bool { foreach (Tag::getByURIId($uri_id, [Tag::EXCLUSIVE_MENTION]) as $tag) { if (DBA::exists('contact', ['uid' => 0, 'nurl' => Strings::normaliseLink($tag['url']), 'contact-type' => Contact::TYPE_COMMUNITY])) { @@ -3309,7 +3338,7 @@ class Item * * @return integer item id */ - public static function searchByLink($uri, $uid = 0) + public static function searchByLink(string $uri, int $uid = 0): int { $ssl_uri = str_replace('http://', 'https://', $uri); $uris = [$uri, $ssl_uri, Strings::normaliseLink($uri)]; @@ -3334,7 +3363,7 @@ class Item * * @return string URI */ - public static function getURIByLink(string $uri) + public static function getURIByLink(string $uri): string { $ssl_uri = str_replace('http://', 'https://', $uri); $uris = [$uri, $ssl_uri, Strings::normaliseLink($uri)]; @@ -3360,7 +3389,7 @@ class Item * * @return integer item id */ - public static function fetchByLink(string $uri, int $uid = 0) + public static function fetchByLink(string $uri, int $uid = 0): int { Logger::info('Trying to fetch link', ['uid' => $uid, 'uri' => $uri]); $item_id = self::searchByLink($uri, $uid); @@ -3381,7 +3410,11 @@ class Item return is_numeric($hookData['item_id']) ? $hookData['item_id'] : 0; } - if ($fetched_uri = ActivityPub\Processor::fetchMissingActivity($uri)) { + $fetchQueue = new ActivityPub\FetchQueue(); + $fetched_uri = ActivityPub\Processor::fetchMissingActivity($fetchQueue, $uri); + $fetchQueue->process(); + + if ($fetched_uri) { $item_id = self::searchByLink($fetched_uri, $uid); } else { $item_id = Diaspora::fetchByURL($uri); @@ -3406,20 +3439,9 @@ class Item * * @return array with share information */ - public static function getShareArray($item) + public static function getShareArray(array $item): array { - if (!preg_match("/(.*?)\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", $item['body'], $matches)) { - return []; - } - - $attribute_string = $matches[2]; - $attributes = ['comment' => trim($matches[1]), 'shared' => trim($matches[3])]; - foreach (['author', 'profile', 'avatar', 'guid', 'posted', 'link'] as $field) { - if (preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches)) { - $attributes[$field] = trim(html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8')); - } - } - return $attributes; + return BBCode::fetchShareAttributes($item['body']); } /** @@ -3429,7 +3451,7 @@ class Item * * @return array item array with data from the original item */ - public static function addShareDataFromOriginal(array $item) + public static function addShareDataFromOriginal(array $item): array { $shared = self::getShareArray($item); if (empty($shared)) { @@ -3490,7 +3512,7 @@ class Item * @return bool * @throws \Exception */ - protected static function isAllowedByUser(array $item, int $user_id) + protected static function isAllowedByUser(array $item, int $user_id): bool { if (!empty($item['author-id']) && Contact\User::isBlocked($item['author-id'], $user_id)) { Logger::notice('Author is blocked by user', ['author-link' => $item['author-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]); @@ -3522,7 +3544,7 @@ class Item * @param array $item * @return string body */ - public static function improveSharedDataInBody(array $item) + public static function improveSharedDataInBody(array $item): string { $shared = BBCode::fetchShareAttributes($item['body']); if (empty($shared['link'])) { diff --git a/src/Model/ItemURI.php b/src/Model/ItemURI.php index d57df4c425..020c468d23 100644 --- a/src/Model/ItemURI.php +++ b/src/Model/ItemURI.php @@ -30,7 +30,6 @@ class ItemURI * Insert an item-uri record and return its id * * @param array $fields Item-uri fields - * * @return int|null item-uri id * @throws \Exception */ @@ -61,12 +60,15 @@ class ItemURI * Searched for an id of a given uri. Adds it, if not existing yet. * * @param string $uri - * * @return integer item-uri id * @throws \Exception */ - public static function getIdByURI($uri) + public static function getIdByURI(string $uri): int { + if (empty($uri)) { + return 0; + } + // If the URI gets too long we only take the first parts and hope for best $uri = substr($uri, 0, 255); @@ -82,11 +84,10 @@ class ItemURI * Searched for an id of a given guid. * * @param string $guid - * * @return integer item-uri id * @throws \Exception */ - public static function getIdByGUID($guid) + public static function getIdByGUID(string $guid): int { // If the GUID gets too long we only take the first parts and hope for best $guid = substr($guid, 0, 255); diff --git a/src/Model/Log/ParsedLogIterator.php b/src/Model/Log/ParsedLogIterator.php index 711391cb01..4309e4cd00 100644 --- a/src/Model/Log/ParsedLogIterator.php +++ b/src/Model/Log/ParsedLogIterator.php @@ -45,7 +45,7 @@ class ParsedLogIterator implements \Iterator private $filters = []; /** @var string search term */ - private $search = ""; + private $search = ''; /** @@ -60,7 +60,7 @@ class ParsedLogIterator implements \Iterator * @param string $filename File to open * @return $this */ - public function open(string $filename) + public function open(string $filename): ParsedLogIterator { $this->reader->open($filename); return $this; @@ -70,7 +70,7 @@ class ParsedLogIterator implements \Iterator * @param int $limit Max num of lines to read * @return $this */ - public function withLimit(int $limit) + public function withLimit(int $limit): ParsedLogIterator { $this->limit = $limit; return $this; @@ -80,7 +80,7 @@ class ParsedLogIterator implements \Iterator * @param array $filters filters per column * @return $this */ - public function withFilters(array $filters) + public function withFilters(array $filters): ParsedLogIterator { $this->filters = $filters; return $this; @@ -90,7 +90,7 @@ class ParsedLogIterator implements \Iterator * @param string $search string to search to filter lines * @return $this */ - public function withSearch(string $search) + public function withSearch(string $search): ParsedLogIterator { $this->search = $search; return $this; @@ -100,18 +100,19 @@ class ParsedLogIterator implements \Iterator * Check if parsed log line match filters. * Always match if no filters are set. * - * @param ParsedLogLine $parsedlogline - * @return bool + * @param ParsedLogLine $parsedlogline ParsedLogLine instance + * @return bool Wether the parse log line matches */ - private function filter($parsedlogline) + private function filter(ParsedLogLine $parsedlogline): bool { $match = true; foreach ($this->filters as $filter => $filtervalue) { switch ($filter) { - case "level": + case 'level': $match = $match && ($parsedlogline->level == strtoupper($filtervalue)); break; - case "context": + + case 'context': $match = $match && ($parsedlogline->context == $filtervalue); break; } @@ -126,9 +127,9 @@ class ParsedLogIterator implements \Iterator * @param ParsedLogLine $parsedlogline * @return bool */ - private function search($parsedlogline) + private function search(ParsedLogLine $parsedlogline): bool { - if ($this->search != "") { + if ($this->search != '') { return strstr($parsedlogline->logline, $this->search) !== false; } return true; @@ -138,7 +139,6 @@ class ParsedLogIterator implements \Iterator * Read a line from reader and parse. * Returns null if limit is reached or the reader is invalid. * - * @param ParsedLogLine $parsedlogline * @return ?ParsedLogLine */ private function read() @@ -191,7 +191,7 @@ class ParsedLogIterator implements \Iterator * @see ReversedFileReader::key() * @return int */ - public function key() + public function key(): int { return $this->reader->key(); } @@ -213,8 +213,8 @@ class ParsedLogIterator implements \Iterator * @see Iterator::valid() * @return bool */ - public function valid() + public function valid(): bool { - return ! is_null($this->value); + return !is_null($this->value); } } diff --git a/src/Model/Mail.php b/src/Model/Mail.php index e82a01fbce..afe3a3227a 100644 --- a/src/Model/Mail.php +++ b/src/Model/Mail.php @@ -45,7 +45,7 @@ class Mail * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function insert($msg, $notification = true) + public static function insert(array $msg, bool $notification = true) { if (!isset($msg['reply'])) { $msg['reply'] = DBA::exists('mail', ['parent-uri' => $msg['parent-uri']]); @@ -125,7 +125,7 @@ class Mail * @return int * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function send($recipient = 0, $body = '', $subject = '', $replyto = '') + public static function send(int $recipient = 0, string $body = '', string $subject = '', string $replyto = ''): int { $a = DI::app(); @@ -154,7 +154,7 @@ class Mail Photo::setPermissionFromBody($body, local_user(), $me['id'], '<' . $contact['id'] . '>', '', '', ''); $guid = System::createUUID(); - $uri = Item::newURI(local_user(), $guid); + $uri = Item::newURI($guid); $convid = 0; $reply = false; @@ -255,7 +255,7 @@ class Mail * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function sendWall(array $recipient = [], $body = '', $subject = '', $replyto = '') + public static function sendWall(array $recipient = [], string $body = '', string $subject = '', string $replyto = ''): int { if (!$recipient) { return -1; @@ -266,7 +266,7 @@ class Mail } $guid = System::createUUID(); - $uri = Item::newURI(local_user(), $guid); + $uri = Item::newURI($guid); $me = Contact::getByURL($replyto); if (!$me['name']) { diff --git a/src/Model/Nodeinfo.php b/src/Model/Nodeinfo.php index 2fd05af64a..047fe0e58a 100644 --- a/src/Model/Nodeinfo.php +++ b/src/Model/Nodeinfo.php @@ -22,6 +22,7 @@ namespace Friendica\Model; use Friendica\Core\Addon; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\DBA; use Friendica\DI; use stdClass; @@ -101,7 +102,7 @@ class Nodeinfo * * @return array with supported services */ - public static function getServices() + public static function getServices(): array { $services = [ 'inbound' => [], @@ -156,9 +157,19 @@ class Nodeinfo return $services; } - public static function getOrganization($config) + /** + * Gathers organization information and returns it as an array + * + * @param IManageConfigValues $config Configuration instance + * @return array Organization information + */ + public static function getOrganization(IManageConfigValues $config): array { - $organization = ['name' => null, 'contact' => null, 'account' => null]; + $organization = [ + 'name' => null, + 'contact' => null, + 'account' => null + ]; if (!empty($config->get('config', 'admin_email'))) { $adminList = explode(',', str_replace(' ', '', $config->get('config', 'admin_email'))); diff --git a/src/Model/OpenWebAuthToken.php b/src/Model/OpenWebAuthToken.php index 802e4edf25..b57356a986 100644 --- a/src/Model/OpenWebAuthToken.php +++ b/src/Model/OpenWebAuthToken.php @@ -36,20 +36,19 @@ class OpenWebAuthToken * @param int $uid The user ID. * @param string $token * @param string $meta - * * @return boolean * @throws \Exception */ - public static function create($type, $uid, $token, $meta) + public static function create(string $type, uid $uid, string $token, string $meta) { $fields = [ - "type" => $type, - "uid" => $uid, - "token" => $token, - "meta" => $meta, - "created" => DateTimeFormat::utcNow() + 'type' => $type, + 'uid' => $uid, + 'token' => $token, + 'meta' => $meta, + 'created' => DateTimeFormat::utcNow() ]; - return DBA::insert("openwebauth-token", $fields); + return DBA::insert('openwebauth-token', $fields); } /** @@ -62,15 +61,15 @@ class OpenWebAuthToken * @return string|boolean The meta enry or false if not found. * @throws \Exception */ - public static function getMeta($type, $uid, $token) + public static function getMeta(string $type, int $uid, string $token) { - $condition = ["type" => $type, "uid" => $uid, "token" => $token]; + $condition = ['type' => $type, 'uid' => $uid, 'token' => $token]; - $entry = DBA::selectFirst("openwebauth-token", ["id", "meta"], $condition); + $entry = DBA::selectFirst('openwebauth-token', ['id', 'meta'], $condition); if (DBA::isResult($entry)) { - DBA::delete("openwebauth-token", ["id" => $entry["id"]]); + DBA::delete('openwebauth-token', ['id' => $entry['id']]); - return $entry["meta"]; + return $entry['meta']; } return false; } @@ -80,12 +79,13 @@ class OpenWebAuthToken * * @param string $type Verify type. * @param string $interval SQL compatible time interval + * @return void * @throws \Exception */ - public static function purge($type, $interval) + public static function purge(string $type, string $interval) { - $condition = ["`type` = ? AND `created` < ?", $type, DateTimeFormat::utcNow() . " - INTERVAL " . $interval]; - DBA::delete("openwebauth-token", $condition); + $condition = ["`type` = ? AND `created` < ?", $type, DateTimeFormat::utcNow() . ' - INTERVAL ' . $interval]; + DBA::delete('openwebauth-token', $condition); } } diff --git a/src/Model/Photo.php b/src/Model/Photo.php index d9e6f7cade..096915523c 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -94,7 +94,7 @@ class Photo $fields = self::getFields(); } - return DBA::selectFirst("photo", $fields, $conditions, $params); + return DBA::selectFirst('photo', $fields, $conditions, $params); } /** @@ -110,10 +110,10 @@ class Photo * @throws \Exception * @see \Friendica\Database\DBA::select */ - public static function getPhotosForUser($uid, $resourceid, array $conditions = [], array $params = []) + public static function getPhotosForUser(int $uid, string $resourceid, array $conditions = [], array $params = []) { - $conditions["resource-id"] = $resourceid; - $conditions["uid"] = $uid; + $conditions['resource-id'] = $resourceid; + $conditions['uid'] = $uid; return self::selectToArray([], $conditions, $params); } @@ -132,11 +132,11 @@ class Photo * @throws \Exception * @see \Friendica\Database\DBA::select */ - public static function getPhotoForUser($uid, $resourceid, $scale = 0, array $conditions = [], array $params = []) + public static function getPhotoForUser(int $uid, $resourceid, $scale = 0, array $conditions = [], array $params = []) { - $conditions["resource-id"] = $resourceid; - $conditions["uid"] = $uid; - $conditions["scale"] = $scale; + $conditions['resource-id'] = $resourceid; + $conditions['uid'] = $uid; + $conditions['scale'] = $scale; return self::selectFirst([], $conditions, $params); } @@ -156,19 +156,19 @@ class Photo */ public static function getPhoto(string $resourceid, int $scale = 0) { - $r = self::selectFirst(["uid"], ["resource-id" => $resourceid]); + $r = self::selectFirst(['uid'], ['resource-id' => $resourceid]); if (!DBA::isResult($r)) { return false; } - $uid = $r["uid"]; + $uid = $r['uid']; $accessible = $uid ? (bool)DI::pConfig()->get($uid, 'system', 'accessible-photos', false) : false; $sql_acl = Security::getPermissionsSQLByUserId($uid, $accessible); $conditions = ["`resource-id` = ? AND `scale` <= ? " . $sql_acl, $resourceid, $scale]; - $params = ["order" => ["scale" => true]]; + $params = ['order' => ['scale' => true]]; $photo = self::selectFirst([], $conditions, $params); return $photo; @@ -182,9 +182,9 @@ class Photo * @return boolean * @throws \Exception */ - public static function exists(array $conditions) + public static function exists(array $conditions): bool { - return DBA::exists("photo", $conditions); + return DBA::exists('photo', $conditions); } @@ -193,7 +193,7 @@ class Photo * * @param array $photo Photo data. Needs at least 'id', 'type', 'backend-class', 'backend-ref' * - * @return \Friendica\Object\Image + * @return \Friendica\Object\Image|null Image object or null on error */ public static function getImageDataForPhoto(array $photo) { @@ -248,11 +248,11 @@ class Photo * @return array field list * @throws \Exception */ - private static function getFields() + private static function getFields(): array { - $allfields = DBStructure::definition(DI::app()->getBasePath(), false); - $fields = array_keys($allfields["photo"]["fields"]); - array_splice($fields, array_search("data", $fields), 1); + $allfields = DI::dbaDefinition()->getAll(); + $fields = array_keys($allfields['photo']['fields']); + array_splice($fields, array_search('data', $fields), 1); return $fields; } @@ -265,14 +265,14 @@ class Photo * @return array * @throws \Exception */ - public static function createPhotoForSystemResource($filename, $mimetype = '') + public static function createPhotoForSystemResource(string $filename, string $mimetype = ''): array { if (empty($mimetype)) { $mimetype = Images::guessTypeByExtension($filename); } $fields = self::getFields(); - $values = array_fill(0, count($fields), ""); + $values = array_fill(0, count($fields), ''); $photo = array_combine($fields, $values); $photo['backend-class'] = SystemResource::NAME; @@ -293,14 +293,14 @@ class Photo * @return array * @throws \Exception */ - public static function createPhotoForExternalResource($url, $uid = 0, $mimetype = '') + public static function createPhotoForExternalResource(string $url, int $uid = 0, string $mimetype = ''): array { if (empty($mimetype)) { $mimetype = Images::guessTypeByExtension($url); } $fields = self::getFields(); - $values = array_fill(0, count($fields), ""); + $values = array_fill(0, count($fields), ''); $photo = array_combine($fields, $values); $photo['backend-class'] = ExternalResource::NAME; @@ -314,14 +314,14 @@ class Photo /** * store photo metadata in db and binary in default backend * - * @param Image $Image Image object with data + * @param Image $image Image object with data * @param integer $uid User ID * @param integer $cid Contact ID - * @param integer $rid Resource ID + * @param string $rid Resource ID * @param string $filename Filename * @param string $album Album name * @param integer $scale Scale - * @param integer $profile Is a profile image? optional, default = 0 + * @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 = "" @@ -331,71 +331,71 @@ class Photo * @return boolean True on success * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function store(Image $Image, $uid, $cid, $rid, $filename, $album, $scale, $type = self::DEFAULT, $allow_cid = "", $allow_gid = "", $deny_cid = "", $deny_gid = "", $desc = "") + public static function store(Image $image, int $uid, int $cid, string $rid, string $filename, string $album, int $scale, int $type = self::DEFAULT, string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '', string $desc = ''): bool { - $photo = self::selectFirst(["guid"], ["`resource-id` = ? AND `guid` != ?", $rid, ""]); + $photo = self::selectFirst(['guid'], ["`resource-id` = ? AND `guid` != ?", $rid, '']); if (DBA::isResult($photo)) { - $guid = $photo["guid"]; + $guid = $photo['guid']; } else { $guid = System::createGUID(); } - $existing_photo = self::selectFirst(["id", "created", "backend-class", "backend-ref"], ["resource-id" => $rid, "uid" => $uid, "contact-id" => $cid, "scale" => $scale]); + $existing_photo = self::selectFirst(['id', 'created', 'backend-class', 'backend-ref'], ['resource-id' => $rid, 'uid' => $uid, 'contact-id' => $cid, 'scale' => $scale]); $created = DateTimeFormat::utcNow(); if (DBA::isResult($existing_photo)) { - $created = $existing_photo["created"]; + $created = $existing_photo['created']; } // Get defined storage backend. // if no storage backend, we use old "data" column in photo table. // if is an existing photo, reuse same backend - $data = ""; - $backend_ref = ""; - $storage = ""; + $data = ''; + $backend_ref = ''; + $storage = ''; try { if (DBA::isResult($existing_photo)) { - $backend_ref = (string)$existing_photo["backend-ref"]; - $storage = DI::storageManager()->getWritableStorageByName($existing_photo["backend-class"] ?? ''); + $backend_ref = (string)$existing_photo['backend-ref']; + $storage = DI::storageManager()->getWritableStorageByName($existing_photo['backend-class'] ?? ''); } else { $storage = DI::storage(); } - $backend_ref = $storage->put($Image->asString(), $backend_ref); + $backend_ref = $storage->put($image->asString(), $backend_ref); } catch (InvalidClassStorageException $storageException) { - $data = $Image->asString(); + $data = $image->asString(); } $fields = [ - "uid" => $uid, - "contact-id" => $cid, - "guid" => $guid, - "resource-id" => $rid, - "hash" => md5($Image->asString()), - "created" => $created, - "edited" => DateTimeFormat::utcNow(), - "filename" => basename($filename), - "type" => $Image->getType(), - "album" => $album, - "height" => $Image->getHeight(), - "width" => $Image->getWidth(), - "datasize" => strlen($Image->asString()), - "data" => $data, - "scale" => $scale, - "photo-type" => $type, - "profile" => false, - "allow_cid" => $allow_cid, - "allow_gid" => $allow_gid, - "deny_cid" => $deny_cid, - "deny_gid" => $deny_gid, - "desc" => $desc, - "backend-class" => (string)$storage, - "backend-ref" => $backend_ref + 'uid' => $uid, + 'contact-id' => $cid, + 'guid' => $guid, + 'resource-id' => $rid, + 'hash' => md5($image->asString()), + 'created' => $created, + 'edited' => DateTimeFormat::utcNow(), + 'filename' => basename($filename), + 'type' => $image->getType(), + 'album' => $album, + 'height' => $image->getHeight(), + 'width' => $image->getWidth(), + 'datasize' => strlen($image->asString()), + 'data' => $data, + 'scale' => $scale, + 'photo-type' => $type, + 'profile' => false, + 'allow_cid' => $allow_cid, + 'allow_gid' => $allow_gid, + 'deny_cid' => $deny_cid, + 'deny_gid' => $deny_gid, + 'desc' => $desc, + 'backend-class' => (string)$storage, + 'backend-ref' => $backend_ref ]; if (DBA::isResult($existing_photo)) { - $r = DBA::update("photo", $fields, ["id" => $existing_photo["id"]]); + $r = DBA::update('photo', $fields, ['id' => $existing_photo['id']]); } else { - $r = DBA::insert("photo", $fields); + $r = DBA::insert('photo', $fields); } return $r; @@ -413,7 +413,7 @@ class Photo * @throws \Exception * @see \Friendica\Database\DBA::delete */ - public static function delete(array $conditions, array $options = []) + public static function delete(array $conditions, array $options = []): bool { // get photo to delete data info $photos = DBA::select('photo', ['id', 'backend-class', 'backend-ref'], $conditions); @@ -423,7 +423,7 @@ class Photo $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? ''); $backend_class->delete($photo['backend-ref'] ?? ''); // Delete the photos after they had been deleted successfully - DBA::delete("photo", ['id' => $photo['id']]); + DBA::delete('photo', ['id' => $photo['id']]); } catch (InvalidClassStorageException $storageException) { DI::logger()->debug('Storage class not found.', ['conditions' => $conditions, 'exception' => $storageException]); } catch (ReferenceStorageException $referenceStorageException) { @@ -433,34 +433,34 @@ class Photo DBA::close($photos); - return DBA::delete("photo", $conditions, $options); + return DBA::delete('photo', $conditions, $options); } /** * Update a photo * - * @param array $fields Contains the fields that are updated - * @param array $conditions Condition array with the key values - * @param Image $img Image to update. Optional, default null. - * @param array|boolean $old_fields Array with the old field values that are about to be replaced (true = update on duplicate) + * @param array $fields Contains the fields that are updated + * @param array $conditions Condition array with the key values + * @param Image $image Image to update. Optional, default null. + * @param array $old_fields Array with the old field values that are about to be replaced (true = update on duplicate) * * @return boolean Was the update successfull? * * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @see \Friendica\Database\DBA::update */ - public static function update($fields, $conditions, Image $img = null, array $old_fields = []) + public static function update(array $fields, array $conditions, Image $image = null, array $old_fields = []): bool { - if (!is_null($img)) { + if (!is_null($image)) { // get photo to update $photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions); foreach($photos as $photo) { try { $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? ''); - $fields["backend-ref"] = $backend_class->put($img->asString(), $photo['backend-ref']); + $fields['backend-ref'] = $backend_class->put($image->asString(), $photo['backend-ref']); } catch (InvalidClassStorageException $storageException) { - $fields["data"] = $img->asString(); + $fields['data'] = $image->asString(); } } $fields['updated'] = DateTimeFormat::utcNow(); @@ -468,7 +468,7 @@ class Photo $fields['edited'] = DateTimeFormat::utcNow(); - return DBA::update("photo", $fields, $conditions, $old_fields); + return DBA::update('photo', $fields, $conditions, $old_fields); } /** @@ -476,20 +476,20 @@ class Photo * @param integer $uid user id * @param integer $cid contact id * @param boolean $quit_on_error optional, default false - * @return array + * @return array|bool Array on success, false on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function importProfilePhoto($image_url, $uid, $cid, $quit_on_error = false) + public static function importProfilePhoto(string $image_url, int $uid, int $cid, bool $quit_on_error = false) { - $thumb = ""; - $micro = ""; + $thumb = ''; + $micro = ''; $photo = DBA::selectFirst( - "photo", ["resource-id"], ["uid" => $uid, "contact-id" => $cid, "scale" => 4, "photo-type" => self::CONTACT_AVATAR] + 'photo', ['resource-id'], ['uid' => $uid, 'contact-id' => $cid, 'scale' => 4, 'photo-type' => self::CONTACT_AVATAR] ); if (!empty($photo['resource-id'])) { - $resource_id = $photo["resource-id"]; + $resource_id = $photo['resource-id']; } else { $resource_id = self::newResource(); } @@ -507,66 +507,66 @@ class Photo $type = ''; } - if ($quit_on_error && ($img_str == "")) { + if ($quit_on_error && ($img_str == '')) { return false; } $type = Images::getMimeTypeByData($img_str, $image_url, $type); - $Image = new Image($img_str, $type); - if ($Image->isValid()) { - $Image->scaleToSquare(300); + $image = new Image($img_str, $type); + if ($image->isValid()) { + $image->scaleToSquare(300); - $filesize = strlen($Image->asString()); + $filesize = strlen($image->asString()); $maximagesize = DI::config()->get('system', 'maximagesize'); if (!empty($maximagesize) && ($filesize > $maximagesize)) { - Logger::info('Avatar exceeds image limit', ['uid' => $uid, 'cid' => $cid, 'maximagesize' => $maximagesize, 'size' => $filesize, 'type' => $Image->getType()]); - if ($Image->getType() == 'image/gif') { - $Image->toStatic(); - $Image = new Image($Image->asString(), 'image/png'); + Logger::info('Avatar exceeds image limit', ['uid' => $uid, 'cid' => $cid, 'maximagesize' => $maximagesize, 'size' => $filesize, 'type' => $image->getType()]); + if ($image->getType() == 'image/gif') { + $image->toStatic(); + $image = new Image($image->asString(), 'image/png'); - $filesize = strlen($Image->asString()); - Logger::info('Converted gif to a static png', ['uid' => $uid, 'cid' => $cid, 'size' => $filesize, 'type' => $Image->getType()]); + $filesize = strlen($image->asString()); + Logger::info('Converted gif to a static png', ['uid' => $uid, 'cid' => $cid, 'size' => $filesize, 'type' => $image->getType()]); } if ($filesize > $maximagesize) { foreach ([160, 80] as $pixels) { if ($filesize > $maximagesize) { - Logger::info('Resize', ['uid' => $uid, 'cid' => $cid, 'size' => $filesize, 'max' => $maximagesize, 'pixels' => $pixels, 'type' => $Image->getType()]); - $Image->scaleDown($pixels); - $filesize = strlen($Image->asString()); + Logger::info('Resize', ['uid' => $uid, 'cid' => $cid, 'size' => $filesize, 'max' => $maximagesize, 'pixels' => $pixels, 'type' => $image->getType()]); + $image->scaleDown($pixels); + $filesize = strlen($image->asString()); } } } - Logger::info('Avatar is resized', ['uid' => $uid, 'cid' => $cid, 'size' => $filesize, 'type' => $Image->getType()]); + Logger::info('Avatar is resized', ['uid' => $uid, 'cid' => $cid, 'size' => $filesize, 'type' => $image->getType()]); } - $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 4, self::CONTACT_AVATAR); + $r = self::store($image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 4, self::CONTACT_AVATAR); if ($r === false) { $photo_failure = true; } - $Image->scaleDown(80); + $image->scaleDown(80); - $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 5, self::CONTACT_AVATAR); + $r = self::store($image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 5, self::CONTACT_AVATAR); if ($r === false) { $photo_failure = true; } - $Image->scaleDown(48); + $image->scaleDown(48); - $r = self::store($Image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 6, self::CONTACT_AVATAR); + $r = self::store($image, $uid, $cid, $resource_id, $filename, self::CONTACT_PHOTOS, 6, self::CONTACT_AVATAR); if ($r === false) { $photo_failure = true; } - $suffix = "?ts=" . time(); + $suffix = '?ts=' . time(); - $image_url = DI::baseUrl() . "/photo/" . $resource_id . "-4." . $Image->getExt() . $suffix; - $thumb = DI::baseUrl() . "/photo/" . $resource_id . "-5." . $Image->getExt() . $suffix; - $micro = DI::baseUrl() . "/photo/" . $resource_id . "-6." . $Image->getExt() . $suffix; + $image_url = DI::baseUrl() . '/photo/' . $resource_id . '-4.' . $image->getExt() . $suffix; + $thumb = DI::baseUrl() . '/photo/' . $resource_id . '-5.' . $image->getExt() . $suffix; + $micro = DI::baseUrl() . '/photo/' . $resource_id . '-6.' . $image->getExt() . $suffix; } else { $photo_failure = true; } @@ -586,35 +586,39 @@ class Photo } /** + * Returns a float that represents the GPS coordinate from EXIF data + * * @param array $exifCoord coordinate * @param string $hemi hemi * @return float */ - public static function getGps($exifCoord, $hemi) + public static function getGps(array $exifCoord, string $hemi): float { $degrees = count($exifCoord) > 0 ? self::gps2Num($exifCoord[0]) : 0; $minutes = count($exifCoord) > 1 ? self::gps2Num($exifCoord[1]) : 0; $seconds = count($exifCoord) > 2 ? self::gps2Num($exifCoord[2]) : 0; - $flip = ($hemi == "W" || $hemi == "S") ? -1 : 1; + $flip = ($hemi == 'W' || $hemi == 'S') ? -1 : 1; return floatval($flip * ($degrees + ($minutes / 60) + ($seconds / 3600))); } /** + * Change GPS to float number + * * @param string $coordPart coordPart * @return float */ - private static function gps2Num($coordPart) + private static function gps2Num(string $coordPart): float { - $parts = explode("/", $coordPart); + $parts = explode('/', $coordPart); if (count($parts) <= 0) { return 0; } if (count($parts) == 1) { - return $parts[0]; + return (float)$parts[0]; } return floatval($parts[0]) / floatval($parts[1]); @@ -631,17 +635,18 @@ class Photo * @return array Returns array of the photo albums * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getAlbums($uid, $update = false) + public static function getAlbums(int $uid, bool $update = false): array { $sql_extra = Security::getPermissionsSQLByUserId($uid); $avatar_type = (local_user() && (local_user() == $uid)) ? self::USER_AVATAR : self::DEFAULT; $banner_type = (local_user() && (local_user() == $uid)) ? self::USER_BANNER : self::DEFAULT; - $key = "photo_albums:".$uid.":".local_user().":".remote_user(); + $key = 'photo_albums:' . $uid . ':' . local_user() . ':' . remote_user(); $albums = DI::cache()->get($key); + if (is_null($albums) || $update) { - if (!DI::config()->get("system", "no_count", false)) { + if (!DI::config()->get('system', 'no_count', false)) { /// @todo This query needs to be renewed. It is really slow // At this time we just store the data in the cache $albums = DBA::toArray(DBA::p("SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`, ANY_VALUE(`created`) AS `created` @@ -674,19 +679,19 @@ class Photo * @return void * @throws \Exception */ - public static function clearAlbumCache($uid) + public static function clearAlbumCache(int $uid) { - $key = "photo_albums:".$uid.":".local_user().":".remote_user(); + $key = 'photo_albums:' . $uid . ':' . local_user() . ':' . remote_user(); DI::cache()->set($key, null, Duration::DAY); } /** * Generate a unique photo ID. * - * @return string + * @return string Resource GUID * @throws \Exception */ - public static function newResource() + public static function newResource(): string { return System::createGUID(32, false); } @@ -697,7 +702,7 @@ class Photo * @param string $image_uri The URI of the photo * @return string The rid of the photo, or an empty string if the URI is not local */ - public static function ridFromURI(string $image_uri) + public static function ridFromURI(string $image_uri): string { if (!stristr($image_uri, DI::baseUrl() . '/photo/')) { return ''; @@ -809,7 +814,7 @@ class Photo * @param string $name Picture link * @return array */ - public static function getResourceData(string $name):array + public static function getResourceData(string $name): array { $base = DI::baseUrl()->get(); @@ -840,8 +845,9 @@ class Photo * @return boolean * @throws \Exception */ - public static function isLocal($name) + public static function isLocal(string $name): bool { + // @TODO Maybe a proper check here on true condition? return (bool)self::getIdForName($name); } @@ -851,7 +857,7 @@ class Photo * @param string $name Picture link * @return int */ - public static function getIdForName($name) + public static function getIdForName(string $name): int { $data = self::getResourceData($name); if (empty($data)) { @@ -872,7 +878,7 @@ class Photo * @return boolean * @throws \Exception */ - public static function isLocalPage($name) + public static function isLocalPage(string $name): bool { $base = DI::baseUrl()->get(); @@ -885,17 +891,23 @@ class Photo return DBA::exists('photo', ['resource-id' => $guid]); } - private static function fitImageSize($Image) + /** + * Tries to resize image to wanted maximum size + * + * @param Image $image Image instance + * @return Image|null Image instance on success, null on error + */ + private static function fitImageSize(Image $image) { $max_length = DI::config()->get('system', 'max_image_length'); if ($max_length > 0) { - $Image->scaleDown($max_length); + $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(); + $filesize = strlen($image->asString()); + $width = $image->getWidth(); + $height = $image->getHeight(); $maximagesize = DI::config()->get('system', 'maximagesize'); @@ -904,10 +916,10 @@ class Photo 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(); + $image->scaleDown($pixels); + $filesize = strlen($image->asString()); + $width = $image->getWidth(); + $height = $image->getHeight(); } } if ($filesize > $maximagesize) { @@ -916,10 +928,16 @@ class Photo } } - return $Image; + return $image; } - private static function loadImageFromURL(string $image_url) + /** + * Fetches image from URL and returns an array with instance and local file name + * + * @param string $image_url URL to image + * @return array With: 'image' and 'filename' fields or empty array on error + */ + private static function loadImageFromURL(string $image_url): array { $filename = basename($image_url); if (!empty($image_url)) { @@ -939,17 +957,23 @@ class Photo $type = Images::getMimeTypeByData($img_str, $image_url, $type); - $Image = new Image($img_str, $type); + $image = new Image($img_str, $type); - $Image = self::fitImageSize($Image); - if (empty($Image)) { + $image = self::fitImageSize($image); + if (empty($image)) { return []; } - return ['image' => $Image, 'filename' => $filename]; + return ['image' => $image, 'filename' => $filename]; } - private static function uploadImage(array $files) + /** + * Inserts uploaded image into database and removes local temporary file + * + * @param array $files File array + * @return array With 'image' for Image instance and 'filename' for local file name or empty array on error + */ + private static function uploadImage(array $files): array { Logger::info('starting new upload'); @@ -1008,34 +1032,36 @@ class Photo Logger::info('File upload', ['src' => $src, 'filename' => $filename, 'size' => $filesize, 'type' => $filetype]); $imagedata = @file_get_contents($src); - $Image = new Image($imagedata, $filetype); - if (!$Image->isValid()) { + $image = new Image($imagedata, $filetype); + if (!$image->isValid()) { Logger::notice('Image is unvalid', ['files' => $files]); return []; } - $Image->orient($src); + $image->orient($src); @unlink($src); - $Image = self::fitImageSize($Image); - if (empty($Image)) { + $image = self::fitImageSize($image); + if (empty($image)) { return []; } - return ['image' => $Image, 'filename' => $filename]; + return ['image' => $image, 'filename' => $filename]; } /** + * Handles uploaded image and assigns it to given user id + * * @param int $uid User ID * @param array $files uploaded file array - * @param string $album + * @param string $album Album name (optional) * @param string|null $allow_cid * @param string|null $allow_gid * @param string $deny_cid * @param string $deny_gid - * @param string $desc - * @param string $resource_id - * @return array photo record + * @param string $desc Description (optional) + * @param string $resource_id GUID (optional) + * @return array photo record or empty array on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function upload(int $uid, array $files, string $album = '', string $allow_cid = null, string $allow_gid = null, string $deny_cid = '', string $deny_gid = '', string $desc = '', string $resource_id = ''): array @@ -1052,10 +1078,10 @@ class Photo return []; } - $Image = $data['image']; + $image = $data['image']; $filename = $data['filename']; - $width = $Image->getWidth(); - $height = $Image->getHeight(); + $width = $image->getWidth(); + $height = $image->getHeight(); $resource_id = $resource_id ?: self::newResource(); $album = $album ?: DI::l10n()->t('Wall Photos'); @@ -1067,23 +1093,23 @@ class Photo $smallest = 0; - $r = self::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 0, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); + $r = self::store($image, $user['uid'], 0, $resource_id, $filename, $album, 0, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); if (!$r) { Logger::notice('Photo could not be stored'); return []; } if ($width > 640 || $height > 640) { - $Image->scaleDown(640); - $r = self::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 1, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); + $image->scaleDown(640); + $r = self::store($image, $user['uid'], 0, $resource_id, $filename, $album, 1, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); if ($r) { $smallest = 1; } } if ($width > 320 || $height > 320) { - $Image->scaleDown(320); - $r = self::store($Image, $user['uid'], 0, $resource_id, $filename, $album, 2, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); + $image->scaleDown(320); + $r = self::store($image, $user['uid'], 0, $resource_id, $filename, $album, 2, self::DEFAULT, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $desc); if ($r && ($smallest == 0)) { $smallest = 2; } @@ -1105,8 +1131,8 @@ class Photo $picture['height'] = $photo['height']; $picture['type'] = $photo['type']; $picture['albumpage'] = DI::baseUrl() . '/photos/' . $user['nickname'] . '/image/' . $resource_id; - $picture['picture'] = DI::baseUrl() . '/photo/{$resource_id}-0.' . $Image->getExt(); - $picture['preview'] = DI::baseUrl() . '/photo/{$resource_id}-{$smallest}.' . $Image->getExt(); + $picture['picture'] = DI::baseUrl() . '/photo/{$resource_id}-0.' . $image->getExt(); + $picture['preview'] = DI::baseUrl() . '/photo/{$resource_id}-{$smallest}.' . $image->getExt(); Logger::info('upload done', ['picture' => $picture]); return $picture; @@ -1139,10 +1165,10 @@ class Photo return ''; } - $Image = $data['image']; + $image = $data['image']; $filename = $data['filename']; - $width = $Image->getWidth(); - $height = $Image->getHeight(); + $width = $image->getWidth(); + $height = $image->getHeight(); $resource_id = self::newResource(); $album = DI::l10n()->t(self::PROFILE_PHOTOS); @@ -1151,28 +1177,28 @@ class Photo logger::info('starting new profile image upload'); if ($width > 300 || $height > 300) { - $Image->scaleDown(300); + $image->scaleDown(300); } - $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 4, self::USER_AVATAR); + $r = self::store($image, $uid, 0, $resource_id, $filename, $album, 4, self::USER_AVATAR); if (!$r) { logger::notice('profile image upload with scale 4 (300) failed'); } if ($width > 80 || $height > 80) { - $Image->scaleDown(80); + $image->scaleDown(80); } - $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 5, self::USER_AVATAR); + $r = self::store($image, $uid, 0, $resource_id, $filename, $album, 5, self::USER_AVATAR); if (!$r) { logger::notice('profile image upload with scale 5 (80) failed'); } if ($width > 48 || $height > 48) { - $Image->scaleDown(48); + $image->scaleDown(48); } - $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 6, self::USER_AVATAR); + $r = self::store($image, $uid, 0, $resource_id, $filename, $album, 6, self::USER_AVATAR); if (!$r) { logger::notice('profile image upload with scale 6 (48) failed'); } @@ -1217,19 +1243,19 @@ class Photo return ''; } - $Image = $data['image']; + $image = $data['image']; $filename = $data['filename']; - $width = $Image->getWidth(); - $height = $Image->getHeight(); + $width = $image->getWidth(); + $height = $image->getHeight(); $resource_id = self::newResource(); $album = DI::l10n()->t(self::BANNER_PHOTOS); if ($width > 960) { - $Image->scaleDown(960); + $image->scaleDown(960); } - $r = self::store($Image, $uid, 0, $resource_id, $filename, $album, 3, self::USER_BANNER); + $r = self::store($image, $uid, 0, $resource_id, $filename, $album, 3, self::USER_BANNER); if (!$r) { logger::notice('profile banner upload with scale 3 (960) failed'); } @@ -1247,3 +1273,4 @@ class Photo return $resource_id; } } + diff --git a/src/Model/Post.php b/src/Model/Post.php index 93a990a37e..2b71e2f142 100644 --- a/src/Model/Post.php +++ b/src/Model/Post.php @@ -27,6 +27,7 @@ use Friendica\Core\System; use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\DI; use Friendica\Protocol\Activity; class Post @@ -39,13 +40,13 @@ class Post * @return int ID of inserted post * @throws \Exception */ - public static function insert(int $uri_id, array $data = []) + public static function insert(int $uri_id, array $data = []): int { if (empty($uri_id)) { throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post', $data); // Additionally assign the key fields $fields['uri-id'] = $uri_id; @@ -107,8 +108,10 @@ class Post * @param object $stmt statement object * @param bool $do_close * @return array Data array + * @todo Find proper type-hint for $stmt and maybe avoid boolean */ - public static function toArray($stmt, $do_close = true) { + public static function toArray($stmt, bool $do_close = true) + { if (is_bool($stmt)) { return $stmt; } @@ -131,7 +134,8 @@ class Post * @return boolean Are there rows for that condition? * @throws \Exception */ - public static function exists($condition) { + public static function exists(array $condition): bool + { return DBA::exists('post-user-view', $condition); } @@ -151,7 +155,7 @@ class Post * $count = Post::count($condition); * @throws \Exception */ - public static function count(array $condition = [], array $params = []) + public static function count(array $condition = [], array $params = []): int { return DBA::count('post-user-view', $condition, $params); } @@ -172,7 +176,7 @@ class Post * $count = Post::count($condition); * @throws \Exception */ - public static function countThread(array $condition = [], array $params = []) + public static function countThread(array $condition = [], array $params = []): int { return DBA::count('post-thread-user-view', $condition, $params); } @@ -193,7 +197,7 @@ class Post * $count = Post::count($condition); * @throws \Exception */ - public static function countPosts(array $condition = [], array $params = []) + public static function countPosts(array $condition = [], array $params = []): int { return DBA::count('post-view', $condition, $params); } @@ -209,7 +213,7 @@ class Post * @throws \Exception * @see DBA::select */ - public static function selectFirst(array $fields = [], array $condition = [], $params = []) + public static function selectFirst(array $fields = [], array $condition = [], array $params = []) { $params['limit'] = 1; @@ -234,7 +238,7 @@ class Post * @throws \Exception * @see DBA::select */ - public static function selectFirstPost(array $fields = [], array $condition = [], $params = []) + public static function selectFirstPost(array $fields = [], array $condition = [], array $params = []) { $params['limit'] = 1; @@ -259,7 +263,7 @@ class Post * @throws \Exception * @see DBA::select */ - public static function selectFirstThread(array $fields = [], array $condition = [], $params = []) + public static function selectFirstThread(array $fields = [], array $condition = [], array $params = []) { $params['limit'] = 1; @@ -284,7 +288,7 @@ class Post * @return array * @throws \Exception */ - public static function selectToArray(array $fields = [], array $condition = [], $params = []) + public static function selectToArray(array $fields = [], array $condition = [], array $params = []) { $result = self::select($fields, $condition, $params); @@ -312,7 +316,7 @@ class Post * @return boolean|object * @throws \Exception */ - private static function selectView(string $view, array $selected = [], array $condition = [], $params = []) + private static function selectView(string $view, array $selected = [], array $condition = [], array $params = []) { if (empty($selected)) { $selected = array_merge(Item::DISPLAY_FIELDLIST, Item::ITEM_FIELDLIST); @@ -337,7 +341,7 @@ class Post * @return boolean|object * @throws \Exception */ - public static function select(array $selected = [], array $condition = [], $params = []) + public static function select(array $selected = [], array $condition = [], array $params = []) { return self::selectView('post-user-view', $selected, $condition, $params); } @@ -352,7 +356,7 @@ class Post * @return boolean|object * @throws \Exception */ - public static function selectPosts(array $selected = [], array $condition = [], $params = []) + public static function selectPosts(array $selected = [], array $condition = [], array $params = []) { return self::selectView('post-view', $selected, $condition, $params); } @@ -367,7 +371,7 @@ class Post * @return boolean|object * @throws \Exception */ - public static function selectThread(array $selected = [], array $condition = [], $params = []) + public static function selectThread(array $selected = [], array $condition = [], array $params = []) { return self::selectView('post-thread-user-view', $selected, $condition, $params); } @@ -384,7 +388,7 @@ class Post * @return boolean|object * @throws \Exception */ - private static function selectViewForUser(string $view, $uid, array $selected = [], array $condition = [], $params = []) + private static function selectViewForUser(string $view, int $uid, array $selected = [], array $condition = [], array $params = []) { if (empty($selected)) { $selected = Item::DISPLAY_FIELDLIST; @@ -425,7 +429,7 @@ class Post * @return boolean|object * @throws \Exception */ - public static function selectForUser($uid, array $selected = [], array $condition = [], $params = []) + public static function selectForUser(int $uid, array $selected = [], array $condition = [], array $params = []) { return self::selectViewForUser('post-user-view', $uid, $selected, $condition, $params); } @@ -441,7 +445,7 @@ class Post * @return boolean|object * @throws \Exception */ - public static function selectPostsForUser($uid, array $selected = [], array $condition = [], $params = []) + public static function selectPostsForUser(int $uid, array $selected = [], array $condition = [], array $params = []) { return self::selectViewForUser('post-view', $uid, $selected, $condition, $params); } @@ -457,7 +461,7 @@ class Post * @return boolean|object * @throws \Exception */ - public static function selectThreadForUser($uid, array $selected = [], array $condition = [], $params = []) + public static function selectThreadForUser(int $uid, array $selected = [], array $condition = [], array $params = []) { return self::selectViewForUser('post-thread-user-view', $uid, $selected, $condition, $params); } @@ -473,7 +477,7 @@ class Post * @throws \Exception * @see DBA::select */ - public static function selectFirstForUser($uid, array $selected = [], array $condition = [], $params = []) + public static function selectFirstForUser(int $uid, array $selected = [], array $condition = [], array $params = []) { $params['limit'] = 1; @@ -521,7 +525,7 @@ class Post // To ensure the data integrity we do it in an transaction DBA::transaction(); - $update_fields = DBStructure::getFieldsForTable('post-user', $fields); + $update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-user', $fields); if (!empty($update_fields)) { $affected_count = 0; $posts = DBA::select('post-user-view', ['post-user-id'], $condition); @@ -538,7 +542,7 @@ class Post $affected = $affected_count; } - $update_fields = DBStructure::getFieldsForTable('post-content', $fields); + $update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-content', $fields); if (!empty($update_fields)) { $affected_count = 0; $posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); @@ -555,7 +559,7 @@ class Post $affected = max($affected, $affected_count); } - $update_fields = DBStructure::getFieldsForTable('post', $fields); + $update_fields = DI::dbaDefinition()->truncateFieldsForTable('post', $fields); if (!empty($update_fields)) { $affected_count = 0; $posts = DBA::select('post-user-view', ['uri-id'], $condition, ['group_by' => ['uri-id']]); @@ -589,7 +593,7 @@ class Post $affected = max($affected, $affected_count); } - $update_fields = DBStructure::getFieldsForTable('post-thread', $fields); + $update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread', $fields); if (!empty($update_fields)) { $affected_count = 0; $posts = DBA::select('post-user-view', ['uri-id'], $thread_condition, ['group_by' => ['uri-id']]); @@ -606,7 +610,7 @@ class Post $affected = max($affected, $affected_count); } - $update_fields = DBStructure::getFieldsForTable('post-thread-user', $fields); + $update_fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread-user', $fields); if (!empty($update_fields)) { $affected_count = 0; $posts = DBA::select('post-user-view', ['post-user-id'], $thread_condition); @@ -640,7 +644,7 @@ class Post * @return boolean was the delete successful? * @throws \Exception */ - public static function delete(array $conditions, array $options = []) + public static function delete(array $conditions, array $options = []): bool { return DBA::delete('post', $conditions, $options); } diff --git a/src/Model/Post/Content.php b/src/Model/Post/Content.php index 3a5c32810c..63ea9b8cd1 100644 --- a/src/Model/Post/Content.php +++ b/src/Model/Post/Content.php @@ -26,6 +26,7 @@ use Friendica\Core\Protocol; use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\DI; use Friendica\Model\Post; class Content @@ -44,7 +45,7 @@ class Content throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-content', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-content', $data); // Additionally assign the key fields $fields['uri-id'] = $uri_id; @@ -67,7 +68,7 @@ class Content throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-content', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-content', $data); // Remove the key fields unset($fields['uri-id']); diff --git a/src/Model/Post/History.php b/src/Model/Post/History.php index 24ee7c1e7d..e7699e20c9 100644 --- a/src/Model/Post/History.php +++ b/src/Model/Post/History.php @@ -24,7 +24,7 @@ namespace Friendica\Model\Post; use Friendica\Core\Logger; use Friendica\Database\DBA; use Friendica\Database\Database; -use Friendica\Database\DBStructure; +use Friendica\DI; use Friendica\Model\Post; class History @@ -37,7 +37,7 @@ class History */ public static function add(int $uri_id, array $item) { - $allfields = DBStructure::definition('', false); + $allfields = DI::dbaDefinition()->getAll(); $fields = array_keys($allfields['post-history']['fields']); $post = Post::selectFirstPost($fields, ['uri-id' => $uri_id]); @@ -52,7 +52,7 @@ class History } $update = false; - $changed = DBStructure::getFieldsForTable('post-history', $item); + $changed = DI::dbaDefinition()->truncateFieldsForTable('post-history', $item); unset($changed['uri-id']); unset($changed['edited']); foreach ($changed as $field => $content) { diff --git a/src/Model/Post/Link.php b/src/Model/Post/Link.php index fb7d0edb8d..83e5da7b31 100644 --- a/src/Model/Post/Link.php +++ b/src/Model/Post/Link.php @@ -40,36 +40,44 @@ class Link /** * Check if the link is stored * - * @param int $uri_id - * @param string $url - * @return bool + * @param int $uriId + * @param string $url URL + * @return bool Whether record has been found */ - public static function exists(int $uri_id, string $url) + public static function exists(int $uriId, string $url): bool { - return DBA::exists('post-link', ['uri-id' => $uri_id, 'url' => $url]); + return DBA::exists('post-link', ['uri-id' => $uriId, 'url' => $url]); } - public static function getByLink(int $uri_id, string $url, $size = '') + /** + * Returns URL by URI id and other URL + * + * @param int $uriId + * @param string $url + * @param string $size + * @return string Found link URL + id on success, $url on failture + */ + public static function getByLink(int $uriId, string $url, string $size = ''): string { - if (empty($uri_id) || empty($url) || Proxy::isLocalImage($url)) { + if (empty($uriId) || empty($url) || Proxy::isLocalImage($url)) { return $url; } if (!in_array(parse_url($url, PHP_URL_SCHEME), ['http', 'https'])) { - Logger::info('Bad URL, quitting', ['uri-id' => $uri_id, 'url' => $url, 'callstack' => System::callstack(20)]); + Logger::info('Bad URL, quitting', ['uri-id' => $uriId, 'url' => $url, 'callstack' => System::callstack(20)]); return $url; } - $link = DBA::selectFirst('post-link', ['id'], ['uri-id' => $uri_id, 'url' => $url]); + $link = DBA::selectFirst('post-link', ['id'], ['uri-id' => $uriId, 'url' => $url]); if (!empty($link['id'])) { $id = $link['id']; - Logger::info('Found', ['id' => $id, 'uri-id' => $uri_id, 'url' => $url]); + Logger::info('Found', ['id' => $id, 'uri-id' => $uriId, 'url' => $url]); } else { $mime = self::fetchMimeType($url); - DBA::insert('post-link', ['uri-id' => $uri_id, 'url' => $url, 'mimetype' => $mime], Database::INSERT_IGNORE); + DBA::insert('post-link', ['uri-id' => $uriId, 'url' => $url, 'mimetype' => $mime], Database::INSERT_IGNORE); $id = DBA::lastInsertId(); - Logger::info('Inserted', ['id' => $id, 'uri-id' => $uri_id, 'url' => $url]); + Logger::info('Inserted', ['id' => $id, 'uri-id' => $uriId, 'url' => $url]); } if (empty($id)) { @@ -81,15 +89,19 @@ class Link case Proxy::SIZE_MICRO: $url .= Proxy::PIXEL_MICRO . '/'; break; + case Proxy::SIZE_THUMB: $url .= Proxy::PIXEL_THUMB . '/'; break; + case Proxy::SIZE_SMALL: $url .= Proxy::PIXEL_SMALL . '/'; break; + case Proxy::SIZE_MEDIUM: $url .= Proxy::PIXEL_MEDIUM . '/'; break; + case Proxy::SIZE_LARGE: $url .= Proxy::PIXEL_LARGE . '/'; break; @@ -97,43 +109,50 @@ class Link return $url . $id; } - private static function fetchMimeType(string $url, string $accept = HttpClientAccept::DEFAULT) + /** + * Fetches MIME type by URL and Accept: header + * + * @param string $url URL to fetch + * @param string $accept Comma-separated list of expected response MIME type(s) + * @return string Discovered MIME type or empty string on failure + */ + private static function fetchMimeType(string $url, string $accept = HttpClientAccept::DEFAULT): string { $timeout = DI::config()->get('system', 'xrd_timeout'); $curlResult = DI::httpClient()->head($url, [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::ACCEPT_CONTENT => $accept]); - if ($curlResult->isSuccess()) { - if (empty($media['mimetype'])) { - return $curlResult->getHeader('Content-Type')[0] ?? ''; - } + + if ($curlResult->isSuccess() && empty($media['mimetype'])) { + return $curlResult->getHeader('Content-Type')[0] ?? ''; } + return ''; } /** * Add external links and replace them in the body * - * @param integer $uriid - * @param string $body + * @param integer $uriId + * @param string $body Item body formatted with BBCodes * @return string Body with replaced links */ - public static function insertFromBody(int $uriid, string $body) + public static function insertFromBody(int $uriId, string $body): string { if (preg_match_all("/\[img\=([0-9]*)x([0-9]*)\](http.*?)\[\/img\]/ism", $body, $pictures, PREG_SET_ORDER)) { foreach ($pictures as $picture) { - $body = str_replace($picture[3], self::getByLink($uriid, $picture[3]), $body); + $body = str_replace($picture[3], self::getByLink($uriId, $picture[3]), $body); } } if (preg_match_all("/\[img=(http[^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { foreach ($pictures as $picture) { - $body = str_replace($picture[1], self::getByLink($uriid, $picture[1]), $body); + $body = str_replace($picture[1], self::getByLink($uriId, $picture[1]), $body); } } if (preg_match_all("/\[img\](http[^\[\]]*)\[\/img\]/ism", $body, $pictures, PREG_SET_ORDER)) { foreach ($pictures as $picture) { - $body = str_replace($picture[1], self::getByLink($uriid, $picture[1]), $body); + $body = str_replace($picture[1], self::getByLink($uriId, $picture[1]), $body); } } diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 78f27b7a09..3b23e5d0fe 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -109,7 +109,7 @@ class Media * @param array $media * @return array cleaned media array */ - private static function unsetEmptyFields(array $media) + private static function unsetEmptyFields(array $media): array { $fields = ['mimetype', 'height', 'width', 'size', 'preview', 'preview-height', 'preview-width', 'description']; foreach ($fields as $field) { @@ -145,7 +145,7 @@ class Media * @param string $title * @return string "[attach]" element */ - public static function getAttachElement(string $href, int $length, string $type, string $title = '') + public static function getAttachElement(string $href, int $length, string $type, string $title = ''): string { $media = self::fetchAdditionalData(['type' => self::DOCUMENT, 'url' => $href, 'size' => $length, 'mimetype' => $type, 'description' => $title]); @@ -160,7 +160,7 @@ class Media * @param array $media * @return array media array with additional data */ - public static function fetchAdditionalData(array $media) + public static function fetchAdditionalData(array $media): array { if (Network::isLocalLink($media['url'])) { $media = self::fetchLocalData($media); @@ -192,7 +192,7 @@ class Media if (($media['type'] == self::IMAGE) || ($filetype == 'image')) { $imagedata = Images::getInfoFromURLCached($media['url']); - if (!empty($imagedata)) { + if ($imagedata) { $media['mimetype'] = $imagedata['mime']; $media['size'] = $imagedata['size']; $media['width'] = $imagedata[0]; @@ -202,7 +202,7 @@ class Media } if (!empty($media['preview'])) { $imagedata = Images::getInfoFromURLCached($media['preview']); - if (!empty($imagedata)) { + if ($imagedata) { $media['preview-width'] = $imagedata[0]; $media['preview-height'] = $imagedata[1]; } @@ -235,7 +235,7 @@ class Media * @param array $media * @return array media with added data */ - private static function fetchLocalData(array $media) + private static function fetchLocalData(array $media): array { if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['url'] ?? '', $matches)) { return $media; @@ -266,7 +266,7 @@ class Media * @param array $data * @return array data array with the detected type */ - public static function addType(array $data) + public static function addType(array $data): array { if (empty($data['mimetype'])) { Logger::info('No MimeType provided', ['media' => $data]); @@ -318,7 +318,7 @@ class Media * @param string $preview Preview picture * @return boolean */ - private static function isPictureLink(string $page, string $preview) + private static function isPictureLink(string $page, string $preview): bool { return preg_match('#/photos/.*/image/#ism', $page) && preg_match('#/photo/.*-1\.#ism', $preview); } @@ -330,7 +330,7 @@ class Media * @param string $body * @return string Body without media links */ - public static function insertFromBody(int $uriid, string $body) + public static function insertFromBody(int $uriid, string $body): string { // Simplify image codes $unshared_body = $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); @@ -413,6 +413,7 @@ class Media * * @param integer $uriid * @param string $body + * @return void */ public static function insertFromRelevantUrl(int $uriid, string $body) { @@ -448,6 +449,7 @@ class Media * * @param integer $uriid * @param string $body + * @return void */ public static function insertFromAttachmentData(int $uriid, string $body) { @@ -506,9 +508,9 @@ class Media /** * Retrieves the media attachments associated with the provided item ID. * - * @param int $uri_id - * @param array $types - * @return array + * @param int $uri_id URI id + * @param array $types Media types + * @return array|bool Array on success, false on error * @throws \Exception */ public static function getByURIId(int $uri_id, array $types = []) @@ -525,12 +527,12 @@ class Media /** * Checks if media attachments are associated with the provided item ID. * - * @param int $uri_id - * @param array $types - * @return array + * @param int $uri_id URI id + * @param array $types Media types + * @return bool Whether media attachment exists * @throws \Exception */ - public static function existsByURIId(int $uri_id, array $types = []) + public static function existsByURIId(int $uri_id, array $types = []): bool { $condition = ['uri-id' => $uri_id]; @@ -544,13 +546,13 @@ class Media /** * Split the attachment media in the three segments "visual", "link" and "additional" * - * @param int $uri_id - * @param string $guid + * @param int $uri_id URI id + * @param string $guid GUID * @param array $links list of links that shouldn't be added * @param bool $has_media * @return array attachments */ - public static function splitAttachments(int $uri_id, string $guid = '', array $links = [], bool $has_media = true) + public static function splitAttachments(int $uri_id, string $guid = '', array $links = [], bool $has_media = true): array { $attachments = ['visual' => [], 'link' => [], 'additional' => []]; @@ -648,7 +650,7 @@ class Media * @param string $body * @return string body */ - public static function addAttachmentsToBody(int $uriid, string $body = '') + public static function addAttachmentsToBody(int $uriid, string $body = ''): string { if (empty($body)) { $item = Post::selectFirst(['body'], ['uri-id' => $uriid]); @@ -701,7 +703,7 @@ class Media * @param string $size One of the Proxy::SIZE_* constants * @return string preview link */ - public static function getPreviewUrlForId(int $id, string $size = ''):string + public static function getPreviewUrlForId(int $id, string $size = ''): string { $url = DI::baseUrl() . '/photo/preview/'; switch ($size) { @@ -731,7 +733,7 @@ class Media * @param string $size One of the Proxy::SIZE_* constants * @return string media link */ - public static function getUrlForId(int $id, string $size = ''):string + public static function getUrlForId(int $id, string $size = ''): string { $url = DI::baseUrl() . '/photo/media/'; switch ($size) { diff --git a/src/Model/Post/Question.php b/src/Model/Post/Question.php index db0d755b7f..6729e9f526 100644 --- a/src/Model/Post/Question.php +++ b/src/Model/Post/Question.php @@ -24,6 +24,7 @@ namespace Friendica\Model\Post; use BadMethodCallException; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\DI; class Question { @@ -42,7 +43,7 @@ class Question throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-question', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-question', $data); // Remove the key fields unset($fields['uri-id']); diff --git a/src/Model/Post/QuestionOption.php b/src/Model/Post/QuestionOption.php index 641c8f2ccf..88617b21fc 100644 --- a/src/Model/Post/QuestionOption.php +++ b/src/Model/Post/QuestionOption.php @@ -24,6 +24,7 @@ namespace Friendica\Model\Post; use BadMethodCallException; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\DI; class QuestionOption { @@ -43,7 +44,7 @@ class QuestionOption throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-question-option', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-question-option', $data); // Remove the key fields unset($fields['uri-id']); diff --git a/src/Model/Post/Thread.php b/src/Model/Post/Thread.php index ab7900ad82..002b5ecb58 100644 --- a/src/Model/Post/Thread.php +++ b/src/Model/Post/Thread.php @@ -25,6 +25,7 @@ use \BadMethodCallException; use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\DI; class Thread { @@ -42,7 +43,7 @@ class Thread throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-thread', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread', $data); // Additionally assign the key fields $fields['uri-id'] = $uri_id; @@ -65,7 +66,7 @@ class Thread throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-thread', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread', $data); // Remove the key fields unset($fields['uri-id']); diff --git a/src/Model/Post/ThreadUser.php b/src/Model/Post/ThreadUser.php index 0de26abc58..a6a3bbd92b 100644 --- a/src/Model/Post/ThreadUser.php +++ b/src/Model/Post/ThreadUser.php @@ -25,6 +25,7 @@ use \BadMethodCallException; use Friendica\Database\Database; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\DI; class ThreadUser { @@ -43,7 +44,7 @@ class ThreadUser throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-thread-user', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread-user', $data); // Additionally assign the key fields $fields['uri-id'] = $uri_id; @@ -68,7 +69,7 @@ class ThreadUser throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-thread-user', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread-user', $data); // Remove the key fields unset($fields['uri-id']); diff --git a/src/Model/Post/User.php b/src/Model/Post/User.php index 0da3062a0b..9da9718068 100644 --- a/src/Model/Post/User.php +++ b/src/Model/Post/User.php @@ -25,6 +25,7 @@ use Friendica\Database\DBA; use \BadMethodCallException; use Friendica\Database\Database; use Friendica\Database\DBStructure; +use Friendica\DI; class User { @@ -47,7 +48,7 @@ class User return false; } - $fields = DBStructure::getFieldsForTable('post-user', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-user', $data); // Additionally assign the key fields $fields['uri-id'] = $uri_id; @@ -81,7 +82,7 @@ class User throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-user', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-user', $data); // Remove the key fields unset($fields['uri-id']); diff --git a/src/Model/Post/UserNotification.php b/src/Model/Post/UserNotification.php index 005dd7084a..4a57ff6ff5 100644 --- a/src/Model/Post/UserNotification.php +++ b/src/Model/Post/UserNotification.php @@ -67,7 +67,7 @@ class UserNotification throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-user-notification', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-user-notification', $data); $fields['uri-id'] = $uri_id; $fields['uid'] = $uid; @@ -91,7 +91,7 @@ class UserNotification throw new BadMethodCallException('Empty URI_id'); } - $fields = DBStructure::getFieldsForTable('post-user-notification', $data); + $fields = DI::dbaDefinition()->truncateFieldsForTable('post-user-notification', $data); // Remove the key fields unset($fields['uri-id']); diff --git a/src/Model/Profile.php b/src/Model/Profile.php index aa027a860b..a3dcc60b1c 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -54,10 +54,10 @@ class Profile * * @param integer User ID * - * @return array Profile data + * @return array|bool Profile data or false on error * @throws \Exception */ - public static function getByUID($uid) + public static function getByUID(int $uid) { return DBA::selectFirst('profile', [], ['uid' => $uid]); } @@ -69,7 +69,7 @@ class Profile * @param int $id The contact owner ID * @param array $fields The selected fields * - * @return array Profile data for the ID + * @return array|bool Profile data for the ID or false on error * @throws \Exception */ public static function getById(int $uid, int $id, array $fields = []) @@ -81,7 +81,7 @@ class Profile * Returns profile data for the contact owner * * @param int $uid The User ID - * @param array $fields The fields to retrieve + * @param array|bool $fields The fields to retrieve or false on error * * @return array Array of profile data * @throws \Exception @@ -94,9 +94,9 @@ class Profile /** * Update a profile entry and distribute the changes if needed * - * @param array $fields - * @param integer $uid - * @return boolean + * @param array $fields Profile fields to update + * @param integer $uid User id + * @return boolean Whether update was successful */ public static function update(array $fields, int $uid): bool { @@ -136,8 +136,10 @@ class Profile /** * Publish a changed profile - * @param int $uid + * + * @param int $uid User id * @param bool $force Force publishing to the directory + * @return void */ public static function publishUpdate(int $uid, bool $force = false) { @@ -160,10 +162,9 @@ class Profile * Returns a formatted location string from the given profile array * * @param array $profile Profile array (Generated from the "profile" table) - * * @return string Location string */ - public static function formatLocation(array $profile) + public static function formatLocation(array $profile): string { $location = ''; @@ -237,7 +238,7 @@ class Profile if (!local_user()) { $a->setCurrentTheme($profile['theme']); - $a->setCurrentMobileTheme(DI::pConfig()->get($a->getProfileOwner(), 'system', 'mobile_theme')); + $a->setCurrentMobileTheme(DI::pConfig()->get($a->getProfileOwner(), 'system', 'mobile_theme') ?? ''); } /* diff --git a/src/Model/PushSubscriber.php b/src/Model/PushSubscriber.php index 51d48d9b23..8aa67eee5f 100644 --- a/src/Model/PushSubscriber.php +++ b/src/Model/PushSubscriber.php @@ -34,9 +34,10 @@ class PushSubscriber * * @param integer $uid User ID * @param int $default_priority + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function publishFeed($uid, $default_priority = PRIORITY_HIGH) + public static function publishFeed(int $uid, int $default_priority = PRIORITY_HIGH) { $condition = ['push' => 0, 'uid' => $uid]; DBA::update('push_subscriber', ['push' => 1, 'next_try' => DBA::NULL_DATETIME], $condition); @@ -48,9 +49,10 @@ class PushSubscriber * start workers to transmit the feed data * * @param int $default_priority + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function requeue($default_priority = PRIORITY_HIGH) + public static function requeue(int $default_priority = PRIORITY_HIGH) { // We'll push to each subscriber that has push > 0, // i.e. there has been an update (set in notifier.php). @@ -80,9 +82,10 @@ class PushSubscriber * @param string $hub_callback Callback address * @param string $hub_topic Feed topic * @param string $hub_secret Subscription secret + * @return void * @throws \Exception */ - public static function renew($uid, $nick, $subscribe, $hub_callback, $hub_topic, $hub_secret) + public static function renew(int $uid, string $nick, int $subscribe, string $hub_callback, string $hub_topic, string $hub_secret) { // fetch the old subscription if it exists $subscriber = DBA::selectFirst('push_subscriber', ['last_update', 'push'], ['callback_url' => $hub_callback]); @@ -119,9 +122,10 @@ class PushSubscriber * Delay the push subscriber * * @param integer $id Subscriber ID + * @return void * @throws \Exception */ - public static function delay($id) + public static function delay(int $id) { $subscriber = DBA::selectFirst('push_subscriber', ['push', 'callback_url', 'renewed', 'nickname'], ['id' => $id]); if (!DBA::isResult($subscriber)) { @@ -158,9 +162,10 @@ class PushSubscriber * * @param integer $id Subscriber ID * @param string $last_update Date of last transmitted item + * @return void * @throws \Exception */ - public static function reset($id, $last_update) + public static function reset(int $id, string $last_update) { $subscriber = DBA::selectFirst('push_subscriber', ['callback_url', 'nickname'], ['id' => $id]); if (!DBA::isResult($subscriber)) { diff --git a/src/Model/Register.php b/src/Model/Register.php index b4e9f75ea7..c24e66d4d0 100644 --- a/src/Model/Register.php +++ b/src/Model/Register.php @@ -34,13 +34,12 @@ class Register /** * Return the list of pending registrations * - * @param int $start Start count (Default is 0) + * @param int $start Start count (Default is 0) * @param int $count Count of the items per page (Default is @see Pager::ITEMS_PER_PAGE) - * - * @return array + * @return array|bool Array on succes, false on failure * @throws \Exception */ - public static function getPending($start = 0, $count = Pager::ITEMS_PER_PAGE) + public static function getPending(int $start = 0, int $count = Pager::ITEMS_PER_PAGE) { return DBA::selectToArray('pending-view', [], [], ['limit' => [$start, $count]]); } @@ -50,8 +49,7 @@ class Register * * @param int $uid The user id * - * @return array The pending user information - * + * @return array|bool Array on succes, false on failure * @throws \Exception */ public static function getPendingForUser(int $uid) @@ -65,7 +63,7 @@ class Register * @return int * @throws \Exception */ - public static function getPendingCount() + public static function getPendingCount(): int { return DBA::count('pending-view', ['self' => true]); } @@ -74,10 +72,10 @@ class Register * Returns the register record associated with the provided hash * * @param string $hash - * @return array + * @return array|bool Array on succes, false on failure * @throws \Exception */ - public static function getByHash($hash) + public static function getByHash(string $hash) { return DBA::selectFirst('register', [], ['hash' => $hash]); } @@ -89,7 +87,7 @@ class Register * @return boolean * @throws \Exception */ - public static function existsByHash($hash) + public static function existsByHash(string $hash): bool { return DBA::exists('register', ['hash' => $hash]); } @@ -100,7 +98,7 @@ class Register * @return string * @throws \Exception */ - public static function createForInvitation() + public static function createForInvitation(): string { $code = Strings::getRandomName(8) . random_int(1000, 9999); @@ -124,7 +122,7 @@ class Register * @return boolean * @throws \Exception */ - public static function createForApproval($uid, $language, $note = '') + public static function createForApproval(int $uid, string $language, string $note = ''): bool { $hash = Strings::getRandomHex(); @@ -151,7 +149,7 @@ class Register * @return boolean * @throws \Exception */ - public static function deleteByHash($hash) + public static function deleteByHash(string $hash): bool { return DBA::delete('register', ['hash' => $hash]); } diff --git a/src/Model/Search.php b/src/Model/Search.php index 09e490e77b..cb518c0b17 100644 --- a/src/Model/Search.php +++ b/src/Model/Search.php @@ -32,10 +32,9 @@ class Search * Returns the list of user defined tags (e.g. #Friendica) * * @return array - * * @throws \Exception */ - public static function getUserTags() + public static function getUserTags(): array { $termsStmt = DBA::p("SELECT DISTINCT(`term`) FROM `search`"); diff --git a/src/Model/Subscription.php b/src/Model/Subscription.php index cb14ae2b5f..26617f941a 100644 --- a/src/Model/Subscription.php +++ b/src/Model/Subscription.php @@ -25,6 +25,7 @@ use Friendica\Core\Logger; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; +use Friendica\Factory\Api\Mastodon\Notification as NotificationFactory; use Friendica\Navigation\Notifications\Entity; use Friendica\Object\Api\Mastodon\Notification; use Minishlink\WebPush\VAPID; @@ -37,8 +38,7 @@ class Subscription * @param int $applicationid * @param int $uid * @param array $fields - * - * @return bool Does it exist? + * @return array|bool Array on success, false on failure */ public static function select(int $applicationid, int $uid, array $fields = []) { @@ -53,7 +53,7 @@ class Subscription * * @return bool Does it exist? */ - public static function exists(int $applicationid, int $uid) + public static function exists(int $applicationid, int $uid): bool { return DBA::exists('subscription', ['application-id' => $applicationid, 'uid' => $uid]); } @@ -64,10 +64,9 @@ class Subscription * @param int $applicationid * @param int $uid * @param array $fields subscription fields - * * @return bool result of update */ - public static function update(int $applicationid, int $uid, array $fields) + public static function update(int $applicationid, int $uid, array $fields): bool { return DBA::update('subscription', $fields, ['application-id' => $applicationid, 'uid' => $uid]); } @@ -76,10 +75,9 @@ class Subscription * Insert or replace a subscription record * * @param array $fields subscription fields - * * @return bool result of replace */ - public static function replace(array $fields) + public static function replace(array $fields): bool { return DBA::replace('subscription', $fields); } @@ -91,7 +89,7 @@ class Subscription * @param int $uid * @return bool */ - public static function delete(int $applicationid, int $uid) + public static function delete(int $applicationid, int $uid): bool { return DBA::delete('subscription', ['application-id' => $applicationid, 'uid' => $uid]); } @@ -136,25 +134,25 @@ class Subscription /** * Prepare push notification * - * @param int $nid + * @param Notification $Notification * @return void */ - public static function pushByNotification(Entity\Notification $Notification) + public static function pushByNotification(Entity\Notification $notification) { - $type = \Friendica\Factory\Api\Mastodon\Notification::getType($Notification); + $type = NotificationFactory::getType($notification); - if (DI::notify()->NotifyOnDesktop($Notification, $type)) { - DI::notify()->createFromNotification($Notification); + if (DI::notify()->NotifyOnDesktop($notification, $type)) { + DI::notify()->createFromNotification($notification); } if (empty($type)) { return; } - $subscriptions = DBA::select('subscription', [], ['uid' => $Notification->uid, $type => true]); + $subscriptions = DBA::select('subscription', [], ['uid' => $notification->uid, $type => true]); while ($subscription = DBA::fetch($subscriptions)) { Logger::info('Push notification', ['id' => $subscription['id'], 'uid' => $subscription['uid'], 'type' => $type]); - Worker::add(PRIORITY_HIGH, 'PushSubscription', $subscription['id'], $Notification->id); + Worker::add(PRIORITY_HIGH, 'PushSubscription', $subscription['id'], $notification->id); } DBA::close($subscriptions); } diff --git a/src/Model/Tag.php b/src/Model/Tag.php index 002501aa45..1381f68611 100644 --- a/src/Model/Tag.php +++ b/src/Model/Tag.php @@ -73,13 +73,14 @@ class Tag /** * Store tag/mention elements * - * @param integer $uriid - * @param integer $type - * @param string $name - * @param string $url - * @param integer $target + * @param integer $uriId + * @param integer $type Tag type + * @param string $name Tag name + * @param string $url Contact URL (optional) + * @param integer $target Target (default: null) + * @return void */ - public static function store(int $uriid, int $type, string $name, string $url = '', int $target = null) + public static function store(int $uriId, int $type, string $name, string $url = '', int $target = null) { if ($type == self::HASHTAG) { // Trim Unicode non-word characters @@ -88,7 +89,7 @@ class Tag $tags = explode(self::TAG_CHARACTER[self::HASHTAG], $name); if (count($tags) > 1) { foreach ($tags as $tag) { - self::store($uriid, $type, $tag, $url); + self::store($uriId, $type, $tag, $url); } return; } @@ -142,7 +143,7 @@ class Tag } } - $fields = ['uri-id' => $uriid, 'type' => $type, 'tid' => $tagid, 'cid' => $cid]; + $fields = ['uri-id' => $uriId, 'type' => $type, 'tid' => $tagid, 'cid' => $cid]; if (in_array($type, [self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION])) { $condition = $fields; @@ -155,7 +156,7 @@ class Tag DBA::insert('post-tag', $fields, Database::INSERT_IGNORE); - Logger::info('Stored tag/mention', ['uri-id' => $uriid, 'tag-id' => $tagid, 'contact-id' => $cid, 'name' => $name, 'type' => $type, 'callstack' => System::callstack(8)]); + Logger::info('Stored tag/mention', ['uri-id' => $uriId, 'tag-id' => $tagid, 'contact-id' => $cid, 'name' => $name, 'type' => $type, 'callstack' => System::callstack(8)]); } /** @@ -213,14 +214,14 @@ class Tag } /** - * Get a tag id for a given tag name and url + * Get a tag id for a given tag name and URL * - * @param string $name + * @param string $name Name of tag * @param string $url - * @param int $type - * @return void + * @param int $type Type of tag + * @return int Tag id */ - public static function getID(string $name, string $url = '', int $type = null) + public static function getID(string $name, string $url = '', int $type = null): int { $fields = ['name' => substr($name, 0, 96), 'url' => $url]; @@ -242,6 +243,9 @@ class Tag return $tid; } + // Also log type + $fields['type'] = $type; + Logger::error('No tag id created', $fields); return 0; } @@ -249,20 +253,21 @@ class Tag /** * Store tag/mention elements * - * @param integer $uriid + * @param integer $uriId * @param string $hash * @param string $name * @param string $url - * @param boolean $probing + * @param boolean $probing Whether probing is active + * @return void */ - public static function storeByHash(int $uriid, string $hash, string $name, string $url = '', $probing = true) + public static function storeByHash(int $uriId, string $hash, string $name, string $url = '', bool $probing = true) { $type = self::getTypeForHash($hash); if ($type == self::UNKNOWN) { return; } - self::store($uriid, $type, $name, $url, $probing); + self::store($uriId, $type, $name, $url, $probing); } /** @@ -273,7 +278,7 @@ class Tag * * @return array Tag list */ - public static function getFromBody(string $body, string $tags = null) + public static function getFromBody(string $body, string $tags = null): array { if (is_null($tags)) { $tags = self::TAG_CHARACTER[self::HASHTAG] . self::TAG_CHARACTER[self::MENTION] . self::TAG_CHARACTER[self::EXCLUSIVE_MENTION]; @@ -289,14 +294,15 @@ class Tag /** * Store tags and mentions from the body * - * @param integer $uriid URI-Id + * @param integer $uriId URI-Id * @param string $body Body of the post * @param string $tags Accepted tags * @param boolean $probing Perform a probing for contacts, adding them if needed + * @return void */ - public static function storeFromBody(int $uriid, string $body, string $tags = null, $probing = true) + public static function storeFromBody(int $uriId, string $body, string $tags = null, bool $probing = true) { - Logger::info('Check for tags', ['uri-id' => $uriid, 'hash' => $tags, 'callstack' => System::callstack()]); + Logger::info('Check for tags', ['uri-id' => $uriId, 'hash' => $tags, 'callstack' => System::callstack()]); if (is_null($tags)) { $tags = self::TAG_CHARACTER[self::HASHTAG] . self::TAG_CHARACTER[self::MENTION] . self::TAG_CHARACTER[self::EXCLUSIVE_MENTION]; @@ -312,13 +318,13 @@ class Tag } foreach (self::getFromBody($body, $tags) as $tag) { - self::storeByHash($uriid, $tag[1], $tag[3], $tag[2], $probing); + self::storeByHash($uriId, $tag[1], $tag[3], $tag[2], $probing); } // Search for hashtags in the shared body (but only if hashtags are wanted) if (!empty($share_body) && (strpos($tags, self::TAG_CHARACTER[self::HASHTAG]) !== false)) { foreach (self::getFromBody($share_body, self::TAG_CHARACTER[self::HASHTAG]) as $tag) { - self::storeByHash($uriid, $tag[1], $tag[3], $tag[2], $probing); + self::storeByHash($uriId, $tag[1], $tag[3], $tag[2], $probing); } } } @@ -328,50 +334,52 @@ class Tag * This function is needed in the intermediate phase. * Later we can call item::setHashtags in advance to have all tags converted. * - * @param integer $uriid URI-Id + * @param integer $uriId URI-Id * @param string $body Body of the post + * @return void */ - public static function storeRawTagsFromBody(int $uriid, string $body) + public static function storeRawTagsFromBody(int $uriId, string $body) { - Logger::info('Check for tags', ['uri-id' => $uriid, 'callstack' => System::callstack()]); + Logger::info('Check for tags', ['uri-id' => $uriId, 'callstack' => System::callstack()]); $result = BBCode::getTags($body); if (empty($result)) { return; } - Logger::info('Found tags', ['uri-id' => $uriid, 'result' => $result]); + Logger::info('Found tags', ['uri-id' => $uriId, 'result' => $result]); foreach ($result as $tag) { if (substr($tag, 0, 1) != self::TAG_CHARACTER[self::HASHTAG]) { continue; } - self::storeByHash($uriid, substr($tag, 0, 1), substr($tag, 1)); + self::storeByHash($uriId, substr($tag, 0, 1), substr($tag, 1)); } } /** * Checks for stored hashtags and mentions for the given post * - * @param integer $uriid + * @param integer $uriId * @return bool */ - public static function existsForPost(int $uriid) + public static function existsForPost(int $uriId): bool { - return DBA::exists('post-tag', ['uri-id' => $uriid, 'type' => [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]]); + return DBA::exists('post-tag', ['uri-id' => $uriId, 'type' => [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]]); } /** * Remove tag/mention * - * @param integer $uriid - * @param integer $type - * @param string $name - * @param string $url + * @param integer $uriId + * @param integer $type Type + * @param string $name Name + * @param string $url URL + * @return void */ - public static function remove(int $uriid, int $type, string $name, string $url = '') + public static function remove(int $uriId, int $type, string $name, string $url = '') { - $condition = ['uri-id' => $uriid, 'type' => $type, 'url' => $url]; + $condition = ['uri-id' => $uriId, 'type' => $type, 'url' => $url]; if ($type == self::HASHTAG) { $condition['name'] = $name; } @@ -381,35 +389,36 @@ class Tag return; } - Logger::info('Removing tag/mention', ['uri-id' => $uriid, 'tid' => $tag['tid'], 'name' => $name, 'url' => $url, 'callstack' => System::callstack(8)]); - DBA::delete('post-tag', ['uri-id' => $uriid, 'type' => $type, 'tid' => $tag['tid'], 'cid' => $tag['cid']]); + Logger::info('Removing tag/mention', ['uri-id' => $uriId, 'tid' => $tag['tid'], 'name' => $name, 'url' => $url, 'callstack' => System::callstack(8)]); + DBA::delete('post-tag', ['uri-id' => $uriId, 'type' => $type, 'tid' => $tag['tid'], 'cid' => $tag['cid']]); } /** * Remove tag/mention * - * @param integer $uriid + * @param integer $uriId * @param string $hash * @param string $name * @param string $url + * @return void */ - public static function removeByHash(int $uriid, string $hash, string $name, string $url = '') + public static function removeByHash(int $uriId, string $hash, string $name, string $url = '') { $type = self::getTypeForHash($hash); if ($type == self::UNKNOWN) { return; } - self::remove($uriid, $type, $name, $url); + self::remove($uriId, $type, $name, $url); } /** * Get the type for the given hash * * @param string $hash - * @return integer type + * @return integer Tag type */ - private static function getTypeForHash(string $hash) + private static function getTypeForHash(string $hash): int { if ($hash == self::TAG_CHARACTER[self::MENTION]) { return self::MENTION; @@ -427,22 +436,23 @@ class Tag /** * Create implicit mentions for a given post * - * @param integer $uri_id - * @param integer $parent_uri_id + * @param integer $uriId + * @param integer $parentUriId + * @return void */ - public static function createImplicitMentions(int $uri_id, int $parent_uri_id) + public static function createImplicitMentions(int $uriId, int $parentUriId) { // Always mention the direct parent author - $parent = Post::selectFirst(['author-link', 'author-name'], ['uri-id' => $parent_uri_id]); - self::store($uri_id, self::IMPLICIT_MENTION, $parent['author-name'], $parent['author-link']); + $parent = Post::selectFirst(['author-link', 'author-name'], ['uri-id' => $parentUriId]); + self::store($uriId, self::IMPLICIT_MENTION, $parent['author-name'], $parent['author-link']); if (DI::config()->get('system', 'disable_implicit_mentions')) { return; } - $tags = DBA::select('tag-view', ['name', 'url'], ['uri-id' => $parent_uri_id, 'type' => [self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]]); + $tags = DBA::select('tag-view', ['name', 'url'], ['uri-id' => $parentUriId, 'type' => [self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]]); while ($tag = DBA::fetch($tags)) { - self::store($uri_id, self::IMPLICIT_MENTION, $tag['name'], $tag['url']); + self::store($uriId, self::IMPLICIT_MENTION, $tag['name'], $tag['url']); } DBA::close($tags); } @@ -450,30 +460,29 @@ class Tag /** * Retrieves the terms from the provided type(s) associated with the provided item ID. * - * @param int $item_id - * @param int|array $type - * @return array + * @param int $uriId + * @param array $type Tag type(s) + * @return array|bool Array on success, false on error * @throws \Exception */ - public static function getByURIId(int $uri_id, array $type = [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]) + public static function getByURIId(int $uriId, array $type = [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]) { - $condition = ['uri-id' => $uri_id, 'type' => $type]; + $condition = ['uri-id' => $uriId, 'type' => $type]; return DBA::selectToArray('tag-view', ['type', 'name', 'url', 'tag-type'], $condition); } /** * Return a string with all tags and mentions * - * @param integer $uri_id - * @param array $type + * @param integer $uriId + * @param array $type Tag type(s) * @return string tags and mentions * @throws \Exception */ - public static function getCSVByURIId(int $uri_id, array $type = [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]) + public static function getCSVByURIId(int $uriId, array $type = [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]): string { $tag_list = []; - $tags = self::getByURIId($uri_id, $type); - foreach ($tags as $tag) { + foreach (self::getByURIId($uriId, $type) as $tag) { $tag_list[] = self::TAG_CHARACTER[$tag['type']] . '[url=' . $tag['url'] . ']' . $tag['name'] . '[/url]'; } @@ -489,7 +498,7 @@ class Tag * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function populateFromItem(&$item) + public static function populateFromItem(array &$item): array { $return = [ 'tags' => [], @@ -498,7 +507,7 @@ class Tag 'implicit_mentions' => [], ]; - $searchpath = DI::baseUrl() . "/search?tag="; + $searchpath = DI::baseUrl() . '/search?tag='; $taglist = DBA::select('tag-view', ['type', 'name', 'url', 'cid'], ['uri-id' => $item['uri-id'], 'type' => [self::HASHTAG, self::MENTION, self::EXCLUSIVE_MENTION, self::IMPLICIT_MENTION]]); @@ -519,6 +528,7 @@ class Tag $return['hashtags'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; $return['tags'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; break; + case self::MENTION: case self::EXCLUSIVE_MENTION: if (!empty($tag['cid'])) { @@ -529,9 +539,13 @@ class Tag $return['mentions'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; $return['tags'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; break; + case self::IMPLICIT_MENTION: $return['implicit_mentions'][] = $prefix . $tag['name']; break; + + default: + Logger:warning('Unknown tag type found', $tag); } } DBA::close($taglist); @@ -546,11 +560,13 @@ class Tag * @param integer $uid * @return integer number of posts */ - public static function countByTag(string $search, int $uid = 0) + public static function countByTag(string $search, int $uid = 0): int { $condition = ["`name` = ? AND (`uid` = ? OR (`uid` = ? AND NOT `global`)) AND (`network` IN (?, ?, ?, ?) OR (`uid` = ? AND `uid` != ?))", - $search, 0, $uid, Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, $uid, 0]; + $search, 0, $uid, + Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, $uid, 0, + ]; return DBA::count('tag-search-view', $condition); } @@ -558,18 +574,20 @@ class Tag /** * Search posts for given tag * - * @param string $search - * @param integer $uid - * @param integer $start - * @param integer $limit + * @param string $search Tag to search for + * @param integer $uid User Id + * @param integer $start Starting record + * @param integer $limit Maximum count of records * @param integer $last_uriid * @return array with URI-ID */ - public static function getURIIdListByTag(string $search, int $uid = 0, int $start = 0, int $limit = 100, int $last_uriid = 0) + public static function getURIIdListByTag(string $search, int $uid = 0, int $start = 0, int $limit = 100, int $last_uriid = 0): array { $condition = ["`name` = ? AND (`uid` = ? OR (`uid` = ? AND NOT `global`)) AND (`network` IN (?, ?, ?, ?) OR (`uid` = ? AND `uid` != ?))", - $search, 0, $uid, Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, $uid, 0]; + $search, 0, $uid, + Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, $uid, 0, + ]; if (!empty($last_uriid)) { $condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $last_uriid]); @@ -582,13 +600,13 @@ class Tag $tags = DBA::select('tag-search-view', ['uri-id'], $condition, $params); - $uriids = []; + $uriIds = []; while ($tag = DBA::fetch($tags)) { - $uriids[] = $tag['uri-id']; + $uriIds[] = $tag['uri-id']; } DBA::close($tags); - return $uriids; + return $uriIds; } /** @@ -599,7 +617,7 @@ class Tag * @return array * @throws \Exception */ - public static function getGlobalTrendingHashtags(int $period, $limit = 10) + public static function getGlobalTrendingHashtags(int $period, $limit = 10): array { $tags = DI::cache()->get('global_trending_tags-' . $period . '-' . $limit); if (!empty($tags)) { @@ -612,9 +630,9 @@ class Tag /** * Fetch the blocked tags as SQL * - * @return string + * @return string SQL for blocked tag names or empty string */ - private static function getBlockedSQL() + private static function getBlockedSQL(): string { $blocked_txt = DI::config()->get('system', 'blocked_tags'); if (empty($blocked_txt)) { @@ -623,7 +641,7 @@ class Tag $blocked = explode(',', $blocked_txt); array_walk($blocked, function(&$value) { $value = "'" . DBA::escape(trim($value)) . "'";}); - return " AND NOT `name` IN (" . implode(',', $blocked) . ")"; + return ' AND NOT `name` IN (' . implode(',', $blocked) . ')'; } /** @@ -634,12 +652,15 @@ class Tag * @return array * @throws \Exception */ - public static function setGlobalTrendingHashtags(int $period, int $limit = 10) + public static function setGlobalTrendingHashtags(int $period, int $limit = 10): array { - // Get a uri-id that is at least X hours old. - // We use the uri-id in the query for the hash tags since this is much faster + /* + * Get a uri-id that is at least X hours old. + * We use the uri-id in the query for the hash tags since this is much faster + */ $post = Post::selectFirstThread(['uri-id'], ["`uid` = ? AND `received` < ?", 0, DateTimeFormat::utc('now - ' . $period . ' hour')], ['order' => ['received' => true]]); + if (empty($post['uri-id'])) { return []; } @@ -650,7 +671,9 @@ class Tag FROM `tag-search-view` WHERE `private` = ? AND `uid` = ? AND `uri-id` > ? $block_sql GROUP BY `term` ORDER BY `authors` DESC, `score` DESC LIMIT ?", - Item::PUBLIC, 0, $post['uri-id'], $limit); + Item::PUBLIC, 0, $post['uri-id'], + $limit + ); if (DBA::isResult($tagsStmt)) { $tags = DBA::toArray($tagsStmt); @@ -669,7 +692,7 @@ class Tag * @return array * @throws \Exception */ - public static function getLocalTrendingHashtags(int $period, $limit = 10) + public static function getLocalTrendingHashtags(int $period, $limit = 10): array { $tags = DI::cache()->get('local_trending_tags-' . $period . '-' . $limit); if (!empty($tags)) { @@ -687,7 +710,7 @@ class Tag * @return array * @throws \Exception */ - public static function setLocalTrendingHashtags(int $period, int $limit = 10) + public static function setLocalTrendingHashtags(int $period, int $limit = 10): array { // Get a uri-id that is at least X hours old. // We use the uri-id in the query for the hash tags since this is much faster @@ -703,7 +726,9 @@ class Tag FROM `tag-search-view` WHERE `private` = ? AND `wall` AND `origin` AND `uri-id` > ? $block_sql GROUP BY `term` ORDER BY `authors` DESC, `score` DESC LIMIT ?", - Item::PUBLIC, $post['uri-id'], $limit); + Item::PUBLIC, $post['uri-id'], + $limit + ); if (DBA::isResult($tagsStmt)) { $tags = DBA::toArray($tagsStmt); @@ -717,11 +742,11 @@ class Tag /** * Check if the provided tag is of one of the provided term types. * - * @param string $tag + * @param string $tag Tag name * @param int ...$types * @return bool */ - public static function isType($tag, ...$types) + public static function isType(string $tag, ...$types): bool { $tag_chars = []; foreach ($types as $type) { @@ -739,7 +764,7 @@ class Tag * @param string $tag * @return array User list */ - private static function getUIDListByTag(string $tag) + private static function getUIDListByTag(string $tag): array { $uids = []; $searches = DBA::select('search', ['uid'], ['term' => $tag]); @@ -754,13 +779,13 @@ class Tag /** * Fetch user who subscribed to the tags of the given item * - * @param integer $uri_id + * @param integer $uriId * @return array User list */ - public static function getUIDListByURIId(int $uri_id) + public static function getUIDListByURIId(int $uriId): array { $uids = []; - $tags = self::getByURIId($uri_id, [self::HASHTAG]); + $tags = self::getByURIId($uriId, [self::HASHTAG]); foreach ($tags as $tag) { $uids = array_merge($uids, self::getUIDListByTag(self::TAG_CHARACTER[self::HASHTAG] . $tag['name'])); diff --git a/src/Model/User.php b/src/Model/User.php index 71e2c8a812..d1306fcb98 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -117,16 +117,18 @@ class User switch ($accounttype) { case 'person': return User::ACCOUNT_TYPE_PERSON; + case 'organisation': return User::ACCOUNT_TYPE_ORGANISATION; + case 'news': return User::ACCOUNT_TYPE_NEWS; + case 'community': return User::ACCOUNT_TYPE_COMMUNITY; - default: - return null; - break; + } + return null; } /** @@ -134,7 +136,7 @@ class User * * @return array system account */ - public static function getSystemAccount() + public static function getSystemAccount(): array { $system = Contact::selectFirst([], ['self' => true, 'uid' => 0]); if (!DBA::isResult($system)) { @@ -244,7 +246,7 @@ class User * * @return string actor account name */ - public static function getActorName() + public static function getActorName(): string { $system_actor_name = DI::config()->get('system', 'actor_name'); if (!empty($system_actor_name)) { @@ -278,7 +280,7 @@ class User * @return boolean * @throws Exception */ - public static function exists($uid) + public static function exists(int $uid): bool { return DBA::exists('user', ['uid' => $uid]); } @@ -289,7 +291,7 @@ class User * @return array|boolean User record if it exists, false otherwise * @throws Exception */ - public static function getById($uid, array $fields = []) + public static function getById(int $uid, array $fields = []) { return !empty($uid) ? DBA::selectFirst('user', $fields, ['uid' => $uid]) : []; } @@ -321,7 +323,7 @@ class User * @return array|boolean User record if it exists, false otherwise * @throws Exception */ - public static function getByNickname($nickname, array $fields = []) + public static function getByNickname(string $nickname, array $fields = []) { return DBA::selectFirst('user', $fields, ['nickname' => $nickname]); } @@ -334,7 +336,7 @@ class User * @return integer user id * @throws Exception */ - public static function getIdForURL(string $url) + public static function getIdForURL(string $url): int { // Avoid database queries when the local node hostname isn't even part of the url. if (!Contact::isLocal($url)) { @@ -362,14 +364,12 @@ class User /** * Get a user based on its email * - * @param string $email - * @param array $fields - * + * @param string $email + * @param array $fields * @return array|boolean User record if it exists, false otherwise - * * @throws Exception */ - public static function getByEmail($email, array $fields = []) + public static function getByEmail(string $email, array $fields = []) { return DBA::selectFirst('user', $fields, ['email' => $email]); } @@ -380,7 +380,7 @@ class User * @param array $fields * @return array user */ - public static function getFirstAdmin(array $fields = []) + public static function getFirstAdmin(array $fields = []) : array { if (!empty(DI::config()->get('config', 'admin_nickname'))) { return self::getByNickname(DI::config()->get('config', 'admin_nickname'), $fields); @@ -469,7 +469,7 @@ class User * @return boolean|array * @throws Exception */ - public static function getOwnerDataByNick($nick) + public static function getOwnerDataByNick(string $nick) { $user = DBA::selectFirst('user', ['uid'], ['nickname' => $nick]); @@ -488,7 +488,7 @@ class User * @return int group id * @throws Exception */ - public static function getDefaultGroup($uid) + public static function getDefaultGroup(int $uid): int { $user = DBA::selectFirst('user', ['def_gid'], ['uid' => $uid]); if (DBA::isResult($user)) { @@ -512,7 +512,7 @@ class User * @throws HTTPException\ForbiddenException * @throws HTTPException\NotFoundException */ - public static function getIdFromPasswordAuthentication($user_info, $password, $third_party = false) + public static function getIdFromPasswordAuthentication($user_info, string $password, bool $third_party = false): int { // Addons registered with the "authenticate" hook may create the user on the // fly. `getAuthenticationInfo` will fail if the user doesn't exist yet. If @@ -580,7 +580,7 @@ class User * @return int User Id if authentication is successful * @throws HTTPException\ForbiddenException */ - public static function getIdFromAuthenticateHooks($username, $password) + public static function getIdFromAuthenticateHooks(string $username, string $password): int { $addon_auth = [ 'username' => $username, @@ -613,7 +613,7 @@ class User * - User array with at least the uid and the hashed password * * @param mixed $user_info - * @return array + * @return array|null Null if not found/determined * @throws HTTPException\NotFoundException */ public static function getAuthenticationInfo($user_info) @@ -671,7 +671,7 @@ class User * @return string * @throws Exception */ - public static function generateNewPassword() + public static function generateNewPassword(): string { return ucfirst(Strings::getRandomName(8)) . random_int(1000, 9999); } @@ -683,7 +683,7 @@ class User * @return bool * @throws Exception */ - public static function isPasswordExposed($password) + public static function isPasswordExposed(string $password): bool { $cache = new CacheItemPool(); $cache->changeConfig([ @@ -712,7 +712,7 @@ class User * @param string $password * @return string */ - private static function hashPasswordLegacy($password) + private static function hashPasswordLegacy(string $password): string { return hash('whirlpool', $password); } @@ -724,7 +724,7 @@ class User * @return string * @throws Exception */ - public static function hashPassword($password) + public static function hashPassword(string $password): string { if (!trim($password)) { throw new Exception(DI::l10n()->t('Password can\'t be empty')); @@ -741,7 +741,7 @@ class User * @return bool * @throws Exception */ - public static function updatePassword($uid, $password) + public static function updatePassword(int $uid, string $password): bool { $password = trim($password); @@ -771,7 +771,7 @@ class User * @return bool * @throws Exception */ - private static function updatePasswordHashed($uid, $pasword_hashed) + private static function updatePasswordHashed(int $uid, string $pasword_hashed): bool { $fields = [ 'password' => $pasword_hashed, @@ -792,7 +792,7 @@ class User * @param string $nickname The nickname that should be checked * @return boolean True is the nickname is blocked on the node */ - public static function isNicknameBlocked($nickname) + public static function isNicknameBlocked(string $nickname): bool { $forbidden_nicknames = DI::config()->get('system', 'forbidden_nicknames', ''); if (!empty($forbidden_nicknames)) { @@ -829,7 +829,7 @@ class User * @return string avatar link * @throws Exception */ - public static function getAvatarUrl(array $user, string $size = ''):string + public static function getAvatarUrl(array $user, string $size = ''): string { if (empty($user['nickname'])) { DI::logger()->warning('Missing user nickname key', ['trace' => System::callstack(20)]); @@ -871,7 +871,7 @@ class User * @return string banner link * @throws Exception */ - public static function getBannerUrl(array $user):string + public static function getBannerUrl(array $user): string { if (empty($user['nickname'])) { DI::logger()->warning('Missing user nickname key', ['trace' => System::callstack(20)]); @@ -913,7 +913,7 @@ class User * @throws ImagickException * @throws Exception */ - public static function create(array $data) + public static function create(array $data): array { $return = ['user' => null, 'password' => '']; @@ -1164,32 +1164,32 @@ class User $type = Images::getMimeTypeByData($img_str, $photo, $type); - $Image = new Image($img_str, $type); - if ($Image->isValid()) { - $Image->scaleToSquare(300); + $image = new Image($img_str, $type); + if ($image->isValid()) { + $image->scaleToSquare(300); $resource_id = Photo::newResource(); // Not using Photo::PROFILE_PHOTOS here, so that it is discovered as translateble string $profile_album = DI::l10n()->t('Profile Photos'); - $r = Photo::store($Image, $uid, 0, $resource_id, $filename, $profile_album, 4); + $r = Photo::store($image, $uid, 0, $resource_id, $filename, $profile_album, 4); if ($r === false) { $photo_failure = true; } - $Image->scaleDown(80); + $image->scaleDown(80); - $r = Photo::store($Image, $uid, 0, $resource_id, $filename, $profile_album, 5); + $r = Photo::store($image, $uid, 0, $resource_id, $filename, $profile_album, 5); if ($r === false) { $photo_failure = true; } - $Image->scaleDown(48); + $image->scaleDown(48); - $r = Photo::store($Image, $uid, 0, $resource_id, $filename, $profile_album, 6); + $r = Photo::store($image, $uid, 0, $resource_id, $filename, $profile_album, 6); if ($r === false) { $photo_failure = true; @@ -1255,7 +1255,7 @@ class User * @throws Exception */ - public static function block(int $uid, bool $block = true) + public static function block(int $uid, bool $block = true): bool { return DBA::update('user', ['blocked' => $block], ['uid' => $uid]); } @@ -1270,7 +1270,7 @@ class User * @throws HTTPException\InternalServerErrorException * @throws Exception */ - public static function allow(string $hash) + public static function allow(string $hash): bool { $register = Register::getByHash($hash); if (!DBA::isResult($register)) { @@ -1316,7 +1316,7 @@ class User * @return bool True, if the deny was successfull * @throws Exception */ - public static function deny(string $hash) + public static function deny(string $hash): bool { $register = Register::getByHash($hash); if (!DBA::isResult($register)) { @@ -1342,13 +1342,12 @@ class User * @param string $email The user's email address * @param string $nick The user's nick name * @param string $lang The user's language (default is english) - * * @return bool True, if the user was created successfully * @throws HTTPException\InternalServerErrorException * @throws ErrorException * @throws ImagickException */ - public static function createMinimal(string $name, string $email, string $nick, string $lang = L10n::DEFAULT) + public static function createMinimal(string $name, string $email, string $nick, string $lang = L10n::DEFAULT): bool { if (empty($name) || empty($email) || @@ -1418,7 +1417,7 @@ class User * @return NULL|boolean from notification() and email() inherited * @throws HTTPException\InternalServerErrorException */ - public static function sendRegisterPendingEmail($user, $sitename, $siteurl, $password) + public static function sendRegisterPendingEmail(array $user, string $sitename, string $siteurl, string $password) { $body = Strings::deindent(DI::l10n()->t( ' @@ -1461,7 +1460,7 @@ class User * @return NULL|boolean from notification() and email() inherited * @throws HTTPException\InternalServerErrorException */ - public static function sendRegisterOpenEmail(L10n $l10n, $user, $sitename, $siteurl, $password) + public static function sendRegisterOpenEmail(L10n $l10n, array $user, string $sitename, string $siteurl, string $password) { $preamble = Strings::deindent($l10n->t( ' @@ -1520,7 +1519,7 @@ class User * @return bool * @throws HTTPException\InternalServerErrorException */ - public static function remove(int $uid) + public static function remove(int $uid): bool { if (empty($uid)) { return false; @@ -1574,7 +1573,7 @@ class User * ] * @throws Exception */ - public static function identities($uid) + public static function identities(int $uid): array { if (empty($uid)) { return []; @@ -1646,7 +1645,7 @@ class User * @param int $uid * @return bool */ - public static function hasIdentities(int $uid):bool + public static function hasIdentities(int $uid): bool { if (empty($uid)) { return false; @@ -1679,7 +1678,7 @@ class User * * @throws Exception */ - public static function getStatistics() + public static function getStatistics(): array { $statistics = [ 'total_users' => 0, @@ -1731,11 +1730,10 @@ class User * @param string $type The type of users, which should get (all, bocked, removed) * @param string $order Order of the user list (Default is 'contact.name') * @param bool $descending Order direction (Default is ascending) - * - * @return array The list of the users + * @return array|bool The list of the users * @throws Exception */ - public static function getList($start = 0, $count = Pager::ITEMS_PER_PAGE, $type = 'all', $order = 'name', bool $descending = false) + public static function getList(int $start = 0, int $count = Pager::ITEMS_PER_PAGE, string $type = 'all', string $order = 'name', bool $descending = false) { $param = ['limit' => [$start, $count], 'order' => [$order => $descending]]; $condition = []; @@ -1744,11 +1742,13 @@ class User $condition['account_removed'] = false; $condition['blocked'] = false; break; + case 'blocked': $condition['account_removed'] = false; $condition['blocked'] = true; $condition['verified'] = true; break; + case 'removed': $condition['account_removed'] = true; break; diff --git a/src/Model/User/Cookie.php b/src/Model/User/Cookie.php index c0e8ffc0e1..4359d21071 100644 --- a/src/Model/User/Cookie.php +++ b/src/Model/User/Cookie.php @@ -52,12 +52,12 @@ class Cookie private $data; /** + * @param App\Request $request The current http request * @param IManageConfigValues $config * @param App\BaseURL $baseURL - * @param array $SERVER The $_SERVER array * @param array $COOKIE The $_COOKIE array */ - public function __construct(IManageConfigValues $config, App\BaseURL $baseURL, array $SERVER = [], array $COOKIE = []) + public function __construct(App\Request $request, IManageConfigValues $config, App\BaseURL $baseURL, array $COOKIE = []) { $this->sslEnabled = $baseURL->getSSLPolicy() === App\BaseURL::SSL_POLICY_FULL; $this->sitePrivateKey = $config->get('system', 'site_prvkey'); @@ -66,7 +66,7 @@ class Cookie self::DEFAULT_EXPIRE); $this->lifetime = $authCookieDays * 24 * 60 * 60; - $this->remoteAddr = ($SERVER['REMOTE_ADDR'] ?? null) ?: '0.0.0.0'; + $this->remoteAddr = $request->getRemoteAddress(); $this->data = json_decode($COOKIE[self::NAME] ?? '[]', true) ?: []; } @@ -124,6 +124,19 @@ class Cookie } } + /** + * Resets the cookie to a given data set + * + * @param array $data + * + * @return bool + */ + public function reset(array $data): bool + { + return $this->clear() && + $this->setMultiple($data); + } + /** * Clears the Friendica cookie */ @@ -131,7 +144,7 @@ class Cookie { $this->data = []; // make sure cookie is deleted on browser close, as a security measure - return $this->setCookie( '', -3600, $this->sslEnabled); + return $this->setCookie('', -3600, $this->sslEnabled); } /** @@ -161,7 +174,7 @@ class Cookie * */ protected function setCookie(string $value = null, int $expire = null, - bool $secure = null): bool + bool $secure = null): bool { return setcookie(self::NAME, $value, $expire, self::PATH, self::DOMAIN, $secure, self::HTTPONLY); } diff --git a/src/Model/Verb.php b/src/Model/Verb.php index 714cae4209..17145adfe7 100644 --- a/src/Model/Verb.php +++ b/src/Model/Verb.php @@ -34,7 +34,7 @@ class Verb * @return integer verb id * @throws \Exception */ - public static function getID(string $verb) + public static function getID(string $verb): int { if (empty($verb)) { return 0; @@ -56,7 +56,7 @@ class Verb * @param integer $id * @return string verb */ - public static function getByID(int $id) + public static function getByID(int $id): string { if (empty($id)) { return ''; diff --git a/src/Module/Admin/Site.php b/src/Module/Admin/Site.php index 36824d5119..fbebfcb3fe 100644 --- a/src/Module/Admin/Site.php +++ b/src/Module/Admin/Site.php @@ -134,6 +134,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']); $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); @@ -304,6 +305,7 @@ class Site extends BaseAdmin DI::config()->set('system', 'temppath', $temppath); DI::config()->set('system', 'only_tag_search' , $only_tag_search); + DI::config()->set('system', 'compute_group_counts', $compute_group_counts); DI::config()->set('system', 'worker_queues' , $worker_queues); DI::config()->set('system', 'worker_fastlane' , $worker_fastlane); @@ -534,6 +536,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.')], '$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 557ecd7f58..667b322422 100644 --- a/src/Module/Admin/Summary.php +++ b/src/Module/Admin/Summary.php @@ -54,12 +54,12 @@ class Summary extends BaseAdmin $warningtext[] = DI::l10n()->t('Template engine (%s) error: %s', $templateEngine::$name, $error); } - if (DBA::count(['information_schema' => 'tables'], ['engine' => 'myisam', 'table_schema' => DBA::databaseName()])) { + if (DBA::count('information_schema.tables', ['engine' => 'myisam', 'table_schema' => DBA::databaseName()])) { $warningtext[] = DI::l10n()->t('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.
', 'https://dev.mysql.com/doc/refman/5.7/en/converting-tables-to-innodb.html'); } // are there InnoDB tables in Antelope in the DB? If so, trigger a warning message - if (DBA::count(['information_schema' => 'tables'], ['ENGINE' => 'InnoDB', 'ROW_FORMAT' => ['COMPACT', 'REDUNDANT'], 'table_schema' => DBA::databaseName()])) { + if (DBA::count('information_schema.tables', ['ENGINE' => 'InnoDB', 'ROW_FORMAT' => ['COMPACT', 'REDUNDANT'], 'table_schema' => DBA::databaseName()])) { $warningtext[] = DI::l10n()->t('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.
', 'https://dev.mysql.com/doc/refman/5.7/en/innodb-file-format.html'); } diff --git a/src/Module/Api/Mastodon/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index 5392a98777..4a8c98697d 100644 --- a/src/Module/Api/Mastodon/Statuses.php +++ b/src/Module/Api/Mastodon/Statuses.php @@ -203,7 +203,7 @@ class Statuses extends BaseApi if (!empty($request['scheduled_at'])) { $item['guid'] = Item::guid($item, true); - $item['uri'] = Item::newURI($item['uid'], $item['guid']); + $item['uri'] = Item::newURI($item['guid']); $id = Post\Delayed::add($item['uri'], $item, PRIORITY_HIGH, Post\Delayed::PREPARED, $request['scheduled_at']); if (empty($id)) { DI::mstdnError()->InternalError(); diff --git a/src/Module/BaseAdmin.php b/src/Module/BaseAdmin.php index 0535996301..713c44cc20 100644 --- a/src/Module/BaseAdmin.php +++ b/src/Module/BaseAdmin.php @@ -43,7 +43,10 @@ require_once 'boot.php'; abstract class BaseAdmin extends BaseModule { /** + * Checks admin access and throws exceptions if not logged-in administrator + * * @param bool $interactive + * @return void * @throws HTTPException\ForbiddenException * @throws HTTPException\InternalServerErrorException */ diff --git a/src/Module/BaseSettings.php b/src/Module/BaseSettings.php index 9319662550..a9bc156f12 100644 --- a/src/Module/BaseSettings.php +++ b/src/Module/BaseSettings.php @@ -48,7 +48,7 @@ class BaseSettings extends BaseModule 'label' => DI::l10n()->t('Two-factor authentication'), 'url' => 'settings/2fa', 'selected' => ((DI::args()->getArgc() > 1) && (DI::args()->getArgv()[1] === '2fa') ? 'active' : ''), - 'accesskey' => 'o', + 'accesskey' => '2', ]; $tabs[] = [ diff --git a/src/Module/Contact.php b/src/Module/Contact.php index c7b2870ece..ccc61d3438 100644 --- a/src/Module/Contact.php +++ b/src/Module/Contact.php @@ -186,7 +186,7 @@ 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); diff --git a/src/Module/Contact/Contacts.php b/src/Module/Contact/Contacts.php index 65fb5a43ea..e26811001f 100644 --- a/src/Module/Contact/Contacts.php +++ b/src/Module/Contact/Contacts.php @@ -141,7 +141,7 @@ class Contacts extends BaseModule '$paginate' => $pager->renderFull($total), ]); - DI::page()['aside'] .= Widget::accounttypes($_SERVER['REQUEST_URI'], $accounttype); + DI::page()['aside'] .= Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype); return $o; } diff --git a/src/Module/Contact/Poke.php b/src/Module/Contact/Poke.php index 0bbc40a980..5836c513f9 100644 --- a/src/Module/Contact/Poke.php +++ b/src/Module/Contact/Poke.php @@ -82,7 +82,7 @@ class Poke extends BaseModule $actor = Contact::getById($a->getContactId()); - $uri = Model\Item::newURI($uid); + $uri = Model\Item::newURI(); $arr = []; diff --git a/src/Module/Contact/Profile.php b/src/Module/Contact/Profile.php index 757ea64d87..793d0fa4a9 100644 --- a/src/Module/Contact/Profile.php +++ b/src/Module/Contact/Profile.php @@ -475,7 +475,10 @@ class Profile extends BaseModule } /** + * Updates contact from probing + * * @param int $contact_id Id of the contact with uid != 0 + * @return void * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ diff --git a/src/Module/Conversation/Community.php b/src/Module/Conversation/Community.php index 877bed3e22..16e0f38afd 100644 --- a/src/Module/Conversation/Community.php +++ b/src/Module/Conversation/Community.php @@ -90,7 +90,7 @@ class Community extends BaseModule Nav::setSelected('community'); - DI::page()['aside'] .= Widget::accounttypes('community/' . self::$content, self::$accountTypeString); + DI::page()['aside'] .= Widget::accountTypes('community/' . self::$content, self::$accountTypeString); if (local_user() && DI::config()->get('system', 'community_no_sharer')) { $path = self::$content; diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 701d5371f0..848f36ce3e 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -86,13 +86,13 @@ class Network extends BaseModule $module = 'network'; - DI::page()['aside'] .= Widget::accounttypes($module, self::$accountTypeString); + 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', local_user(), self::$forumContactId); DI::page()['aside'] .= Widget::postedByYear($module . '/archive', local_user(), false); DI::page()['aside'] .= Widget::networks($module, !self::$forumContactId ? self::$network : ''); DI::page()['aside'] .= Widget\SavedSearches::getHTML(DI::args()->getQueryString()); - DI::page()['aside'] .= Widget::fileAs('filed', null); + DI::page()['aside'] .= Widget::fileAs('filed', ''); $arr = ['query' => DI::args()->getQueryString()]; Hook::callAll('network_content_init', $arr); diff --git a/src/Module/DFRN/Notify.php b/src/Module/DFRN/Notify.php index 09fe7ec144..2dae0da0ad 100644 --- a/src/Module/DFRN/Notify.php +++ b/src/Module/DFRN/Notify.php @@ -59,12 +59,13 @@ class Notify extends BaseModule } } - private static function dispatchPublic($postdata) + private static function dispatchPublic(array $postdata) { $msg = Diaspora::decodeRaw($postdata, '', true); - if (!$msg) { + if (!is_array($msg)) { // We have to fail silently to be able to hand it over to the salmon parser - return false; + Logger::warning('Diaspora::decodeRaw() has failed for some reason.'); + return; } // Fetch the corresponding public contact @@ -88,10 +89,10 @@ class Notify extends BaseModule System::xmlExit($ret, 'Done'); } - private static function dispatchPrivate($user, $postdata) + private static function dispatchPrivate(array $user, string $postdata) { $msg = Diaspora::decodeRaw($postdata, $user['prvkey'] ?? ''); - if (!$msg) { + if (!is_array($msg)) { System::xmlExit(4, 'Unable to parse message'); } diff --git a/src/Module/DFRN/Poll.php b/src/Module/DFRN/Poll.php index 516f863845..e41dafed56 100644 --- a/src/Module/DFRN/Poll.php +++ b/src/Module/DFRN/Poll.php @@ -34,6 +34,6 @@ class Poll extends BaseModule protected function rawContent(array $request = []) { $last_update = $request['last_update'] ?? ''; - System::httpExit(OStatus::feed($this->parameters['nickname'], $last_update, 10), Response::TYPE_ATOM); + System::httpExit(OStatus::feed($this->parameters['nickname'], $last_update, 10) ?? '', Response::TYPE_ATOM); } } diff --git a/src/Module/Debug/ActivityPubConversion.php b/src/Module/Debug/ActivityPubConversion.php index ec7fee3f46..5fa9a8b409 100644 --- a/src/Module/Debug/ActivityPubConversion.php +++ b/src/Module/Debug/ActivityPubConversion.php @@ -123,7 +123,7 @@ class ActivityPubConversion extends BaseModule 'content' => visible_whitespace(var_export($object_data, true)) ]; - $item = ActivityPub\Processor::createItem($object_data); + $item = ActivityPub\Processor::createItem(new ActivityPub\FetchQueue(), $object_data); $results[] = [ 'title' => DI::l10n()->t('Result Item'), diff --git a/src/Module/Directory.php b/src/Module/Directory.php index b79e7b1495..9fac9db302 100644 --- a/src/Module/Directory.php +++ b/src/Module/Directory.php @@ -112,7 +112,7 @@ class Directory extends BaseModule * * @throws \Exception */ - public static function formatEntry(array $contact, $photo_size = 'photo') + public static function formatEntry(array $contact, string $photo_size = 'photo'): array { $itemurl = (($contact['addr'] != "") ? $contact['addr'] : $contact['url']); @@ -166,7 +166,7 @@ class Directory extends BaseModule 'img_hover' => $contact['name'], 'name' => $contact['name'], 'details' => $details, - 'account_type' => Model\Contact::getAccountType($contact['contact-type']), + 'account_type' => Model\Contact::getAccountType($contact['contact-type'] ?? 0), 'profile' => $profile, 'location' => $location_e, 'tags' => $contact['pub_keywords'], diff --git a/src/Module/HTTPException/PageNotFound.php b/src/Module/HTTPException/PageNotFound.php index 4cfa35276d..ecebc7757a 100644 --- a/src/Module/HTTPException/PageNotFound.php +++ b/src/Module/HTTPException/PageNotFound.php @@ -21,14 +21,29 @@ namespace Friendica\Module\HTTPException; +use Friendica\App; use Friendica\BaseModule; +use Friendica\Core\L10n; use Friendica\Core\System; use Friendica\DI; +use Friendica\Module\Response; use Friendica\Network\HTTPException; +use Friendica\Util\Profiler; use Psr\Http\Message\ResponseInterface; +use Psr\Log\LoggerInterface; class PageNotFound extends BaseModule { + /** @var string */ + private $remoteAddress; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Request $request, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->remoteAddress = $request->getRemoteAddress(); + } + protected function content(array $request = []): string { throw new HTTPException\NotFoundException(DI::l10n()->t('Page not found.')); @@ -58,7 +73,7 @@ class PageNotFound extends BaseModule $this->logger->debug('index.php: page not found.', [ 'request_uri' => $this->server['REQUEST_URI'], - 'address' => $this->server['REMOTE_ADDR'], + 'address' => $this->remoteAddress, 'query' => $this->server['QUERY_STRING'] ]); diff --git a/src/Module/Install.php b/src/Module/Install.php index 09025ff493..843cee9f18 100644 --- a/src/Module/Install.php +++ b/src/Module/Install.php @@ -170,7 +170,7 @@ class Install extends BaseModule return; } - $this->installer->installDatabase($configCache->get('system', 'basepath')); + $this->installer->installDatabase(); // install allowed themes to register theme hooks // this is same as "Reload active theme" in /admin/themes @@ -363,7 +363,7 @@ class Install extends BaseModule * @return string The text for the next steps * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private function whatNext() + private function whatNext(): string { $baseurl = $this->baseUrl->get(); return @@ -383,6 +383,7 @@ class Install extends BaseModule * @param string $cat The category of the setting * @param string $key The key of the setting * @param null|string $default The default value + * @return void */ private function checkSetting(Cache $configCache, array $post, string $cat, string $key, ?string $default = null) { diff --git a/src/Module/Maintenance.php b/src/Module/Maintenance.php index 05540a228b..4080869158 100644 --- a/src/Module/Maintenance.php +++ b/src/Module/Maintenance.php @@ -45,7 +45,7 @@ class Maintenance extends BaseModule $exception = new HTTPException\ServiceUnavailableException($reason); - header($_SERVER["SERVER_PROTOCOL"] . ' ' . $exception->getCode() . ' ' . DI::l10n()->t('System down for maintenance')); + header($_SERVER['SERVER_PROTOCOL'] . ' ' . $exception->getCode() . ' ' . DI::l10n()->t('System down for maintenance')); $tpl = Renderer::getMarkupTemplate('exception.tpl'); diff --git a/src/Module/NoScrape.php b/src/Module/NoScrape.php index fbc01c2d3c..e3a01ceaab 100644 --- a/src/Module/NoScrape.php +++ b/src/Module/NoScrape.php @@ -131,7 +131,7 @@ class NoScrape extends BaseModule $profile_fields = ['about', 'locality', 'region', 'postal-code', 'country-name', 'xmpp', 'matrix']; foreach ($profile_fields as $field) { if (!empty($owner[$field])) { - $json_info["$field"] = $owner[$field]; + $json_info[$field] = $owner[$field]; } } diff --git a/src/Module/Notifications/Ping.php b/src/Module/Notifications/Ping.php index 7dc2158260..c09d6d0cbe 100644 --- a/src/Module/Notifications/Ping.php +++ b/src/Module/Notifications/Ping.php @@ -113,7 +113,8 @@ class Ping extends BaseModule } DBA::close($items); - if ($network_count) { + $compute_group_counts = DI::config()->get('system','compute_group_counts'); + if ($network_count && $compute_group_counts) { // Find out how unseen network posts are spread across groups $group_counts = Group::countUnseen(); if (DBA::isResult($group_counts)) { diff --git a/src/Module/OpenSearch.php b/src/Module/OpenSearch.php index 35d6890ec6..9f89660eed 100644 --- a/src/Module/OpenSearch.php +++ b/src/Module/OpenSearch.php @@ -50,9 +50,12 @@ class OpenSearch extends BaseModule '@attributes' => [ 'xmlns' => 'http://a9.com/-/spec/opensearch/1.1', ], - 'ShortName' => "Friendica $hostname", - 'Description' => "Search in Friendica $hostname", - 'Contact' => 'https://github.com/friendica/friendica/issues', + 'ShortName' => "Friendica $hostname", + 'Description' => "Search in Friendica $hostname", + 'Contact' => 'https://github.com/friendica/friendica/issues', + 'InputEncoding' => 'UTF-8', + 'OutputEncoding' => 'UTF-8', + 'Developer' => 'Friendica Developer Team', ], ], $xml); diff --git a/src/Module/PermissionTooltip.php b/src/Module/PermissionTooltip.php index 07faa72e3e..ec449aa15f 100644 --- a/src/Module/PermissionTooltip.php +++ b/src/Module/PermissionTooltip.php @@ -174,7 +174,7 @@ class PermissionTooltip extends \Friendica\BaseModule * @param int $uriId * @return string */ - private function fetchReceivers(int $uriId):string + private function fetchReceivers(int $uriId): string { $own_url = ''; $uid = local_user(); diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 86c737aa4e..d1b4b9629e 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -60,17 +60,17 @@ class Photo extends BaseModule { $totalstamp = microtime(true); - if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { - header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT"); - if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) { - header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]); + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { + header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); + if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) { + header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']); } - header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT"); - header("Cache-Control: max-age=31536000"); - if (function_exists("header_remove")) { - header_remove("Last-Modified"); - header_remove("Expires"); - header_remove("Cache-Control"); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT'); + header('Cache-Control: max-age=31536000'); + if (function_exists('header_remove')) { + header_remove('Last-Modified'); + header_remove('Expires'); + header_remove('Cache-Control'); } throw new NotModifiedException(); } @@ -128,11 +128,11 @@ class Photo extends BaseModule throw new HTTPException\NotFoundException(DI::l10n()->t('The Photo is not available.')); } - $photo = self::getPhotoByid($id, $this->parameters['type'], $customsize ?: Proxy::PIXEL_SMALL); + $photo = self::getPhotoById($id, $this->parameters['type'], $customsize ?: Proxy::PIXEL_SMALL); } else { $photoid = pathinfo($this->parameters['name'], PATHINFO_FILENAME); $scale = 0; - if (substr($photoid, -2, 1) == "-") { + if (substr($photoid, -2, 1) == '-') { $scale = intval(substr($photoid, -1, 1)); $photoid = substr($photoid, 0, -2); } @@ -148,7 +148,7 @@ class Photo extends BaseModule throw new HTTPException\NotFoundException(); } - $cacheable = ($photo["allow_cid"] . $photo["allow_gid"] . $photo["deny_cid"] . $photo["deny_gid"] === "") && (isset($photo["cacheable"]) ? $photo["cacheable"] : true); + $cacheable = ($photo['allow_cid'] . $photo['allow_gid'] . $photo['deny_cid'] . $photo['deny_gid'] === '') && (isset($photo['cacheable']) ? $photo['cacheable'] : true); $stamp = microtime(true); @@ -179,35 +179,35 @@ class Photo extends BaseModule } // if customsize is set and image is not a gif, resize it - if ($photo['type'] !== "image/gif" && $customsize > 0 && $customsize <= Proxy::PIXEL_THUMB && $square_resize) { + if ($photo['type'] !== 'image/gif' && $customsize > 0 && $customsize <= Proxy::PIXEL_THUMB && $square_resize) { $img = new Image($imgdata, $photo['type']); $img->scaleToSquare($customsize); $imgdata = $img->asString(); - } elseif ($photo['type'] !== "image/gif" && $customsize > 0) { + } elseif ($photo['type'] !== 'image/gif' && $customsize > 0) { $img = new Image($imgdata, $photo['type']); $img->scaleDown($customsize); $imgdata = $img->asString(); } - if (function_exists("header_remove")) { - header_remove("Pragma"); - header_remove("pragma"); + if (function_exists('header_remove')) { + header_remove('Pragma'); + header_remove('pragma'); } - header("Content-type: " . $photo['type']); + header('Content-type: ' . $photo['type']); $stamp = microtime(true); if (!$cacheable) { // it is a private photo that they have no permission to view. // tell the browser not to cache it, in case they authenticate // and subsequently have permission to see it - header("Cache-Control: no-store, no-cache, must-revalidate"); + header('Cache-Control: no-store, no-cache, must-revalidate'); } else { $md5 = $photo['hash'] ?: md5($imgdata); - header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT"); + header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); header("Etag: \"{$md5}\""); - header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT"); - header("Cache-Control: max-age=31536000"); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT'); + header('Cache-Control: max-age=31536000'); } $checksum = microtime(true) - $stamp; @@ -228,10 +228,18 @@ class Photo extends BaseModule System::exit(); } - private static function getPhotoByid(int $id, $type, $customsize) + /** + * Fetches photo record by given id number, type and custom size + * + * @param int $id Photo id + * @param string $type Photo type + * @param int $customsize Custom size (?) + * @return array|bool Array on success, false on error + */ + private static function getPhotoById(int $id, string $type, int $customsize) { switch($type) { - case "preview": + case 'preview': $media = DBA::selectFirst('post-media', ['preview', 'url', 'mimetype', 'type', 'uri-id'], ['id' => $id]); if (empty($media)) { return false; @@ -250,8 +258,8 @@ class Photo extends BaseModule return MPhoto::getPhoto($matches[1], $matches[2]); } - return MPhoto::createPhotoForExternalResource($url, (int)local_user(), $media['mimetype']); - case "media": + return MPhoto::createPhotoForExternalResource($url, (int)local_user(), $media['mimetype'] ?? ''); + case 'media': $media = DBA::selectFirst('post-media', ['url', 'mimetype', 'uri-id'], ['id' => $id, 'type' => Post\Media::IMAGE]); if (empty($media)) { return false; @@ -262,14 +270,14 @@ class Photo extends BaseModule } return MPhoto::createPhotoForExternalResource($media['url'], (int)local_user(), $media['mimetype']); - case "link": + case 'link': $link = DBA::selectFirst('post-link', ['url', 'mimetype'], ['id' => $id]); if (empty($link)) { return false; } - return MPhoto::createPhotoForExternalResource($link['url'], (int)local_user(), $link['mimetype']); - case "contact": + return MPhoto::createPhotoForExternalResource($link['url'], (int)local_user(), $link['mimetype'] ?? ''); + case 'contact': $fields = ['uid', 'uri-id', 'url', 'nurl', 'avatar', 'photo', 'xmpp', 'addr', 'network', 'failed', 'updated']; $contact = Contact::getById($id, $fields); if (empty($contact)) { @@ -287,7 +295,7 @@ class Photo extends BaseModule } else { $scale = 4; } - $photo = MPhoto::selectFirst([], ["scale" => $scale, "uid" => $contact['uid'], "profile" => 1]); + $photo = MPhoto::selectFirst([], ['scale' => $scale, 'uid' => $contact['uid'], 'profile' => 1]); if (!empty($photo)) { return $photo; } @@ -330,7 +338,7 @@ class Photo extends BaseModule } if ($update) { Logger::info('Invalid file, contact update initiated', ['cid' => $id, 'url' => $contact['url'], 'avatar' => $url]); - Worker::add(PRIORITY_LOW, "UpdateContact", $id); + Worker::add(PRIORITY_LOW, 'UpdateContact', $id); } else { Logger::info('Invalid file', ['cid' => $id, 'url' => $contact['url'], 'avatar' => $url]); } @@ -352,7 +360,7 @@ class Photo extends BaseModule } } return MPhoto::createPhotoForExternalResource($url, 0, $mimetext); - case "header": + case 'header': $fields = ['uid', 'url', 'header', 'network', 'gsid']; $contact = Contact::getById($id, $fields); if (empty($contact)) { @@ -367,37 +375,37 @@ class Photo extends BaseModule $url = Contact::getDefaultHeader($contact); } return MPhoto::createPhotoForExternalResource($url); - case "banner": - $photo = MPhoto::selectFirst([], ["scale" => 3, 'uid' => $id, 'photo-type' => MPhoto::USER_BANNER]); + case 'banner': + $photo = MPhoto::selectFirst([], ['scale' => 3, 'uid' => $id, 'photo-type' => MPhoto::USER_BANNER]); if (!empty($photo)) { return $photo; } return MPhoto::createPhotoForExternalResource(DI::baseUrl() . '/images/friendica-banner.jpg'); - case "profile": - case "custom": + case 'profile': + case 'custom': $scale = 4; break; - case "micro": + case 'micro': $scale = 6; break; - case "avatar": + case 'avatar': default: $scale = 5; } - $photo = MPhoto::selectFirst([], ["scale" => $scale, "uid" => $id, "profile" => 1]); + $photo = MPhoto::selectFirst([], ['scale' => $scale, 'uid' => $id, 'profile' => 1]); if (empty($photo)) { $contact = DBA::selectFirst('contact', [], ['uid' => $id, 'self' => true]) ?: []; switch($type) { - case "profile": - case "custom": + case 'profile': + case 'custom': $default = Contact::getDefaultAvatar($contact, Proxy::SIZE_SMALL); break; - case "micro": + case 'micro': $default = Contact::getDefaultAvatar($contact, Proxy::SIZE_MICRO); break; - case "avatar": + case 'avatar': default: $default = Contact::getDefaultAvatar($contact, Proxy::SIZE_THUMB); } diff --git a/src/Module/Proxy.php b/src/Module/Proxy.php index 90f1185800..cff5ed90b0 100644 --- a/src/Module/Proxy.php +++ b/src/Module/Proxy.php @@ -55,17 +55,17 @@ class Proxy extends BaseModule throw new \Friendica\Network\HTTPException\NotFoundException(); } - if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { - header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT"); - if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) { - header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]); + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { + header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); + if (!empty($_SERVER['HTTP_IF_NONE_MATCH'])) { + header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']); } - header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT"); - header("Cache-Control: max-age=31536000"); - if (function_exists("header_remove")) { - header_remove("Last-Modified"); - header_remove("Expires"); - header_remove("Cache-Control"); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT'); + header('Cache-Control: max-age=31536000'); + if (function_exists('header_remove')) { + header_remove('Last-Modified'); + header_remove('Expires'); + header_remove('Cache-Control'); } throw new NotModifiedException(); } @@ -123,7 +123,7 @@ class Proxy extends BaseModule * ] * @throws \Exception */ - private function getRequestInfo() + private function getRequestInfo(): array { $size = ProxyUtils::PIXEL_LARGE; $sizetype = ''; @@ -187,6 +187,7 @@ class Proxy extends BaseModule * Output the image with cache headers * * @param Image $img + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function responseImageHttpCache(Image $img) diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index 4b161e39ce..db20dd0a3d 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -21,11 +21,13 @@ namespace Friendica\Module\Search; +use Friendica\App; use Friendica\Content\Nav; use Friendica\Content\Pager; use Friendica\Content\Text\HTML; use Friendica\Content\Widget; use Friendica\Core\Cache\Enum\Duration; +use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\Renderer; use Friendica\Core\Search; @@ -37,11 +39,24 @@ use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\Tag; use Friendica\Module\BaseSearch; +use Friendica\Module\Response; use Friendica\Network\HTTPException; use Friendica\Util\Network; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; class Index extends BaseSearch { + /** @var string */ + private $remoteAddress; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Request $request, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->remoteAddress = $request->getRemoteAddress(); + } + protected function content(array $request = []): string { $search = (!empty($_GET['q']) ? trim(rawurldecode($_GET['q'])) : ''); @@ -66,7 +81,7 @@ class Index extends BaseSearch if ($crawl_permit_period == 0) $crawl_permit_period = 10; - $remote = $_SERVER['REMOTE_ADDR']; + $remote = $this->remoteAddress; $result = DI::cache()->get('remote_search:' . $remote); if (!is_null($result)) { $resultdata = json_decode($result); diff --git a/src/Module/Security/Logout.php b/src/Module/Security/Logout.php index 1ec0764834..004292cb5c 100644 --- a/src/Module/Security/Logout.php +++ b/src/Module/Security/Logout.php @@ -31,7 +31,6 @@ use Friendica\Core\System; use Friendica\Model\Profile; use Friendica\Model\User\Cookie; use Friendica\Module\Response; -use Friendica\Security\TwoFactor; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -46,17 +45,14 @@ class Logout extends BaseModule protected $cookie; /** @var IHandleSessions */ protected $session; - /** @var TwoFactor\Repository\TrustedBrowser */ - protected $trustedBrowserRepo; - public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, TwoFactor\Repository\TrustedBrowser $trustedBrowserRepo, ICanCache $cache, Cookie $cookie, IHandleSessions $session, array $server, array $parameters = []) + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, ICanCache $cache, Cookie $cookie, IHandleSessions $session, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->cache = $cache; - $this->cookie = $cookie; - $this->session = $session; - $this->trustedBrowserRepo = $trustedBrowserRepo; + $this->cache = $cache; + $this->cookie = $cookie; + $this->session = $session; } @@ -73,9 +69,9 @@ class Logout extends BaseModule Hook::callAll("logging_out"); - // Remove this trusted browser as it won't be able to be used ever again after the cookie is cleared - if ($this->cookie->get('trusted')) { - $this->trustedBrowserRepo->removeForUser(local_user(), $this->cookie->get('trusted')); + // If this is a trusted browser, redirect to the 2fa signout page + if ($this->cookie->get('2fa_cookie_hash')) { + $this->baseUrl->redirect('2fa/signout'); } $this->cookie->clear(); diff --git a/src/Module/Security/TwoFactor/SignOut.php b/src/Module/Security/TwoFactor/SignOut.php new file mode 100644 index 0000000000..75efc9e60b --- /dev/null +++ b/src/Module/Security/TwoFactor/SignOut.php @@ -0,0 +1,129 @@ +. + * + */ + +namespace Friendica\Module\Security\TwoFactor; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleSessions; +use Friendica\Model\User\Cookie; +use Friendica\Module\Response; +use Friendica\Network\HTTPException\NotFoundException; +use Friendica\Util\Profiler; +use Friendica\Security\TwoFactor; +use Psr\Log\LoggerInterface; + +/** + * Page 4: Logout dialog for trusted browsers + * + * @package Friendica\Module\TwoFactor + */ +class SignOut extends BaseModule +{ + protected $errors = []; + + /** @var IHandleSessions */ + protected $session; + /** @var Cookie */ + protected $cookie; + /** @var TwoFactor\Repository\TrustedBrowser */ + protected $trustedBrowserRepository; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, IHandleSessions $session, Cookie $cookie, TwoFactor\Repository\TrustedBrowser $trustedBrowserRepository, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->cookie = $cookie; + $this->trustedBrowserRepository = $trustedBrowserRepository; + } + + protected function post(array $request = []) + { + if (!local_user() || !($this->cookie->get('2fa_cookie_hash'))) { + return; + } + + $action = $request['action'] ?? ''; + + if (!empty($action)) { + self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_signout'); + + switch ($action) { + case 'trust_and_sign_out': + $trusted = $this->cookie->get('2fa_cookie_hash'); + $this->cookie->reset(['2fa_cookie_hash' => $trusted]); + $this->session->clear(); + + info($this->t('Logged out.')); + $this->baseUrl->redirect(); + break; + case 'sign_out': + $this->trustedBrowserRepository->removeForUser(local_user(), $this->cookie->get('2fa_cookie_hash')); + $this->cookie->clear(); + $this->session->clear(); + + info($this->t('Logged out.')); + $this->baseUrl->redirect(); + break; + default: + $this->baseUrl->redirect(); + } + } + } + + protected function content(array $request = []): string + { + if (!local_user() || !($this->cookie->get('2fa_cookie_hash'))) { + $this->baseUrl->redirect(); + } + + try { + $trustedBrowser = $this->trustedBrowserRepository->selectOneByHash($this->cookie->get('2fa_cookie_hash')); + if (!$trustedBrowser->trusted) { + $trusted = $this->cookie->get('2fa_cookie_hash'); + $this->cookie->reset(['2fa_cookie_hash' => $trusted]); + $this->session->clear(); + + info($this->t('Logged out.')); + $this->baseUrl->redirect(); + } + } catch (TwoFactor\Exception\TrustedBrowserNotFoundException $exception) { + $this->cookie->clear(); + $this->session->clear(); + + info($this->t('Logged out.')); + $this->baseUrl->redirect(); + } + + return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/signout.tpl'), [ + '$form_security_token' => self::getFormSecurityToken('twofactor_signout'), + + '$title' => $this->t('Sign out of this browser?'), + '$message' => $this->t('

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

'), + '$sign_out_label' => $this->t('Sign out'), + '$cancel_label' => $this->t('Cancel'), + '$trust_and_sign_out_label' => $this->t('Trust and sign out'), + ]); + } +} diff --git a/src/Module/Security/TwoFactor/Trust.php b/src/Module/Security/TwoFactor/Trust.php new file mode 100644 index 0000000000..4ba4ba69b3 --- /dev/null +++ b/src/Module/Security/TwoFactor/Trust.php @@ -0,0 +1,146 @@ +. + * + */ + +namespace Friendica\Module\Security\TwoFactor; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleSessions; +use Friendica\Model\User; +use Friendica\Model\User\Cookie; +use Friendica\Module\Response; +use Friendica\Network\HTTPException\FoundException; +use Friendica\Network\HTTPException\MovedPermanentlyException; +use Friendica\Network\HTTPException\TemporaryRedirectException; +use Friendica\Security\Authentication; +use Friendica\Security\TwoFactor\Exception\TrustedBrowserNotFoundException; +use Friendica\Security\TwoFactor\Exception\TrustedBrowserPersistenceException; +use Friendica\Util\Profiler; +use Friendica\Security\TwoFactor; +use Psr\Log\LoggerInterface; + +/** + * Page 2: Trust Browser dialog + * + * @package Friendica\Module\TwoFactor + */ +class Trust extends BaseModule +{ + /** @var App */ + protected $app; + /** @var Authentication */ + protected $auth; + /** @var IHandleSessions */ + protected $session; + /** @var Cookie */ + protected $cookie; + /** @var TwoFactor\Factory\TrustedBrowser */ + protected $trustedBrowserFactory; + /** @var TwoFactor\Repository\TrustedBrowser */ + protected $trustedBrowserRepository; + + public function __construct(App $app, Authentication $auth, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IHandleSessions $session, Cookie $cookie, TwoFactor\Factory\TrustedBrowser $trustedBrowserFactory, TwoFactor\Repository\TrustedBrowser $trustedBrowserRepositoy, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->app = $app; + $this->auth = $auth; + $this->session = $session; + $this->cookie = $cookie; + $this->trustedBrowserFactory = $trustedBrowserFactory; + $this->trustedBrowserRepository = $trustedBrowserRepositoy; + } + + protected function post(array $request = []) + { + if (!local_user() || !$this->session->get('2fa')) { + $this->logger->info('Invalid call', ['request' => $request]); + return; + } + + $action = $request['action'] ?? ''; + + if (!empty($action)) { + self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_trust'); + + switch ($action) { + case 'trust': + case 'dont_trust': + $trustedBrowser = $this->trustedBrowserFactory->createForUserWithUserAgent(local_user(), $this->server['HTTP_USER_AGENT'], $action === 'trust'); + try { + $this->trustedBrowserRepository->save($trustedBrowser); + + // The string is sent to the browser to be sent back with each request + if (!$this->cookie->set('2fa_cookie_hash', $trustedBrowser->cookie_hash)) { + notice($this->t('Couldn\'t save browser to Cookie.')); + }; + } catch (TrustedBrowserPersistenceException $exception) { + $this->logger->warning('Unexpected error when saving the trusted browser.', ['trustedBrowser' => $trustedBrowser, 'exception' => $exception]); + } + break; + } + + try { + $this->auth->setForUser($this->app, User::getById($this->app->getLoggedInUserId()), true, true); + } catch (FoundException | TemporaryRedirectException | MovedPermanentlyException $e) { + // exception wanted! + throw $e; + } catch (\Exception $e) { + $this->logger->warning('Unexpected error during authentication.', ['user' => $this->app->getLoggedInUserId(), 'exception' => $exception]); + } + } + } + + protected function content(array $request = []): string + { + if (!local_user() || !$this->session->get('2fa')) { + $this->baseUrl->redirect(); + } + + if ($this->cookie->get('2fa_cookie_hash')) { + try { + $trustedBrowser = $this->trustedBrowserRepository->selectOneByHash($this->cookie->get('2fa_cookie_hash')); + if (!$trustedBrowser->trusted) { + $this->auth->setForUser($this->app, User::getById($this->app->getLoggedInUserId()), true, true); + $this->baseUrl->redirect(); + } + } catch (TrustedBrowserNotFoundException $exception) { + $this->logger->notice('Trusted Browser of the cookie not found.', ['cookie_hash' => $this->cookie->get('trusted'), 'uid' => $this->app->getLoggedInUserId(), 'exception' => $exception]); + } catch (TrustedBrowserPersistenceException $exception) { + $this->logger->warning('Unexpected persistence exception.', ['cookie_hash' => $this->cookie->get('trusted'), 'uid' => $this->app->getLoggedInUserId(), 'exception' => $exception]); + } catch (\Exception $exception) { + $this->logger->warning('Unexpected exception.', ['cookie_hash' => $this->cookie->get('trusted'), 'uid' => $this->app->getLoggedInUserId(), 'exception' => $exception]); + } + } + + return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/trust.tpl'), [ + '$form_security_token' => self::getFormSecurityToken('twofactor_trust'), + + '$title' => $this->t('Trust this browser?'), + '$message' => $this->t('

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

'), + '$not_now_label' => $this->t('Not now'), + '$dont_trust_label' => $this->t('Don\'t trust'), + '$trust_label' => $this->t('Trust'), + ]); + } +} diff --git a/src/Module/Security/TwoFactor/Verify.php b/src/Module/Security/TwoFactor/Verify.php index c6d1294320..d0850aedcb 100644 --- a/src/Module/Security/TwoFactor/Verify.php +++ b/src/Module/Security/TwoFactor/Verify.php @@ -21,13 +21,17 @@ namespace Friendica\Module\Security\TwoFactor; +use Friendica\App; use Friendica\BaseModule; +use Friendica\Core\L10n; +use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; use Friendica\Core\Renderer; -use Friendica\Core\Session; -use Friendica\DI; -use Friendica\Model\User; +use Friendica\Core\Session\Capability\IHandleSessions; +use Friendica\Module\Response; +use Friendica\Util\Profiler; use PragmaRX\Google2FA\Google2FA; use Friendica\Security\TwoFactor; +use Psr\Log\LoggerInterface; /** * Page 1: Authenticator code verification @@ -36,7 +40,20 @@ use Friendica\Security\TwoFactor; */ class Verify extends BaseModule { - private static $errors = []; + protected $errors = []; + + /** @var IHandleSessions */ + protected $session; + /** @var IManagePersonalConfigValues */ + protected $pConfig; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IManagePersonalConfigValues $pConfig, IHandleSessions $session, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->pConfig = $pConfig; + } protected function post(array $request = []) { @@ -44,36 +61,20 @@ class Verify extends BaseModule return; } - if (($_POST['action'] ?? '') == 'verify') { + if (($request['action'] ?? '') === 'verify') { self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_verify'); - $a = DI::app(); + $code = $request['verify_code'] ?? ''; - $code = $_POST['verify_code'] ?? ''; - - $valid = (new Google2FA())->verifyKey(DI::pConfig()->get(local_user(), '2fa', 'secret'), $code); + $valid = (new Google2FA())->verifyKey($this->pConfig->get(local_user(), '2fa', 'secret'), $code); // The same code can't be used twice even if it's valid - if ($valid && Session::get('2fa') !== $code) { - Session::set('2fa', $code); + if ($valid && $this->session->get('2fa') !== $code) { + $this->session->set('2fa', $code); - // Trust this browser feature - if (!empty($_REQUEST['trust_browser'])) { - $trustedBrowserFactory = new TwoFactor\Factory\TrustedBrowser(DI::logger()); - $trustedBrowserRepository = new TwoFactor\Repository\TrustedBrowser(DI::dba(), DI::logger(), $trustedBrowserFactory); - - $trustedBrowser = $trustedBrowserFactory->createForUserWithUserAgent(local_user(), $_SERVER['HTTP_USER_AGENT']); - - $trustedBrowserRepository->save($trustedBrowser); - - // The string is sent to the browser to be sent back with each request - DI::cookie()->set('trusted', $trustedBrowser->cookie_hash); - } - - // Resume normal login workflow - DI::auth()->setForUser($a, User::getById($a->getLoggedInUserId()), true, true); + $this->baseUrl->redirect('2fa/trust'); } else { - self::$errors[] = DI::l10n()->t('Invalid code, please retry.'); + $this->errors[] = $this->t('Invalid code, please retry.'); } } } @@ -81,25 +82,24 @@ class Verify extends BaseModule protected function content(array $request = []): string { if (!local_user()) { - DI::baseUrl()->redirect(); + $this->baseUrl->redirect(); } // Already authenticated with 2FA token - if (Session::get('2fa')) { - DI::baseUrl()->redirect(); + if ($this->session->get('2fa')) { + $this->baseUrl->redirect(); } return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/verify.tpl'), [ '$form_security_token' => self::getFormSecurityToken('twofactor_verify'), - '$title' => DI::l10n()->t('Two-factor authentication'), - '$message' => DI::l10n()->t('

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

'), - '$errors_label' => DI::l10n()->tt('Error', 'Errors', count(self::$errors)), - '$errors' => self::$errors, - '$recovery_message' => DI::l10n()->t('Don’t have your phone? Enter a two-factor recovery code', '2fa/recovery'), - '$verify_code' => ['verify_code', DI::l10n()->t('Please enter a code from your authentication app'), '', '', DI::l10n()->t('Required'), 'autofocus autocomplete="off" placeholder="000000"', 'tel'], - '$trust_browser' => ['trust_browser', DI::l10n()->t('This is my two-factor authenticator app device'), !empty($_REQUEST['trust_browser'])], - '$verify_label' => DI::l10n()->t('Verify code and complete login'), + '$title' => $this->t('Two-factor authentication'), + '$message' => $this->t('

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

'), + '$errors_label' => $this->tt('Error', 'Errors', count($this->errors)), + '$errors' => $this->errors, + '$recovery_message' => $this->t('If you do not have access to your authentication code you can use a two-factor recovery code.', '2fa/recovery'), + '$verify_code' => ['verify_code', $this->t('Please enter a code from your authentication app'), '', '', $this->t('Required'), 'autofocus autocomplete="one-time-code" placeholder="000000" inputmode="numeric" pattern="[0-9]*"'], + '$verify_label' => $this->t('Verify code and complete login'), ]); } } diff --git a/src/Module/Settings/TwoFactor/Index.php b/src/Module/Settings/TwoFactor/Index.php index 35c5d3cf9c..0da49f3177 100644 --- a/src/Module/Settings/TwoFactor/Index.php +++ b/src/Module/Settings/TwoFactor/Index.php @@ -24,6 +24,7 @@ namespace Friendica\Module\Settings\TwoFactor; use Friendica\Core\Renderer; use Friendica\Core\Session; use Friendica\DI; +use Friendica\Network\HTTPException\FoundException; use Friendica\Security\TwoFactor\Model\AppSpecificPassword; use Friendica\Security\TwoFactor\Model\RecoveryCode; use Friendica\Model\User; @@ -44,8 +45,8 @@ class Index extends BaseSettings try { User::getIdFromPasswordAuthentication(local_user(), $_POST['password'] ?? ''); - $has_secret = (bool) DI::pConfig()->get(local_user(), '2fa', 'secret'); - $verified = DI::pConfig()->get(local_user(), '2fa', 'verified'); + $has_secret = (bool)DI::pConfig()->get(local_user(), '2fa', 'secret'); + $verified = DI::pConfig()->get(local_user(), '2fa', 'verified'); switch ($_POST['action'] ?? '') { case 'enable': @@ -54,7 +55,8 @@ class Index extends BaseSettings DI::pConfig()->set(local_user(), '2fa', 'secret', $Google2FA->generateSecretKey(32)); - DI::baseUrl()->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password')); + DI::baseUrl() + ->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password')); } break; case 'disable': @@ -70,27 +72,33 @@ class Index extends BaseSettings break; case 'recovery': if ($has_secret) { - DI::baseUrl()->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password')); + DI::baseUrl() + ->redirect('settings/2fa/recovery?t=' . self::getFormSecurityToken('settings_2fa_password')); } break; case 'app_specific': if ($has_secret) { - DI::baseUrl()->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password')); + DI::baseUrl() + ->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password')); } break; case 'trusted': if ($has_secret) { - DI::baseUrl()->redirect('settings/2fa/trusted?t=' . self::getFormSecurityToken('settings_2fa_password')); + DI::baseUrl() + ->redirect('settings/2fa/trusted?t=' . self::getFormSecurityToken('settings_2fa_password')); } break; case 'configure': if (!$verified) { - DI::baseUrl()->redirect('settings/2fa/verify?t=' . self::getFormSecurityToken('settings_2fa_password')); + DI::baseUrl() + ->redirect('settings/2fa/verify?t=' . self::getFormSecurityToken('settings_2fa_password')); } break; } + } catch (FoundException $exception) { + // Nothing to do here } catch (\Exception $e) { - notice(DI::l10n()->t('Wrong Password')); + notice(DI::l10n()->t($e->getMessage())); } } diff --git a/src/Module/Settings/TwoFactor/Trusted.php b/src/Module/Settings/TwoFactor/Trusted.php index 12327a5918..140394e077 100644 --- a/src/Module/Settings/TwoFactor/Trusted.php +++ b/src/Module/Settings/TwoFactor/Trusted.php @@ -77,7 +77,7 @@ class Trusted extends BaseSettings self::checkFormSecurityTokenRedirectOnError('settings/2fa/trusted', 'settings_2fa_trusted'); switch ($_POST['action']) { - case 'remove_all' : + case 'remove_all': $this->trustedBrowserRepo->removeAllForUser(local_user()); info($this->t('Trusted browsers successfully removed.')); $this->baseUrl->redirect('settings/2fa/trusted?t=' . self::getFormSecurityToken('settings_2fa_password')); @@ -118,29 +118,31 @@ class Trusted extends BaseSettings $result = $parser->parse($trustedBrowser->user_agent); $uaData = [ - 'os' => $result->os->family, - 'device' => $result->device->family, - 'browser' => $result->ua->family, + 'os' => $result->os->family, + 'device' => $result->device->family, + 'browser' => $result->ua->family, + 'trusted_labeled' => $trustedBrowser->trusted ? $this->t('Yes') : $this->t('No'), ]; return $trustedBrowser->toArray() + $dates + $uaData; }, $trustedBrowsers->getArrayCopy()); return Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/twofactor/trusted_browsers.tpl'), [ - '$form_security_token' => self::getFormSecurityToken('settings_2fa_trusted'), + '$form_security_token' => self::getFormSecurityToken('settings_2fa_trusted'), '$password_security_token' => self::getFormSecurityToken('settings_2fa_password'), - '$title' => $this->t('Two-factor Trusted Browsers'), - '$message' => $this->t('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.'), - '$device_label' => $this->t('Device'), - '$os_label' => $this->t('OS'), - '$browser_label' => $this->t('Browser'), - '$created_label' => $this->t('Trusted'), - '$last_used_label' => $this->t('Last Use'), - '$remove_label' => $this->t('Remove'), - '$remove_all_label' => $this->t('Remove All'), + '$title' => $this->t('Two-factor Trusted Browsers'), + '$message' => $this->t('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.'), + '$device_label' => $this->t('Device'), + '$os_label' => $this->t('OS'), + '$browser_label' => $this->t('Browser'), + '$trusted_label' => $this->t('Trusted'), + '$created_label' => $this->t('Created At'), + '$last_used_label' => $this->t('Last Use'), + '$remove_label' => $this->t('Remove'), + '$remove_all_label' => $this->t('Remove All'), - '$trusted_browsers' => $trustedBrowserDisplay, + '$trusted_browsers' => $trustedBrowserDisplay, ]); } } diff --git a/src/Module/Settings/UserExport.php b/src/Module/Settings/UserExport.php index 2d29f4d647..4dfbdb99eb 100644 --- a/src/Module/Settings/UserExport.php +++ b/src/Module/Settings/UserExport.php @@ -124,7 +124,7 @@ class UserExport extends BaseSettings */ private static function exportMultiRow(string $query) { - $dbStructure = DBStructure::definition(DI::app()->getBasePath(), false); + $dbStructure = DI::dbaDefinition()->getAll(); preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match); $table = $match[1]; @@ -156,7 +156,7 @@ class UserExport extends BaseSettings */ private static function exportRow(string $query) { - $dbStructure = DBStructure::definition(DI::app()->getBasePath(), false); + $dbStructure = DI::dbaDefinition()->getAll(); preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match); $table = $match[1]; diff --git a/src/Navigation/Notifications/Factory/Notification.php b/src/Navigation/Notifications/Factory/Notification.php index 10c8b54a0e..5c1f74df4f 100644 --- a/src/Navigation/Notifications/Factory/Notification.php +++ b/src/Navigation/Notifications/Factory/Notification.php @@ -183,6 +183,13 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow } } + // Final check on $link_item + // @see https://github.com/friendica/friendica/issues/11632#issuecomment-1183365937 + if (empty($link_item)) { + $this->logger->info('Link item is still empty. Dumping whole Notification object:', [$Notification]); + return $message; + } + $link = $this->baseUrl . '/display/' . urlencode($link_item['guid']); $body = BBCode::toPlaintext($item['body'], false); diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index be5c6d7318..7157868f54 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -32,6 +32,7 @@ use Friendica\Core\L10n; use Friendica\Core\System; use Friendica\Database\Database; use Friendica\Database\DBA; +use Friendica\Factory\Api\Mastodon\Notification as NotificationFactory; use Friendica\Model; use Friendica\Navigation\Notifications\Collection; use Friendica\Navigation\Notifications\Entity; @@ -660,7 +661,7 @@ class Notify extends BaseRepository public function NotifyOnDesktop(Entity\Notification $Notification, string $type = null): bool { if (is_null($type)) { - $type = \Friendica\Factory\Api\Mastodon\Notification::getType($Notification); + $type = NotificationFactory::getType($Notification); } if (in_array($Notification->type, [Model\Post\UserNotification::TYPE_FOLLOW, Model\Post\UserNotification::TYPE_SHARED])) { diff --git a/src/Network/HTTPClient/Capability/ICanHandleHttpResponses.php b/src/Network/HTTPClient/Capability/ICanHandleHttpResponses.php index e2db2f50fc..b6f0c6f3e2 100644 --- a/src/Network/HTTPClient/Capability/ICanHandleHttpResponses.php +++ b/src/Network/HTTPClient/Capability/ICanHandleHttpResponses.php @@ -33,14 +33,14 @@ interface ICanHandleHttpResponses * * @return string The Return Code */ - public function getReturnCode(); + public function getReturnCode(): string; /** * Returns the Content Type * * @return string the Content Type */ - public function getContentType(); + public function getContentType(): string; /** * Returns the headers @@ -55,21 +55,20 @@ interface ICanHandleHttpResponses /** * Returns all headers - * @see MessageInterface::getHeaders() * + * @see MessageInterface::getHeaders() * @return string[][] */ public function getHeaders(); /** * Check if a specified header exists + * * @see MessageInterface::hasHeader() - * * @param string $field header field - * * @return boolean "true" if header exists */ - public function inHeader(string $field); + public function inHeader(string $field): bool; /** * Returns the headers as an associated array @@ -83,21 +82,22 @@ interface ICanHandleHttpResponses /** * @return bool */ - public function isSuccess(); + public function isSuccess(): bool; /** * @return string */ - public function getUrl(); + public function getUrl(): string; /** * @return string */ - public function getRedirectUrl(); + public function getRedirectUrl(): string; /** - * @see MessageInterface::getBody() + * Getter for body * + * @see MessageInterface::getBody() * @return string */ public function getBody(); @@ -105,20 +105,20 @@ interface ICanHandleHttpResponses /** * @return boolean */ - public function isRedirectUrl(); + public function isRedirectUrl(): bool; /** * @return integer */ - public function getErrorNumber(); + public function getErrorNumber(): int; /** * @return string */ - public function getError(); + public function getError(): string; /** * @return boolean */ - public function isTimeout(); + public function isTimeout(): bool; } diff --git a/src/Network/HTTPClient/Factory/HttpClient.php b/src/Network/HTTPClient/Factory/HttpClient.php index b3fd76936e..29ef3c09eb 100644 --- a/src/Network/HTTPClient/Factory/HttpClient.php +++ b/src/Network/HTTPClient/Factory/HttpClient.php @@ -94,11 +94,11 @@ class HttpClient extends BaseFactory $guzzle = new GuzzleHttp\Client([ RequestOptions::ALLOW_REDIRECTS => [ - 'max' => 8, - 'on_redirect' => $onRedirect, - 'track_redirect' => true, - 'strict' => true, - 'referer' => true, + 'max' => 8, + 'on_redirect' => $onRedirect, + 'track_redirects' => true, + 'strict' => true, + 'referer' => true, ], RequestOptions::HTTP_ERRORS => false, // Without this setting it seems as if some webservers send compressed content diff --git a/src/Network/HTTPException.php b/src/Network/HTTPException.php index f59ff547c9..7ef1ca9828 100644 --- a/src/Network/HTTPException.php +++ b/src/Network/HTTPException.php @@ -34,7 +34,7 @@ abstract class HTTPException extends Exception protected $httpdesc = ''; protected $explanation = ''; - public function __construct($message = '', Exception $previous = null) + public function __construct(string $message = '', Exception $previous = null) { parent::__construct($message, $this->code, $previous); } diff --git a/src/Network/Probe.php b/src/Network/Probe.php index c5ecf96ed3..c54ddc8e99 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -85,18 +85,17 @@ class Probe * Rearrange the array so that it always has the same order * * @param array $data Unordered data - * * @return array Ordered data */ - private static function rearrangeData($data) + private static function rearrangeData(array $data): array { - $fields = ["name", "nick", "guid", "url", "addr", "alias", "photo", "header", - "account-type", "community", "keywords", "location", "about", "xmpp", "matrix", - "hide", "batch", "notify", "poll", "request", "confirm", "subscribe", "poco", - "following", "followers", "inbox", "outbox", "sharedinbox", - "priority", "network", "pubkey", "manually-approve", "baseurl", "gsid"]; + $fields = ['name', 'nick', 'guid', 'url', 'addr', 'alias', 'photo', 'header', + 'account-type', 'community', 'keywords', 'location', 'about', 'xmpp', 'matrix', + 'hide', 'batch', 'notify', 'poll', 'request', 'confirm', 'subscribe', 'poco', + 'following', 'followers', 'inbox', 'outbox', 'sharedinbox', + 'priority', 'network', 'pubkey', 'manually-approve', 'baseurl', 'gsid']; - $numeric_fields = ["gsid", "hide", "account-type", "manually-approve"]; + $numeric_fields = ['gsid', 'hide', 'account-type', 'manually-approve']; $newdata = []; foreach ($fields as $field) { @@ -107,14 +106,14 @@ class Probe $newdata[$field] = $data[$field]; } } elseif (!in_array($field, $numeric_fields)) { - $newdata[$field] = ""; + $newdata[$field] = ''; } else { $newdata[$field] = null; } } // We don't use the "priority" field anymore and replace it with a dummy. - $newdata["priority"] = 0; + $newdata['priority'] = 0; return $newdata; } @@ -123,10 +122,9 @@ class Probe * Check if the hostname belongs to the own server * * @param string $host The hostname that is to be checked - * * @return bool Does the testes hostname belongs to the own server? */ - private static function ownHost($host) + private static function ownHost(string $host): bool { $own_host = DI::baseUrl()->getHostname(); @@ -149,21 +147,20 @@ class Probe * It seems as if it was dropped from the standard. * * @param string $host The host part of an url - * * @return array with template and type of the webfinger template for JSON or XML * @throws HTTPException\InternalServerErrorException */ - private static function hostMeta($host) + private static function hostMeta(string $host): array { // Reset the static variable self::$baseurl = ''; // Handles the case when the hostname contains the scheme if (!parse_url($host, PHP_URL_SCHEME)) { - $ssl_url = "https://" . $host . "/.well-known/host-meta"; - $url = "http://" . $host . "/.well-known/host-meta"; + $ssl_url = 'https://' . $host . '/.well-known/host-meta'; + $url = 'http://' . $host . '/.well-known/host-meta'; } else { - $ssl_url = $host . "/.well-known/host-meta"; + $ssl_url = $host . '/.well-known/host-meta'; $url = ''; } @@ -210,26 +207,26 @@ class Probe } $links = XML::elementToArray($xrd); - if (!isset($links["xrd"]["link"])) { + if (!isset($links['xrd']['link'])) { Logger::info('No xrd data found', ['host' => $host]); return []; } $lrdd = []; - foreach ($links["xrd"]["link"] as $value => $link) { - if (!empty($link["@attributes"])) { - $attributes = $link["@attributes"]; - } elseif ($value == "@attributes") { + foreach ($links['xrd']['link'] as $value => $link) { + if (!empty($link['@attributes'])) { + $attributes = $link['@attributes']; + } elseif ($value == '@attributes') { $attributes = $link; } else { continue; } - if (!empty($attributes["rel"]) && $attributes["rel"] == "lrdd" && !empty($attributes["template"])) { - $type = (empty($attributes["type"]) ? '' : $attributes["type"]); + if (!empty($attributes['rel']) && $attributes['rel'] == 'lrdd' && !empty($attributes['template'])) { + $type = (empty($attributes['type']) ? '' : $attributes['type']); - $lrdd[$type] = $attributes["template"]; + $lrdd[$type] = $attributes['template']; } } @@ -249,11 +246,10 @@ class Probe * Check an URI for LRDD data * * @param string $uri Address that should be probed - * * @return array uri data * @throws HTTPException\InternalServerErrorException */ - public static function lrdd(string $uri) + public static function lrdd(string $uri): array { $data = self::getWebfingerArray($uri); if (empty($data)) { @@ -261,22 +257,25 @@ class Probe } $webfinger = $data['webfinger']; - if (empty($webfinger["links"])) { + if (empty($webfinger['links'])) { Logger::info('No webfinger links found', ['uri' => $uri]); return []; } $data = []; - foreach ($webfinger["links"] as $link) { - $data[] = ["@attributes" => $link]; + foreach ($webfinger['links'] as $link) { + $data[] = ['@attributes' => $link]; } - if (!empty($webfinger["aliases"]) && is_array($webfinger["aliases"])) { - foreach ($webfinger["aliases"] as $alias) { - $data[] = ["@attributes" => - ["rel" => "alias", - "href" => $alias]]; + if (!empty($webfinger['aliases']) && is_array($webfinger['aliases'])) { + foreach ($webfinger['aliases'] as $alias) { + $data[] = [ + '@attributes' => [ + 'rel' => 'alias', + 'href' => $alias, + ] + ]; } } @@ -383,10 +382,9 @@ class Probe * Fetches the "hide" status from the profile * * @param string $url URL of the profile - * * @return boolean "hide" status */ - private static function getHideStatus($url) + private static function getHideStatus(string $url): bool { $curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML, [HttpClientOptions::CONTENT_LENGTH => 1000000]); if (!$curlResult->isSuccess()) { @@ -443,11 +441,11 @@ class Probe /** * Fetch the "subscribe" and add it to the result * - * @param array $result - * @param array $webfinger - * @return array result + * @param array $result Result array + * @param array $webfinger Webfinger data + * @return array result Altered/unaltered result array */ - private static function getSubscribeLink(array $result, array $webfinger) + private static function getSubscribeLink(array $result, array $webfinger): array { if (empty($webfinger['links'])) { return $result; @@ -465,8 +463,8 @@ class Probe /** * Get webfinger data from a given URI * - * @param string $uri - * @return array + * @param string $uri URI + * @return array Webfinger data * @throws HTTPException\InternalServerErrorException */ private static function getWebfingerArray(string $uri): array @@ -583,7 +581,7 @@ class Probe * @param string $addr * @return array webfinger results */ - private static function getWebfinger(string $template, string $type, string $uri, string $addr) + private static function getWebfinger(string $template, string $type, string $uri, string $addr): array { if (Network::isUrlBlocked($template)) { Logger::info('Domain is blocked', ['url' => $template]); @@ -593,7 +591,7 @@ class Probe // First try the address because this is the primary purpose of webfinger if (!empty($addr)) { $detected = $addr; - $path = str_replace('{uri}', urlencode("acct:" . $addr), $template); + $path = str_replace('{uri}', urlencode('acct:' . $addr), $template); $webfinger = self::webfinger($path, $type); if (self::$istimeout) { return []; @@ -626,11 +624,10 @@ class Probe * @param string $network Test for this specific network * @param integer $uid User ID for the probe (only used for mails) * @param array $ap_profile Previously probed AP profile - * - * @return array uri data + * @return array URI data * @throws HTTPException\InternalServerErrorException */ - private static function detect(string $uri, string $network, int $uid, array $ap_profile) + private static function detect(string $uri, string $network, int $uid, array $ap_profile): array { $hookData = [ 'uri' => $uri, @@ -688,19 +685,19 @@ class Probe $result = []; - if (in_array($network, ["", Protocol::DFRN])) { + if (in_array($network, ['', Protocol::DFRN])) { $result = self::dfrn($webfinger); } - if ((!$result && ($network == "")) || ($network == Protocol::DIASPORA)) { + if ((!$result && ($network == '')) || ($network == Protocol::DIASPORA)) { $result = self::diaspora($webfinger); } - if ((!$result && ($network == "")) || ($network == Protocol::OSTATUS)) { + if ((!$result && ($network == '')) || ($network == Protocol::OSTATUS)) { $result = self::ostatus($webfinger); } if (in_array($network, ['', Protocol::ZOT])) { $result = self::zot($webfinger, $result, $baseurl); } - if ((!$result && ($network == "")) || ($network == Protocol::PUMPIO)) { + if ((!$result && ($network == '')) || ($network == Protocol::PUMPIO)) { $result = self::pumpio($webfinger, $addr); } if (empty($result['network']) && empty($ap_profile['network']) || ($network == Protocol::FEED)) { @@ -708,30 +705,30 @@ class Probe } else { // We overwrite the detected nick with our try if the previois routines hadn't detected it. // Additionally it is overwritten when the nickname doesn't make sense (contains spaces). - if ((empty($result["nick"]) || (strstr($result["nick"], " "))) && ($nick != "")) { - $result["nick"] = $nick; + if ((empty($result['nick']) || (strstr($result['nick'], ' '))) && ($nick != '')) { + $result['nick'] = $nick; } - if (empty($result["addr"]) && ($addr != "")) { - $result["addr"] = $addr; + if (empty($result['addr']) && ($addr != '')) { + $result['addr'] = $addr; } } $result = self::getSubscribeLink($result, $webfinger); - if (empty($result["network"])) { - $result["network"] = Protocol::PHANTOM; + if (empty($result['network'])) { + $result['network'] = Protocol::PHANTOM; } if (empty($result['baseurl']) && !empty($baseurl)) { $result['baseurl'] = $baseurl; } - if (empty($result["url"])) { - $result["url"] = $uri; + if (empty($result['url'])) { + $result['url'] = $uri; } - Logger::info('Probing done', ['uri' => $uri, 'network' => $result["network"]]); + Logger::info('Probing done', ['uri' => $uri, 'network' => $result['network']]); return $result; } @@ -739,24 +736,24 @@ class Probe /** * Check for Zot contact * - * @param array $webfinger Webfinger data - * @param array $data previously probed data - * + * @param array $webfinger Webfinger data + * @param array $data previously probed data + * @param string $baseUrl Base URL * @return array Zot data * @throws HTTPException\InternalServerErrorException */ - private static function zot($webfinger, $data, $baseurl) + private static function zot(array $webfinger, array $data, string $baseurl): array { - if (!empty($webfinger["aliases"]) && is_array($webfinger["aliases"])) { - foreach ($webfinger["aliases"] as $alias) { + if (!empty($webfinger['aliases']) && is_array($webfinger['aliases'])) { + foreach ($webfinger['aliases'] as $alias) { if (substr($alias, 0, 5) == 'acct:') { - $data["addr"] = substr($alias, 5); + $data['addr'] = substr($alias, 5); } } } - if (!empty($webfinger["subject"]) && (substr($webfinger["subject"], 0, 5) == "acct:")) { - $data["addr"] = substr($webfinger["subject"], 5); + if (!empty($webfinger['subject']) && (substr($webfinger['subject'], 0, 5) == 'acct:')) { + $data['addr'] = substr($webfinger['subject'], 5); } $zot_url = ''; @@ -791,7 +788,7 @@ class Probe return $data; } - public static function pollZot($url, $data) + public static function pollZot(string $url, array $data): array { $curlResult = DI::httpClient()->get($url, HttpClientAccept::JSON); if ($curlResult->isTimeout()) { @@ -882,11 +879,10 @@ class Probe * * @param string $url Address that should be probed * @param string $type type - * * @return array webfinger data * @throws HTTPException\InternalServerErrorException */ - public static function webfinger($url, $type) + public static function webfinger(string $url, string $type): array { $xrd_timeout = DI::config()->get('system', 'xrd_timeout', 20); @@ -899,7 +895,7 @@ class Probe $webfinger = json_decode($data, true); if (!empty($webfinger)) { - if (!isset($webfinger["links"])) { + if (!isset($webfinger['links'])) { Logger::info('No json webfinger links', ['url' => $url]); return []; } @@ -914,33 +910,33 @@ class Probe } $xrd_arr = XML::elementToArray($xrd); - if (!isset($xrd_arr["xrd"]["link"])) { + if (!isset($xrd_arr['xrd']['link'])) { Logger::info('No XML webfinger links', ['url' => $url]); return []; } $webfinger = []; - if (!empty($xrd_arr["xrd"]["subject"])) { - $webfinger["subject"] = $xrd_arr["xrd"]["subject"]; + if (!empty($xrd_arr['xrd']['subject'])) { + $webfinger['subject'] = $xrd_arr['xrd']['subject']; } - if (!empty($xrd_arr["xrd"]["alias"])) { - $webfinger["aliases"] = $xrd_arr["xrd"]["alias"]; + if (!empty($xrd_arr['xrd']['alias'])) { + $webfinger['aliases'] = $xrd_arr['xrd']['alias']; } - $webfinger["links"] = []; + $webfinger['links'] = []; - foreach ($xrd_arr["xrd"]["link"] as $value => $data) { - if (!empty($data["@attributes"])) { - $attributes = $data["@attributes"]; - } elseif ($value == "@attributes") { + foreach ($xrd_arr['xrd']['link'] as $value => $data) { + if (!empty($data['@attributes'])) { + $attributes = $data['@attributes']; + } elseif ($value == '@attributes') { $attributes = $data; } else { continue; } - $webfinger["links"][] = $attributes; + $webfinger['links'][] = $attributes; } return $webfinger; } @@ -953,11 +949,10 @@ class Probe * * @param string $noscrape_url Link to the noscrape page * @param array $data The already fetched data - * * @return array noscrape data * @throws HTTPException\InternalServerErrorException */ - private static function pollNoscrape($noscrape_url, $data) + private static function pollNoscrape(string $noscrape_url, array $data): array { $curlResult = DI::httpClient()->get($noscrape_url, HttpClientAccept::JSON); if ($curlResult->isTimeout()) { @@ -976,78 +971,78 @@ class Probe return $data; } - if (!empty($json["fn"])) { - $data["name"] = $json["fn"]; + if (!empty($json['fn'])) { + $data['name'] = $json['fn']; } - if (!empty($json["addr"])) { - $data["addr"] = $json["addr"]; + if (!empty($json['addr'])) { + $data['addr'] = $json['addr']; } - if (!empty($json["nick"])) { - $data["nick"] = $json["nick"]; + if (!empty($json['nick'])) { + $data['nick'] = $json['nick']; } - if (!empty($json["guid"])) { - $data["guid"] = $json["guid"]; + if (!empty($json['guid'])) { + $data['guid'] = $json['guid']; } - if (!empty($json["comm"])) { - $data["community"] = $json["comm"]; + if (!empty($json['comm'])) { + $data['community'] = $json['comm']; } - if (!empty($json["tags"])) { - $keywords = implode(", ", $json["tags"]); - if ($keywords != "") { - $data["keywords"] = $keywords; + if (!empty($json['tags'])) { + $keywords = implode(', ', $json['tags']); + if ($keywords != '') { + $data['keywords'] = $keywords; } } $location = Profile::formatLocation($json); if ($location) { - $data["location"] = $location; + $data['location'] = $location; } - if (!empty($json["about"])) { - $data["about"] = $json["about"]; + if (!empty($json['about'])) { + $data['about'] = $json['about']; } - if (!empty($json["xmpp"])) { - $data["xmpp"] = $json["xmpp"]; + if (!empty($json['xmpp'])) { + $data['xmpp'] = $json['xmpp']; } - if (!empty($json["matrix"])) { - $data["matrix"] = $json["matrix"]; + if (!empty($json['matrix'])) { + $data['matrix'] = $json['matrix']; } - if (!empty($json["key"])) { - $data["pubkey"] = $json["key"]; + if (!empty($json['key'])) { + $data['pubkey'] = $json['key']; } - if (!empty($json["photo"])) { - $data["photo"] = $json["photo"]; + if (!empty($json['photo'])) { + $data['photo'] = $json['photo']; } - if (!empty($json["dfrn-request"])) { - $data["request"] = $json["dfrn-request"]; + if (!empty($json['dfrn-request'])) { + $data['request'] = $json['dfrn-request']; } - if (!empty($json["dfrn-confirm"])) { - $data["confirm"] = $json["dfrn-confirm"]; + if (!empty($json['dfrn-confirm'])) { + $data['confirm'] = $json['dfrn-confirm']; } - if (!empty($json["dfrn-notify"])) { - $data["notify"] = $json["dfrn-notify"]; + if (!empty($json['dfrn-notify'])) { + $data['notify'] = $json['dfrn-notify']; } - if (!empty($json["dfrn-poll"])) { - $data["poll"] = $json["dfrn-poll"]; + if (!empty($json['dfrn-poll'])) { + $data['poll'] = $json['dfrn-poll']; } - if (isset($json["hide"])) { - $data["hide"] = (bool)$json["hide"]; + if (isset($json['hide'])) { + $data['hide'] = (bool)$json['hide']; } else { - $data["hide"] = false; + $data['hide'] = false; } return $data; @@ -1085,48 +1080,47 @@ class Probe * Fetch data from a DFRN profile page and via "noscrape" * * @param string $profile_link Link to the profile page - * * @return array profile data * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function profile($profile_link) + public static function profile(string $profile_link): array { $data = []; Logger::info('Check profile', ['link' => $profile_link]); // Fetch data via noscrape - this is faster - $noscrape_url = str_replace(["/hcard/", "/profile/"], "/noscrape/", $profile_link); + $noscrape_url = str_replace(['/hcard/', '/profile/'], '/noscrape/', $profile_link); $data = self::pollNoscrape($noscrape_url, $data); - if (!isset($data["notify"]) - || !isset($data["confirm"]) - || !isset($data["request"]) - || !isset($data["poll"]) - || !isset($data["name"]) - || !isset($data["photo"]) + if (!isset($data['notify']) + || !isset($data['confirm']) + || !isset($data['request']) + || !isset($data['poll']) + || !isset($data['name']) + || !isset($data['photo']) ) { $data = self::pollHcard($profile_link, $data, true); } $prof_data = []; - if (empty($data["addr"]) || empty($data["nick"])) { + if (empty($data['addr']) || empty($data['nick'])) { $probe_data = self::uri($profile_link); - $data["addr"] = ($data["addr"] ?? '') ?: $probe_data["addr"]; - $data["nick"] = ($data["nick"] ?? '') ?: $probe_data["nick"]; + $data['addr'] = ($data['addr'] ?? '') ?: $probe_data['addr']; + $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']; + $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; Logger::debug('Result', ['link' => $profile_link, 'data' => $prof_data]); @@ -1137,73 +1131,71 @@ class Probe * Check for DFRN contact * * @param array $webfinger Webfinger data - * * @return array DFRN data * @throws HTTPException\InternalServerErrorException */ - private static function dfrn($webfinger) + private static function dfrn(array $webfinger): array { - $hcard_url = ""; + $hcard_url = ''; $data = []; // The array is reversed to take into account the order of preference for same-rel links // See: https://tools.ietf.org/html/rfc7033#section-4.4.4 - foreach (array_reverse($webfinger["links"]) as $link) { - if (($link["rel"] == ActivityNamespace::DFRN) && !empty($link["href"])) { - $data["network"] = Protocol::DFRN; - } elseif (($link["rel"] == ActivityNamespace::FEED) && !empty($link["href"])) { - $data["poll"] = $link["href"]; - } elseif (($link["rel"] == "http://webfinger.net/rel/profile-page") && (($link["type"] ?? "") == "text/html") && !empty($link["href"])) { - $data["url"] = $link["href"]; - } elseif (($link["rel"] == "http://microformats.org/profile/hcard") && !empty($link["href"])) { - $hcard_url = $link["href"]; - } elseif (($link["rel"] == ActivityNamespace::POCO) && !empty($link["href"])) { - $data["poco"] = $link["href"]; - } elseif (($link["rel"] == "http://webfinger.net/rel/avatar") && !empty($link["href"])) { - $data["photo"] = $link["href"]; - } elseif (($link["rel"] == "http://joindiaspora.com/seed_location") && !empty($link["href"])) { - $data["baseurl"] = trim($link["href"], '/'); - } elseif (($link["rel"] == "http://joindiaspora.com/guid") && !empty($link["href"])) { - $data["guid"] = $link["href"]; - } elseif (($link["rel"] == "diaspora-public-key") && !empty($link["href"])) { - $data["pubkey"] = base64_decode($link["href"]); + foreach (array_reverse($webfinger['links']) as $link) { + if (($link['rel'] == ActivityNamespace::DFRN) && !empty($link['href'])) { + $data['network'] = Protocol::DFRN; + } elseif (($link['rel'] == ActivityNamespace::FEED) && !empty($link['href'])) { + $data['poll'] = $link['href']; + } elseif (($link['rel'] == 'http://webfinger.net/rel/profile-page') && (($link['type'] ?? '') == 'text/html') && !empty($link['href'])) { + $data['url'] = $link['href']; + } elseif (($link['rel'] == 'http://microformats.org/profile/hcard') && !empty($link['href'])) { + $hcard_url = $link['href']; + } elseif (($link['rel'] == ActivityNamespace::POCO) && !empty($link['href'])) { + $data['poco'] = $link['href']; + } elseif (($link['rel'] == 'http://webfinger.net/rel/avatar') && !empty($link['href'])) { + $data['photo'] = $link['href']; + } elseif (($link['rel'] == 'http://joindiaspora.com/seed_location') && !empty($link['href'])) { + $data['baseurl'] = trim($link['href'], '/'); + } elseif (($link['rel'] == 'http://joindiaspora.com/guid') && !empty($link['href'])) { + $data['guid'] = $link['href']; + } elseif (($link['rel'] == 'diaspora-public-key') && !empty($link['href'])) { + $data['pubkey'] = base64_decode($link['href']); - //if (strstr($data["pubkey"], 'RSA ') || ($link["type"] == "RSA")) - if (strstr($data["pubkey"], 'RSA ')) { - $data["pubkey"] = Crypto::rsaToPem($data["pubkey"]); + if (strstr($data['pubkey'], 'RSA ')) { + $data['pubkey'] = Crypto::rsaToPem($data['pubkey']); } } } - if (!empty($webfinger["aliases"]) && is_array($webfinger["aliases"])) { - foreach ($webfinger["aliases"] as $alias) { - if (empty($data["url"]) && !strstr($alias, "@")) { - $data["url"] = $alias; - } elseif (!strstr($alias, "@") && Strings::normaliseLink($alias) != Strings::normaliseLink($data["url"])) { - $data["alias"] = $alias; + if (!empty($webfinger['aliases']) && is_array($webfinger['aliases'])) { + foreach ($webfinger['aliases'] as $alias) { + if (empty($data['url']) && !strstr($alias, '@')) { + $data['url'] = $alias; + } elseif (!strstr($alias, '@') && Strings::normaliseLink($alias) != Strings::normaliseLink($data['url'])) { + $data['alias'] = $alias; } elseif (substr($alias, 0, 5) == 'acct:') { - $data["addr"] = substr($alias, 5); + $data['addr'] = substr($alias, 5); } } } - if (!empty($webfinger["subject"]) && (substr($webfinger["subject"], 0, 5) == "acct:")) { - $data["addr"] = substr($webfinger["subject"], 5); + if (!empty($webfinger['subject']) && (substr($webfinger['subject'], 0, 5) == 'acct:')) { + $data['addr'] = substr($webfinger['subject'], 5); } - if (!isset($data["network"]) || ($hcard_url == "")) { + if (!isset($data['network']) || ($hcard_url == '')) { return []; } // Fetch data via noscrape - this is faster - $noscrape_url = str_replace("/hcard/", "/noscrape/", $hcard_url); + $noscrape_url = str_replace('/hcard/', '/noscrape/', $hcard_url); $data = self::pollNoscrape($noscrape_url, $data); - if (isset($data["notify"]) - && isset($data["confirm"]) - && isset($data["request"]) - && isset($data["poll"]) - && isset($data["name"]) - && isset($data["photo"]) + if (isset($data['notify']) + && isset($data['confirm']) + && isset($data['request']) + && isset($data['poll']) + && isset($data['name']) + && isset($data['photo']) ) { return $data; } @@ -1219,11 +1211,10 @@ class Probe * @param string $hcard_url Link to the hcard page * @param array $data The already fetched data * @param boolean $dfrn Poll DFRN specific data - * * @return array hcard data * @throws HTTPException\InternalServerErrorException */ - private static function pollHcard($hcard_url, $data, $dfrn = false) + private static function pollHcard(string $hcard_url, array $data, bool $dfrn = false): array { $curlResult = DI::httpClient()->get($hcard_url, HttpClientAccept::HTML); if ($curlResult->isTimeout()) { @@ -1247,8 +1238,8 @@ class Probe return []; } - if (!isset($data["baseurl"])) { - $data["baseurl"] = ""; + if (!isset($data['baseurl'])) { + $data['baseurl'] = ''; } if ($vcards->length > 0) { @@ -1257,36 +1248,36 @@ class Probe // We have to discard the guid from the hcard in favour of the guid from lrdd // Reason: Hubzilla doesn't use the value "uid" in the hcard like Diaspora does. $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' uid ')]", $vcard); // */ - if (($search->length > 0) && empty($data["guid"])) { - $data["guid"] = $search->item(0)->nodeValue; + if (($search->length > 0) && empty($data['guid'])) { + $data['guid'] = $search->item(0)->nodeValue; } $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' nickname ')]", $vcard); // */ if ($search->length > 0) { - $data["nick"] = $search->item(0)->nodeValue; + $data['nick'] = $search->item(0)->nodeValue; } $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' fn ')]", $vcard); // */ if ($search->length > 0) { - $data["name"] = $search->item(0)->nodeValue; + $data['name'] = $search->item(0)->nodeValue; } $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' searchable ')]", $vcard); // */ if ($search->length > 0) { - $data["searchable"] = $search->item(0)->nodeValue; + $data['searchable'] = $search->item(0)->nodeValue; } $search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' key ')]", $vcard); // */ if ($search->length > 0) { - $data["pubkey"] = $search->item(0)->nodeValue; - if (strstr($data["pubkey"], 'RSA ')) { - $data["pubkey"] = Crypto::rsaToPem($data["pubkey"]); + $data['pubkey'] = $search->item(0)->nodeValue; + if (strstr($data['pubkey'], 'RSA ')) { + $data['pubkey'] = Crypto::rsaToPem($data['pubkey']); } } $search = $xpath->query("//*[@id='pod_location']", $vcard); // */ if ($search->length > 0) { - $data["baseurl"] = trim($search->item(0)->nodeValue, "/"); + $data['baseurl'] = trim($search->item(0)->nodeValue, '/'); } } @@ -1299,21 +1290,21 @@ class Probe $attr[$attribute->name] = trim($attribute->value); } - if (isset($attr["src"]) && isset($attr["width"])) { - $avatar[$attr["width"]] = $attr["src"]; + if (isset($attr['src']) && isset($attr['width'])) { + $avatar[$attr['width']] = $attr['src']; } // We don't have a width. So we just take everything that we got. // This is a Hubzilla workaround which doesn't send a width. - if ((sizeof($avatar) == 0) && !empty($attr["src"])) { - $avatar[] = $attr["src"]; + if ((sizeof($avatar) == 0) && !empty($attr['src'])) { + $avatar[] = $attr['src']; } } } if (sizeof($avatar)) { ksort($avatar); - $data["photo"] = self::fixAvatar(array_pop($avatar), $data["baseurl"]); + $data['photo'] = self::fixAvatar(array_pop($avatar), $data['baseurl']); } if ($dfrn) { @@ -1321,19 +1312,19 @@ class Probe $search = $xpath->query("//link[contains(concat(' ', @rel), ' dfrn-')]"); if ($search->length > 0) { foreach ($search as $link) { - //$data["request"] = $search->item(0)->nodeValue; + //$data['request'] = $search->item(0)->nodeValue; $attr = []; foreach ($link->attributes as $attribute) { $attr[$attribute->name] = trim($attribute->value); } - $data[substr($attr["rel"], 5)] = $attr["href"]; + $data[substr($attr['rel'], 5)] = $attr['href']; } } // Older Friendica versions had used the "uid" field differently than newer versions - if (!empty($data["nick"]) && !empty($data["guid"]) && ($data["nick"] == $data["guid"])) { - unset($data["guid"]); + if (!empty($data['nick']) && !empty($data['guid']) && ($data['nick'] == $data['guid'])) { + unset($data['guid']); } } @@ -1345,64 +1336,62 @@ class Probe * Check for Diaspora contact * * @param array $webfinger Webfinger data - * * @return array Diaspora data * @throws HTTPException\InternalServerErrorException */ - private static function diaspora($webfinger) + private static function diaspora(array $webfinger): array { - $hcard_url = ""; + $hcard_url = ''; $data = []; // The array is reversed to take into account the order of preference for same-rel links // See: https://tools.ietf.org/html/rfc7033#section-4.4.4 - foreach (array_reverse($webfinger["links"]) as $link) { - if (($link["rel"] == "http://microformats.org/profile/hcard") && !empty($link["href"])) { - $hcard_url = $link["href"]; - } elseif (($link["rel"] == "http://joindiaspora.com/seed_location") && !empty($link["href"])) { - $data["baseurl"] = trim($link["href"], '/'); - } elseif (($link["rel"] == "http://joindiaspora.com/guid") && !empty($link["href"])) { - $data["guid"] = $link["href"]; - } elseif (($link["rel"] == "http://webfinger.net/rel/profile-page") && (($link["type"] ?? "") == "text/html") && !empty($link["href"])) { - $data["url"] = $link["href"]; - } elseif (($link["rel"] == "http://webfinger.net/rel/profile-page") && empty($link["type"]) && !empty($link["href"])) { - $profile_url = $link["href"]; - } elseif (($link["rel"] == ActivityNamespace::FEED) && !empty($link["href"])) { - $data["poll"] = $link["href"]; - } elseif (($link["rel"] == ActivityNamespace::POCO) && !empty($link["href"])) { - $data["poco"] = $link["href"]; - } elseif (($link["rel"] == "salmon") && !empty($link["href"])) { - $data["notify"] = $link["href"]; - } elseif (($link["rel"] == "diaspora-public-key") && !empty($link["href"])) { - $data["pubkey"] = base64_decode($link["href"]); + foreach (array_reverse($webfinger['links']) as $link) { + if (($link['rel'] == 'http://microformats.org/profile/hcard') && !empty($link['href'])) { + $hcard_url = $link['href']; + } elseif (($link['rel'] == 'http://joindiaspora.com/seed_location') && !empty($link['href'])) { + $data['baseurl'] = trim($link['href'], '/'); + } elseif (($link['rel'] == 'http://joindiaspora.com/guid') && !empty($link['href'])) { + $data['guid'] = $link['href']; + } elseif (($link['rel'] == 'http://webfinger.net/rel/profile-page') && (($link['type'] ?? '') == 'text/html') && !empty($link['href'])) { + $data['url'] = $link['href']; + } elseif (($link['rel'] == 'http://webfinger.net/rel/profile-page') && empty($link['type']) && !empty($link['href'])) { + $profile_url = $link['href']; + } elseif (($link['rel'] == ActivityNamespace::FEED) && !empty($link['href'])) { + $data['poll'] = $link['href']; + } elseif (($link['rel'] == ActivityNamespace::POCO) && !empty($link['href'])) { + $data['poco'] = $link['href']; + } elseif (($link['rel'] == 'salmon') && !empty($link['href'])) { + $data['notify'] = $link['href']; + } elseif (($link['rel'] == 'diaspora-public-key') && !empty($link['href'])) { + $data['pubkey'] = base64_decode($link['href']); - //if (strstr($data["pubkey"], 'RSA ') || ($link["type"] == "RSA")) - if (strstr($data["pubkey"], 'RSA ')) { - $data["pubkey"] = Crypto::rsaToPem($data["pubkey"]); + if (strstr($data['pubkey'], 'RSA ')) { + $data['pubkey'] = Crypto::rsaToPem($data['pubkey']); } } } - if (empty($data["url"]) && !empty($profile_url)) { - $data["url"] = $profile_url; + if (empty($data['url']) && !empty($profile_url)) { + $data['url'] = $profile_url; } - if (empty($data["url"]) || empty($hcard_url)) { + if (empty($data['url']) || empty($hcard_url)) { return []; } - if (!empty($webfinger["aliases"]) && is_array($webfinger["aliases"])) { - foreach ($webfinger["aliases"] as $alias) { - if (Strings::normaliseLink($alias) != Strings::normaliseLink($data["url"]) && ! strstr($alias, "@")) { - $data["alias"] = $alias; + if (!empty($webfinger['aliases']) && is_array($webfinger['aliases'])) { + foreach ($webfinger['aliases'] as $alias) { + if (Strings::normaliseLink($alias) != Strings::normaliseLink($data['url']) && ! strstr($alias, '@')) { + $data['alias'] = $alias; } elseif (substr($alias, 0, 5) == 'acct:') { - $data["addr"] = substr($alias, 5); + $data['addr'] = substr($alias, 5); } } } - if (!empty($webfinger["subject"]) && (substr($webfinger["subject"], 0, 5) == 'acct:')) { - $data["addr"] = substr($webfinger["subject"], 5); + if (!empty($webfinger['subject']) && (substr($webfinger['subject'], 0, 5) == 'acct:')) { + $data['addr'] = substr($webfinger['subject'], 5); } // Fetch further information from the hcard @@ -1412,23 +1401,23 @@ class Probe return []; } - if (!empty($data["url"]) - && !empty($data["guid"]) - && !empty($data["baseurl"]) - && !empty($data["pubkey"]) + if (!empty($data['url']) + && !empty($data['guid']) + && !empty($data['baseurl']) + && !empty($data['pubkey']) && !empty($hcard_url) ) { - $data["network"] = Protocol::DIASPORA; - $data["manually-approve"] = false; + $data['network'] = Protocol::DIASPORA; + $data['manually-approve'] = false; // The Diaspora handle must always be lowercase - if (!empty($data["addr"])) { - $data["addr"] = strtolower($data["addr"]); + if (!empty($data['addr'])) { + $data['addr'] = strtolower($data['addr']); } // We have to overwrite the detected value for "notify" since Hubzilla doesn't send it - $data["notify"] = $data["baseurl"] . "/receive/users/" . $data["guid"]; - $data["batch"] = $data["baseurl"] . "/receive/public"; + $data['notify'] = $data['baseurl'] . '/receive/users/' . $data['guid']; + $data['batch'] = $data['baseurl'] . '/receive/public'; } else { return []; } @@ -1441,43 +1430,42 @@ class Probe * * @param array $webfinger Webfinger data * @param bool $short Short detection mode - * * @return array|bool OStatus data or "false" on error or "true" on short mode * @throws HTTPException\InternalServerErrorException */ - private static function ostatus($webfinger, $short = false) + private static function ostatus(array $webfinger, bool $short = false) { $data = []; - if (!empty($webfinger["aliases"]) && is_array($webfinger["aliases"])) { - foreach ($webfinger["aliases"] as $alias) { - if (strstr($alias, "@") && !strstr(Strings::normaliseLink($alias), "http://")) { - $data["addr"] = str_replace('acct:', '', $alias); + if (!empty($webfinger['aliases']) && is_array($webfinger['aliases'])) { + foreach ($webfinger['aliases'] as $alias) { + if (strstr($alias, '@') && !strstr(Strings::normaliseLink($alias), 'http://')) { + $data['addr'] = str_replace('acct:', '', $alias); } } } - if (!empty($webfinger["subject"]) && strstr($webfinger["subject"], "@") - && !strstr(Strings::normaliseLink($webfinger["subject"]), "http://") + if (!empty($webfinger['subject']) && strstr($webfinger['subject'], '@') + && !strstr(Strings::normaliseLink($webfinger['subject']), 'http://') ) { - $data["addr"] = str_replace('acct:', '', $webfinger["subject"]); + $data['addr'] = str_replace('acct:', '', $webfinger['subject']); } - if (!empty($webfinger["links"])) { + if (!empty($webfinger['links'])) { // The array is reversed to take into account the order of preference for same-rel links // See: https://tools.ietf.org/html/rfc7033#section-4.4.4 - foreach (array_reverse($webfinger["links"]) as $link) { - if (($link["rel"] == "http://webfinger.net/rel/profile-page") - && (($link["type"] ?? "") == "text/html") - && ($link["href"] != "") + foreach (array_reverse($webfinger['links']) as $link) { + if (($link['rel'] == 'http://webfinger.net/rel/profile-page') + && (($link['type'] ?? '') == 'text/html') + && ($link['href'] != '') ) { - $data["url"] = $data["alias"] = $link["href"]; - } elseif (($link["rel"] == "salmon") && !empty($link["href"])) { - $data["notify"] = $link["href"]; - } elseif (($link["rel"] == ActivityNamespace::FEED) && !empty($link["href"])) { - $data["poll"] = $link["href"]; - } elseif (($link["rel"] == "magic-public-key") && !empty($link["href"])) { - $pubkey = $link["href"]; + $data['url'] = $data['alias'] = $link['href']; + } elseif (($link['rel'] == 'salmon') && !empty($link['href'])) { + $data['notify'] = $link['href']; + } elseif (($link['rel'] == ActivityNamespace::FEED) && !empty($link['href'])) { + $data['poll'] = $link['href']; + } elseif (($link['rel'] == 'magic-public-key') && !empty($link['href'])) { + $pubkey = $link['href']; if (substr($pubkey, 0, 5) === 'data:') { if (strstr($pubkey, ',')) { @@ -1495,23 +1483,23 @@ class Probe $pubkey = $curlResult->getBody(); } - $key = explode(".", $pubkey); + $key = explode('.', $pubkey); if (sizeof($key) >= 3) { $m = Strings::base64UrlDecode($key[1]); $e = Strings::base64UrlDecode($key[2]); - $data["pubkey"] = Crypto::meToPem($m, $e); + $data['pubkey'] = Crypto::meToPem($m, $e); } } } } - if (isset($data["notify"]) && isset($data["pubkey"]) - && isset($data["poll"]) - && isset($data["url"]) + if (isset($data['notify']) && isset($data['pubkey']) + && isset($data['poll']) + && isset($data['url']) ) { - $data["network"] = Protocol::OSTATUS; - $data["manually-approve"] = false; + $data['network'] = Protocol::OSTATUS; + $data['manually-approve'] = false; } else { return $short ? false : []; } @@ -1521,7 +1509,7 @@ class Probe } // Fetch all additional data from the feed - $curlResult = DI::httpClient()->get($data["poll"], HttpClientAccept::FEED_XML); + $curlResult = DI::httpClient()->get($data['poll'], HttpClientAccept::FEED_XML); if ($curlResult->isTimeout()) { self::$istimeout = true; return []; @@ -1532,32 +1520,32 @@ class Probe return []; } - if (!empty($feed_data["header"]["author-name"])) { - $data["name"] = $feed_data["header"]["author-name"]; + if (!empty($feed_data['header']['author-name'])) { + $data['name'] = $feed_data['header']['author-name']; } - if (!empty($feed_data["header"]["author-nick"])) { - $data["nick"] = $feed_data["header"]["author-nick"]; + if (!empty($feed_data['header']['author-nick'])) { + $data['nick'] = $feed_data['header']['author-nick']; } - if (!empty($feed_data["header"]["author-avatar"])) { - $data["photo"] = self::fixAvatar($feed_data["header"]["author-avatar"], $data["url"]); + if (!empty($feed_data['header']['author-avatar'])) { + $data['photo'] = self::fixAvatar($feed_data['header']['author-avatar'], $data['url']); } - if (!empty($feed_data["header"]["author-id"])) { - $data["alias"] = $feed_data["header"]["author-id"]; + if (!empty($feed_data['header']['author-id'])) { + $data['alias'] = $feed_data['header']['author-id']; } - if (!empty($feed_data["header"]["author-location"])) { - $data["location"] = $feed_data["header"]["author-location"]; + if (!empty($feed_data['header']['author-location'])) { + $data['location'] = $feed_data['header']['author-location']; } - if (!empty($feed_data["header"]["author-about"])) { - $data["about"] = $feed_data["header"]["author-about"]; + if (!empty($feed_data['header']['author-about'])) { + $data['about'] = $feed_data['header']['author-about']; } // OStatus has serious issues when the the url doesn't fit (ssl vs. non ssl) // So we take the value that we just fetched, although the other one worked as well - if (!empty($feed_data["header"]["author-link"])) { - $data["url"] = $feed_data["header"]["author-link"]; + if (!empty($feed_data['header']['author-link'])) { + $data['url'] = $feed_data['header']['author-link']; } - if ($data["url"] == $data["alias"]) { - $data["alias"] = ''; + if ($data['url'] == $data['alias']) { + $data['alias'] = ''; } /// @todo Fetch location and "about" from the feed as well @@ -1568,10 +1556,9 @@ class Probe * Fetch data from a pump.io profile page * * @param string $profile_link Link to the profile page - * - * @return array profile data + * @return array Profile data */ - private static function pumpioProfileData($profile_link) + private static function pumpioProfileData(string $profile_link): array { $curlResult = DI::httpClient()->get($profile_link, HttpClientAccept::HTML); if (!$curlResult->isSuccess() || empty($curlResult->getBody())) { @@ -1586,28 +1573,27 @@ class Probe $xpath = new DomXPath($doc); $data = []; + $data['name'] = $xpath->query("//span[contains(@class, 'p-name')]")->item(0)->nodeValue; - $data["name"] = $xpath->query("//span[contains(@class, 'p-name')]")->item(0)->nodeValue; - - if ($data["name"] == '') { + if ($data['name'] == '') { // This is ugly - but pump.io doesn't seem to know a better way for it - $data["name"] = trim($xpath->query("//h1[@class='media-header']")->item(0)->nodeValue); - $pos = strpos($data["name"], chr(10)); + $data['name'] = trim($xpath->query("//h1[@class='media-header']")->item(0)->nodeValue); + $pos = strpos($data['name'], chr(10)); if ($pos) { - $data["name"] = trim(substr($data["name"], 0, $pos)); + $data['name'] = trim(substr($data['name'], 0, $pos)); } } - $data["location"] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'p-locality')]"); + $data['location'] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'p-locality')]"); - if ($data["location"] == '') { - $data["location"] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'location')]"); + if ($data['location'] == '') { + $data['location'] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'location')]"); } - $data["about"] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'p-note')]"); + $data['about'] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'p-note')]"); - if ($data["about"] == '') { - $data["about"] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'summary')]"); + if ($data['about'] == '') { + $data['about'] = XML::getFirstNodeValue($xpath, "//p[contains(@class, 'summary')]"); } $avatar = $xpath->query("//img[contains(@class, 'u-photo')]")->item(0); @@ -1616,8 +1602,8 @@ class Probe } if ($avatar) { foreach ($avatar->attributes as $attribute) { - if ($attribute->name == "src") { - $data["photo"] = trim($attribute->value); + if ($attribute->name == 'src') { + $data['photo'] = trim($attribute->value); } } } @@ -1632,39 +1618,39 @@ class Probe * @param string $addr * @return array pump.io data */ - private static function pumpio($webfinger, $addr) + private static function pumpio(array $webfinger, string $addr): array { $data = []; // The array is reversed to take into account the order of preference for same-rel links // See: https://tools.ietf.org/html/rfc7033#section-4.4.4 - foreach (array_reverse($webfinger["links"]) as $link) { - if (($link["rel"] == "http://webfinger.net/rel/profile-page") - && (($link["type"] ?? "") == "text/html") - && ($link["href"] != "") + foreach (array_reverse($webfinger['links']) as $link) { + if (($link['rel'] == 'http://webfinger.net/rel/profile-page') + && (($link['type'] ?? '') == 'text/html') + && ($link['href'] != '') ) { - $data["url"] = $link["href"]; - } elseif (($link["rel"] == "activity-inbox") && ($link["href"] != "")) { - $data["notify"] = $link["href"]; - } elseif (($link["rel"] == "activity-outbox") && ($link["href"] != "")) { - $data["poll"] = $link["href"]; - } elseif (($link["rel"] == "dialback") && ($link["href"] != "")) { - $data["dialback"] = $link["href"]; + $data['url'] = $link['href']; + } elseif (($link['rel'] == 'activity-inbox') && ($link['href'] != '')) { + $data['notify'] = $link['href']; + } elseif (($link['rel'] == 'activity-outbox') && ($link['href'] != '')) { + $data['poll'] = $link['href']; + } elseif (($link['rel'] == 'dialback') && ($link['href'] != '')) { + $data['dialback'] = $link['href']; } } - if (isset($data["poll"]) && isset($data["notify"]) - && isset($data["dialback"]) - && isset($data["url"]) + if (isset($data['poll']) && isset($data['notify']) + && isset($data['dialback']) + && isset($data['url']) ) { // by now we use these fields only for the network type detection // So we unset all data that isn't used at the moment - unset($data["dialback"]); + unset($data['dialback']); - $data["network"] = Protocol::PUMPIO; + $data['network'] = Protocol::PUMPIO; } else { return []; } - $profile_data = self::pumpioProfileData($data["url"]); + $profile_data = self::pumpioProfileData($data['url']); if (!$profile_data) { return []; @@ -1719,9 +1705,9 @@ class Probe * @param string $href The potential relative href found in the HTML document * @param string $base The HTML document URL * @param DOMXPath $xpath The HTML document XPath - * @return string + * @return string Absolute URL */ - private static function ensureAbsoluteLinkFromHTMLDoc(string $href, string $base, DOMXPath $xpath) + private static function ensureAbsoluteLinkFromHTMLDoc(string $href, string $base, DOMXPath $xpath): string { if (filter_var($href, FILTER_VALIDATE_URL)) { return $href; @@ -1780,11 +1766,10 @@ class Probe * * @param string $url Profile link * @param boolean $probe Do a probe if the page contains a feed link - * * @return array feed data * @throws HTTPException\InternalServerErrorException */ - private static function feed($url, $probe = true) + private static function feed(string $url, bool $probe = true): array { $curlResult = DI::httpClient()->get($url, HttpClientAccept::FEED_XML); if ($curlResult->isTimeout()) { @@ -1808,26 +1793,26 @@ class Probe return self::feed($feed_url, false); } - if (!empty($feed_data["header"]["author-name"])) { - $data["name"] = $feed_data["header"]["author-name"]; + if (!empty($feed_data['header']['author-name'])) { + $data['name'] = $feed_data['header']['author-name']; } - if (!empty($feed_data["header"]["author-nick"])) { - $data["nick"] = $feed_data["header"]["author-nick"]; + if (!empty($feed_data['header']['author-nick'])) { + $data['nick'] = $feed_data['header']['author-nick']; } - if (!empty($feed_data["header"]["author-avatar"])) { - $data["photo"] = $feed_data["header"]["author-avatar"]; + if (!empty($feed_data['header']['author-avatar'])) { + $data['photo'] = $feed_data['header']['author-avatar']; } - if (!empty($feed_data["header"]["author-id"])) { - $data["alias"] = $feed_data["header"]["author-id"]; + if (!empty($feed_data['header']['author-id'])) { + $data['alias'] = $feed_data['header']['author-id']; } - $data["url"] = $url; - $data["poll"] = $url; + $data['url'] = $url; + $data['poll'] = $url; - $data["network"] = Protocol::FEED; + $data['network'] = Protocol::FEED; return $data; } @@ -1837,11 +1822,10 @@ class Probe * * @param string $uri Profile link * @param integer $uid User ID - * * @return array mail data * @throws \Exception */ - private static function mail($uri, $uid) + private static function mail(string $uri, int $uid): array { if (!Network::isEmailDomainValid($uri)) { return []; @@ -1879,14 +1863,14 @@ class Probe $phost = substr($uri, strpos($uri, '@') + 1); $data = []; - $data["addr"] = $uri; - $data["network"] = Protocol::MAIL; - $data["name"] = substr($uri, 0, strpos($uri, '@')); - $data["nick"] = $data["name"]; - $data["photo"] = Network::lookupAvatarByEmail($uri); - $data["url"] = 'mailto:'.$uri; - $data["notify"] = 'smtp ' . Strings::getRandomHex(); - $data["poll"] = 'email ' . Strings::getRandomHex(); + $data['addr'] = $uri; + $data['network'] = Protocol::MAIL; + $data['name'] = substr($uri, 0, strpos($uri, '@')); + $data['nick'] = $data['name']; + $data['photo'] = Network::lookupAvatarByEmail($uri); + $data['url'] = 'mailto:'.$uri; + $data['notify'] = 'smtp ' . Strings::getRandomHex(); + $data['poll'] = 'email ' . Strings::getRandomHex(); $x = Email::messageMeta($mbox, $msgs[0]); if (stristr($x[0]->from, $uri)) { @@ -1896,17 +1880,17 @@ class Probe } if (isset($adr)) { foreach ($adr as $feadr) { - if ((strcasecmp($feadr->mailbox, $data["name"]) == 0) + if ((strcasecmp($feadr->mailbox, $data['name']) == 0) &&(strcasecmp($feadr->host, $phost) == 0) && (strlen($feadr->personal)) ) { $personal = imap_mime_header_decode($feadr->personal); - $data["name"] = ""; + $data['name'] = ''; foreach ($personal as $perspart) { - if ($perspart->charset != "default") { - $data["name"] .= iconv($perspart->charset, 'UTF-8//IGNORE', $perspart->text); + if ($perspart->charset != 'default') { + $data['name'] .= iconv($perspart->charset, 'UTF-8//IGNORE', $perspart->text); } else { - $data["name"] .= $perspart->text; + $data['name'] .= $perspart->text; } } } @@ -1923,11 +1907,10 @@ class Probe * * @param string $avatar Path to the avatar * @param string $base Another path that is hopefully complete - * * @return string fixed avatar path * @throws \Exception */ - public static function fixAvatar($avatar, $base) + public static function fixAvatar(string $avatar, string $base): string { $base_parts = parse_url($base); @@ -1962,7 +1945,7 @@ class Probe * @param array $data probing result * @return string last activity */ - public static function getLastUpdate(array $data) + public static function getLastUpdate(array $data): string { $uid = User::getIdForURL($data['url']); if (!empty($uid)) { @@ -1991,11 +1974,9 @@ class Probe * Fetch the last activity date from the "noscrape" endpoint * * @param array $data Probing result - * @return string last activity - * - * @return bool 'true' if update was successful or the server was unreachable + * @return string last activity or true if update was successful or the server was unreachable */ - private static function updateFromNoScrape(array $data) + private static function updateFromNoScrape(array $data): string { if (empty($data['baseurl'])) { return ''; @@ -2028,7 +2009,7 @@ class Probe * @return string last activity * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function updateFromOutbox(string $feed, array $data) + private static function updateFromOutbox(string $feed, array $data): string { $outbox = ActivityPub::fetchContent($feed); if (empty($outbox)) { @@ -2080,7 +2061,7 @@ class Probe * @param array $data Probing result * @return string last activity */ - private static function updateFromFeed(array $data) + private static function updateFromFeed(array $data): string { // Search for the newest entry in the feed $curlResult = DI::httpClient()->get($data['poll'], HttpClientAccept::ATOM_XML); diff --git a/src/Object/Api/Twitter/User.php b/src/Object/Api/Twitter/User.php index 67351fc220..51721a86d1 100644 --- a/src/Object/Api/Twitter/User.php +++ b/src/Object/Api/Twitter/User.php @@ -119,7 +119,7 @@ class User extends BaseDataTransferObject if (!$include_user_entities) { unset($this->entities); } - $this->description = BBCode::toPlaintext($publicContact['about']); + $this->description = (!empty($publicContact['about']) ? BBCode::toPlaintext($publicContact['about']) : ''); $this->profile_image_url_https = Contact::getAvatarUrlForUrl($publicContact['url'], $uid, Proxy::SIZE_MICRO); $this->protected = false; $this->followers_count = $apcontact['followers_count'] ?? 0; diff --git a/src/Object/EMail/ItemCCEMail.php b/src/Object/EMail/ItemCCEMail.php index 5ac8b99096..927a068d7d 100644 --- a/src/Object/EMail/ItemCCEMail.php +++ b/src/Object/EMail/ItemCCEMail.php @@ -44,9 +44,9 @@ class ItemCCEMail extends Email $disclaimer .= $l10n->t('You may visit them online at %s', $baseUrl . '/profile/' . $a->getLoggedInUserNickname()) . EOL; $disclaimer .= $l10n->t('Please contact the sender by replying to this post if you do not wish to receive these messages.') . EOL; if (!$item['title'] == '') { - $subject = EmailProtocol::encodeHeader($item['title'], 'UTF-8'); + $subject = $item['title']; } else { - $subject = EmailProtocol::encodeHeader('[Friendica]' . ' ' . $l10n->t('%s posted an update.', $user['username']), 'UTF-8'); + $subject = '[Friendica]' . ' ' . $l10n->t('%s posted an update.', $user['username']); } $link = '' . $user['username'] . '

'; $html = Item::prepareBody($item); diff --git a/src/Object/Image.php b/src/Object/Image.php index 16206963b4..866ac268fa 100644 --- a/src/Object/Image.php +++ b/src/Object/Image.php @@ -47,12 +47,13 @@ class Image /** * Constructor - * @param string $data - * @param boolean $type optional, default null + * + * @param string $data Image data + * @param string $type optional, default null * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public function __construct($data, $type = null) + public function __construct(string $data, string $type = null) { $this->imagick = class_exists('Imagick'); $this->types = Images::supportedTypes(); @@ -62,12 +63,12 @@ class Image $this->type = $type; if ($this->isImagick() && $this->loadData($data)) { - return true; + return; } else { // Failed to load with Imagick, fallback $this->imagick = false; } - return $this->loadData($data); + $this->loadData($data); } /** @@ -98,12 +99,14 @@ class Image } /** - * @param string $data data - * @return boolean + * Loads image data into handler class + * + * @param string $data Image data + * @return boolean Success * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private function loadData($data) + private function loadData(string $data): bool { if ($this->isImagick()) { $this->image = new Imagick(); @@ -132,7 +135,7 @@ class Image * setup the compression here, so we'll do it only once */ switch ($this->getType()) { - case "image/png": + case 'image/png': $quality = DI::config()->get('system', 'png_quality'); /* * From http://www.imagemagick.org/script/command-line-options.php#quality: @@ -145,7 +148,9 @@ class Image $quality = $quality * 10; $this->image->setCompressionQuality($quality); break; - case "image/jpeg": + + case 'image/jpg': + case 'image/jpeg': $quality = DI::config()->get('system', 'jpeg_quality'); $this->image->setCompressionQuality($quality); } @@ -185,7 +190,7 @@ class Image /** * @return boolean */ - public function isValid() + public function isValid(): bool { if ($this->isImagick()) { return ($this->image !== false); @@ -269,10 +274,12 @@ class Image } /** + * Scales image down + * * @param integer $max max dimension * @return mixed */ - public function scaleDown($max) + public function scaleDown(int $max) { if (!$this->isValid()) { return false; @@ -327,10 +334,12 @@ class Image } /** + * Rotates image + * * @param integer $degrees degrees to rotate image * @return mixed */ - public function rotate($degrees) + public function rotate(int $degrees) { if (!$this->isValid()) { return false; @@ -351,11 +360,13 @@ class Image } /** + * Flips image + * * @param boolean $horiz optional, default true * @param boolean $vert optional, default false * @return mixed */ - public function flip($horiz = true, $vert = false) + public function flip(bool $horiz = true, bool $vert = false) { if (!$this->isValid()) { return false; @@ -391,10 +402,12 @@ class Image } /** - * @param string $filename filename + * Fixes orientation and maybe returns EXIF data (?) + * + * @param string $filename Filename * @return mixed */ - public function orient($filename) + public function orient(string $filename) { if ($this->isImagick()) { // based off comment on http://php.net/manual/en/imagick.getimageorientation.php @@ -470,10 +483,12 @@ class Image } /** - * @param integer $min minimum dimension + * Rescales image to minimum size + * + * @param integer $min Minimum dimension * @return mixed */ - public function scaleUp($min) + public function scaleUp(int $min) { if (!$this->isValid()) { return false; @@ -513,10 +528,12 @@ class Image } /** - * @param integer $dim dimension + * Scales image to square + * + * @param integer $dim Dimension * @return mixed */ - public function scaleToSquare($dim) + public function scaleToSquare(int $dim) { if (!$this->isValid()) { return false; @@ -528,11 +545,11 @@ class Image /** * Scale image to target dimensions * - * @param int $dest_width - * @param int $dest_height - * @return boolean + * @param int $dest_width Destination width + * @param int $dest_height Destination height + * @return boolean Success */ - private function scale($dest_width, $dest_height) + private function scale(int $dest_width, int $dest_height): bool { if (!$this->isValid()) { return false; @@ -584,6 +601,8 @@ class Image /** * Convert a GIF to a PNG to make it static + * + * @return void */ public function toStatic() { @@ -598,6 +617,8 @@ class Image } /** + * Crops image + * * @param integer $max maximum * @param integer $x x coordinate * @param integer $y y coordinate @@ -605,7 +626,7 @@ class Image * @param integer $h height * @return mixed */ - public function crop($max, $x, $y, $w, $h) + public function crop(int $max, int $x, int $y, int $w, int $h) { if (!$this->isValid()) { return false; @@ -638,6 +659,9 @@ class Image $this->image = $dest; $this->width = imagesx($this->image); $this->height = imagesy($this->image); + + // All successful + return true; } /** @@ -650,11 +674,14 @@ class Image * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function __toString() { - return $this->asString(); + public function __toString(): string + { + return (string) $this->asString(); } /** + * Returns image as string or false on failure + * * @return mixed * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ @@ -681,13 +708,16 @@ class Image imageinterlace($this->image, true); switch ($this->getType()) { - case "image/png": + case 'image/png': $quality = DI::config()->get('system', 'png_quality'); imagepng($this->image, null, $quality); break; - case "image/jpeg": + + case 'image/jpeg': + case 'image/jpg': $quality = DI::config()->get('system', 'jpeg_quality'); imagejpeg($this->image, null, $quality); + break; } $string = ob_get_contents(); ob_end_clean(); diff --git a/src/Object/Post.php b/src/Object/Post.php index fec3b3f2b3..fe271b5a87 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -42,6 +42,7 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy; use Friendica\Util\Strings; use Friendica\Util\Temporal; +use InvalidArgumentException; /** * An item @@ -105,7 +106,7 @@ class Post // Only add will be displayed if ($item['network'] === Protocol::MAIL && local_user() != $item['uid']) { continue; - } elseif (!DI::contentItem()->visibleActivity($item)) { + } elseif (!DI::contentItem()->isVisibleActivity($item)) { continue; } @@ -124,21 +125,27 @@ class Post /** * Fetch the privacy of the post * - * @param array $item - * @return string + * @param array $item Item record + * @return string Item privacy message + * @throws InvalidArgumentException If $item['private'] is unknown */ - private function fetchPrivacy(array $item):string + private function fetchPrivacy(array $item): string { switch ($item['private']) { case Item::PRIVATE: $output = DI::l10n()->t('Private Message'); break; + case Item::PUBLIC: $output = DI::l10n()->t('Public Message'); break; + case Item::UNLISTED: $output = DI::l10n()->t('Unlisted Message'); break; + + default: + throw new InvalidArgumentException('Item privacy ' . $item['privacy'] . ' is unsupported'); } return $output; @@ -151,25 +158,27 @@ class Post * @param string $formSecurityToken A security Token to avoid CSF attacks * @param integer $thread_level default = 1 * - * @return mixed The data requested on success - * false on failure + * @return mixed The data requested on success, false on failure * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public function getTemplateData(array $conv_responses, string $formSecurityToken, $thread_level = 1) + public function getTemplateData(array $conv_responses, string $formSecurityToken, int $thread_level = 1) { $item = $this->getData(); $edited = false; - // If the time between "created" and "edited" differs we add - // a notice that the post was edited. - // Note: In some networks reshared items seem to have (sometimes) a difference - // between creation time and edit time of a second. Thats why we add the notice - // only if the difference is more than 1 second. + + /* + * If the time between "created" and "edited" differs we add + * a notice that the post was edited. + * Note: In some networks reshared items seem to have (sometimes) a difference + * between creation time and edit time of a second. Thats why we add the notice + * only if the difference is more than 1 second. + */ if (strtotime($item['edited']) - strtotime($item['created']) > 1) { $edited = [ 'label' => DI::l10n()->t('This entry was edited'), 'date' => DateTimeFormat::local($item['edited'], 'r'), - 'relative' => Temporal::getRelativeDate($item['edited']) + 'relative' => Temporal::getRelativeDate($item['edited']), ]; } $sparkle = ''; @@ -184,8 +193,8 @@ class Post $pin = false; $star = false; $ignore = false; - $ispinned = "unpinned"; - $isstarred = "unstarred"; + $ispinned = 'unpinned'; + $isstarred = 'unstarred'; $indent = ''; $shiny = ''; $osparkle = ''; @@ -209,10 +218,10 @@ class Post if (local_user()) { if (Strings::compareLink(Session::get('my_url'), $item['author-link'])) { - if ($item["event-id"] != 0) { - $edpost = ["events/event/" . $item['event-id'], DI::l10n()->t("Edit")]; + if ($item['event-id'] != 0) { + $edpost = ['events/event/' . $item['event-id'], DI::l10n()->t('Edit')]; } else { - $edpost = ["editpost/" . $item['id'], DI::l10n()->t("Edit")]; + $edpost = ['editpost/' . $item['id'], DI::l10n()->t('Edit')]; } } $dropping = in_array($item['uid'], [0, local_user()]); @@ -289,6 +298,7 @@ class Post $response_verbs[] = 'attendyes'; $response_verbs[] = 'attendno'; $response_verbs[] = 'attendmaybe'; + if ($conv->isWritable()) { $isevent = true; $attend = [DI::l10n()->t('I will attend'), DI::l10n()->t('I will not attend'), DI::l10n()->t('I might attend')]; @@ -324,20 +334,20 @@ class Post 'do' => DI::l10n()->t('Ignore thread'), 'undo' => DI::l10n()->t('Unignore thread'), 'toggle' => DI::l10n()->t('Toggle ignore status'), - 'classdo' => $ignored ? "hidden" : "", - 'classundo' => $ignored ? "" : "hidden", + 'classdo' => $ignored ? 'hidden' : '', + 'classundo' => $ignored ? '' : 'hidden', 'ignored' => DI::l10n()->t('Ignored'), ]; } - $isstarred = (($item['starred']) ? "starred" : "unstarred"); + $isstarred = (($item['starred']) ? 'starred' : 'unstarred'); $star = [ 'do' => DI::l10n()->t('Add star'), 'undo' => DI::l10n()->t('Remove star'), 'toggle' => DI::l10n()->t('Toggle star status'), - 'classdo' => $item['starred'] ? "hidden" : "", - 'classundo' => $item['starred'] ? "" : "hidden", + 'classdo' => $item['starred'] ? 'hidden' : '', + 'classundo' => $item['starred'] ? '' : 'hidden', 'starred' => DI::l10n()->t('Starred'), ]; @@ -357,7 +367,7 @@ class Post $tagger = [ 'add' => DI::l10n()->t('Add tag'), - 'class' => "", + 'class' => '', ]; } } @@ -402,17 +412,17 @@ class Post } // Disable features that aren't available in several networks - if (!in_array($item["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA])) { - if ($buttons["dislike"]) { - $buttons["dislike"] = false; + if (!in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA])) { + if ($buttons['dislike']) { + $buttons['dislike'] = false; } $isevent = false; $tagger = ''; } - if ($buttons["like"] && in_array($item["network"], [Protocol::FEED, Protocol::MAIL])) { - $buttons["like"] = false; + if ($buttons['like'] && in_array($item['network'], [Protocol::FEED, Protocol::MAIL])) { + $buttons['like'] = false; } $tags = Tag::populateFromItem($item); @@ -453,7 +463,7 @@ class Post $tmp_item = [ 'template' => $this->getTemplate(), - 'type' => implode("", array_slice(explode("/", $item['verb']), -1)), + 'type' => implode('', array_slice(explode('/', $item['verb']), -1)), 'comment_firstcollapsed' => false, 'comment_lastcollapsed' => false, 'suppress_tags' => DI::config()->get('system', 'suppress_tags'), @@ -528,7 +538,7 @@ class Post 'wait' => DI::l10n()->t('Please wait'), 'thread_level' => $thread_level, 'edited' => $edited, - 'network' => $item["network"], + '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']), 'received' => $item['received'], @@ -595,7 +605,7 @@ class Post /** * @return integer */ - public function getId() + public function getId(): int { return $this->getDataValue('id'); } @@ -603,7 +613,7 @@ class Post /** * @return boolean */ - public function isThreaded() + public function isThreaded(): bool { return $this->threaded; } @@ -649,10 +659,9 @@ class Post * Get a child by its ID * * @param integer $id The child id - * * @return mixed */ - public function getChild($id) + public function getChild(int $id) { foreach ($this->getChildren() as $child) { if ($child->getId() == $id) { @@ -668,7 +677,7 @@ class Post * * @return Post[] */ - public function getChildren() + public function getChildren(): array { return $this->children; } @@ -677,7 +686,6 @@ class Post * Set our parent * * @param Post $item The item to set as parent - * * @return void */ protected function setParent(Post $item) @@ -706,11 +714,10 @@ class Post * Remove a child * * @param Post $item The child to be removed - * * @return boolean Success or failure * @throws \Exception */ - public function removeChild(Post $item) + public function removeChild(Post $item): bool { $id = $item->getId(); foreach ($this->getChildren() as $key => $child) { @@ -722,6 +729,7 @@ class Post return true; } } + Logger::info('[WARN] Item::removeChild : Item is not a child (' . $id . ').'); return false; } @@ -739,8 +747,7 @@ class Post /** * Set conversation thread * - * @param Thread $thread - * + * @param Thread|null $thread * @return void */ public function setThread(Thread $thread = null) @@ -756,7 +763,7 @@ class Post /** * Get conversation * - * @return Thread + * @return Thread|null */ public function getThread() { @@ -770,7 +777,7 @@ class Post * * @return array */ - public function getData() + public function getData(): array { return $this->data; } @@ -779,11 +786,9 @@ class Post * Get a data value * * @param string $name key - * - * @return mixed value on success - * false on failure + * @return mixed value on success, false on failure */ - public function getDataValue($name) + public function getDataValue(string $name) { if (!isset($this->data[$name])) { // Logger::info('[ERROR] Item::getDataValue : Item has no value name "'. $name .'".'); @@ -796,15 +801,15 @@ class Post /** * Set template * - * @param string $name template name - * @return bool - * @throws \Exception + * @param string $name Template name + * @return bool If template was set + * @throws InvalidArgumentException */ - private function setTemplate($name) + private function setTemplate(string $name): bool { if (empty($this->available_templates[$name])) { - Logger::info('[ERROR] Item::setTemplate : Template not available ("' . $name . '").'); - return false; + // Throw exception + throw new InvalidArgumentException('[ERROR] Item::setTemplate : Template not available ("' . $name . '").'); } $this->template = $this->available_templates[$name]; @@ -827,7 +832,7 @@ class Post * * @return boolean */ - private function isToplevel() + private function isToplevel(): bool { return $this->toplevel; } @@ -837,7 +842,7 @@ class Post * * @return boolean */ - private function isWritable() + private function isWritable(): bool { $conv = $this->getThread(); @@ -860,7 +865,7 @@ class Post * * @return integer */ - private function countDescendants() + private function countDescendants(): int { $children = $this->getChildren(); $total = count($children); @@ -878,7 +883,7 @@ class Post * * @return string */ - private function getCommentBoxTemplate() + private function getCommentBoxTemplate(): string { return $this->comment_box_template; } @@ -889,7 +894,7 @@ class Post * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private function getDefaultText() + private function getDefaultText(): string { $a = DI::app(); @@ -935,12 +940,11 @@ class Post * Get the comment box * * @param string $indent Indent value - * - * @return mixed The comment box string (empty if no comment box) - * false on failure + * @return mixed The comment box string (empty if no comment box), false on failure * @throws \Exception + * @todo return false is nowhere in this method? */ - private function getCommentBox($indent) + private function getCommentBox(string $indent) { $a = DI::app(); @@ -1008,7 +1012,7 @@ class Post /** * @return string */ - private function getRedirectUrl() + private function getRedirectUrl(): string { return $this->redirect_url; } @@ -1033,21 +1037,24 @@ class Post $owner_namematch = (($this->getDataValue('owner-name')) && $this->getDataValue('owner-name') == $this->getDataValue('author-name')); if (!$owner_linkmatch && !$alias_linkmatch && !$owner_namematch) { - // The author url doesn't match the owner (typically the contact) - // and also doesn't match the contact alias. - // The name match is a hack to catch several weird cases where URLs are - // all over the park. It can be tricked, but this prevents you from - // seeing "Bob Smith to Bob Smith via Wall-to-wall" and you know darn - // well that it's the same Bob Smith. - // But it could be somebody else with the same name. It just isn't highly likely. - - + /* + * The author url doesn't match the owner (typically the contact) + * and also doesn't match the contact alias. + * The name match is a hack to catch several weird cases where URLs are + * all over the park. It can be tricked, but this prevents you from + * seeing "Bob Smith to Bob Smith via Wall-to-wall" and you know darn + * well that it's the same Bob Smith. + * But it could be somebody else with the same name. It just isn't highly likely. + */ $this->owner_name = $this->getDataValue('owner-name'); $this->wall_to_wall = true; - $owner = ['uid' => 0, 'id' => $this->getDataValue('owner-id'), + $owner = [ + 'uid' => 0, + 'id' => $this->getDataValue('owner-id'), 'network' => $this->getDataValue('owner-network'), - 'url' => $this->getDataValue('owner-link')]; + 'url' => $this->getDataValue('owner-link'), + ]; $this->owner_url = Contact::magicLinkByContact($owner); } } @@ -1064,7 +1071,7 @@ class Post /** * @return boolean */ - private function isWallToWall() + private function isWallToWall(): bool { return $this->wall_to_wall; } @@ -1072,7 +1079,7 @@ class Post /** * @return string */ - private function getOwnerUrl() + private function getOwnerUrl(): string { return $this->owner_url; } @@ -1080,7 +1087,7 @@ class Post /** * @return string */ - private function getOwnerName() + private function getOwnerName(): string { return $this->owner_name; } @@ -1088,7 +1095,7 @@ class Post /** * @return boolean */ - private function isVisiting() + private function isVisiting(): bool { return $this->visiting; } diff --git a/src/Object/Search/ContactResult.php b/src/Object/Search/ContactResult.php index dabae1f4d3..8895f0ce0b 100644 --- a/src/Object/Search/ContactResult.php +++ b/src/Object/Search/ContactResult.php @@ -110,7 +110,7 @@ class ContactResult implements IResult /** * @return string */ - public function getUrl() + public function getUrl(): string { return $this->url; } diff --git a/src/Profile/ProfileField/Collection/ProfileFields.php b/src/Profile/ProfileField/Collection/ProfileFields.php index 0520103d76..f04aaa65da 100644 --- a/src/Profile/ProfileField/Collection/ProfileFields.php +++ b/src/Profile/ProfileField/Collection/ProfileFields.php @@ -33,9 +33,9 @@ class ProfileFields extends BaseCollection /** * @param callable $callback - * @return ProfileFields + * @return ProfileFields (as an extended form of BaseCollection) */ - public function map(callable $callback): ProfileFields + public function map(callable $callback): BaseCollection { return parent::map($callback); } @@ -43,9 +43,9 @@ class ProfileFields extends BaseCollection /** * @param callable|null $callback * @param int $flag - * @return ProfileFields + * @return ProfileFields as an extended version of BaseCollection */ - public function filter(callable $callback = null, int $flag = 0): ProfileFields + public function filter(callable $callback = null, int $flag = 0): BaseCollection { return parent::filter($callback, $flag); } diff --git a/src/Protocol/Activity.php b/src/Protocol/Activity.php index e75b1cf507..0f15e851c3 100644 --- a/src/Protocol/Activity.php +++ b/src/Protocol/Activity.php @@ -212,7 +212,7 @@ final class Activity * * @return bool True, if the activity is hidden */ - public function isHidden(string $activity) + public function isHidden(string $activity): bool { foreach (self::HIDDEN_ACTIVITIES as $hiddenActivity) { if ($this->match($activity, $hiddenActivity)) { @@ -231,7 +231,7 @@ final class Activity * * @return boolean */ - public function match(string $haystack, string $needle) + public function match(string $haystack, string $needle): bool { return (($haystack === $needle) || ((basename($needle) === $haystack) && diff --git a/src/Protocol/ActivityPub.php b/src/Protocol/ActivityPub.php index 78496e2433..858f837e8f 100644 --- a/src/Protocol/ActivityPub.php +++ b/src/Protocol/ActivityPub.php @@ -25,6 +25,7 @@ use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Model\APContact; use Friendica\Model\User; +use Friendica\Protocol\ActivityPub\FetchQueue; use Friendica\Util\HTTPSignature; use Friendica\Util\JsonLD; @@ -83,7 +84,7 @@ class ActivityPub * * @return bool is it AP? */ - public static function isRequest() + public static function isRequest(): bool { $isrequest = stristr($_SERVER['HTTP_ACCEPT'] ?? '', 'application/activity+json') || stristr($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') || @@ -104,12 +105,12 @@ class ActivityPub * @return array * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function fetchContent(string $url, int $uid = 0) + public static function fetchContent(string $url, int $uid = 0): array { return HTTPSignature::fetch($url, $uid); } - private static function getAccountType($apcontact) + private static function getAccountType(array $apcontact): int { $accounttype = -1; @@ -146,7 +147,7 @@ class ActivityPub * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function probeProfile($url, $update = true) + public static function probeProfile(string $url, bool $update = true): array { $apcontact = APContact::getByURL($url, $update); if (empty($apcontact)) { @@ -202,9 +203,10 @@ class ActivityPub * * @param string $url * @param integer $uid User ID + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function fetchOutbox($url, $uid) + public static function fetchOutbox(string $url, int $uid) { $data = self::fetchContent($url, $uid); if (empty($data)) { @@ -222,10 +224,14 @@ class ActivityPub $items = []; } + $fetchQueue = new FetchQueue(); + foreach ($items as $activity) { $ldactivity = JsonLD::compact($activity); - ActivityPub\Receiver::processActivity($ldactivity, '', $uid, true); + ActivityPub\Receiver::processActivity($fetchQueue, $ldactivity, '', $uid, true); } + + $fetchQueue->process(); } /** @@ -235,7 +241,7 @@ class ActivityPub * @param integer $uid Optional user id * @return array Endpoint items */ - public static function fetchItems(string $url, int $uid = 0) + public static function fetchItems(string $url, int $uid = 0): array { $data = self::fetchContent($url, $uid); if (empty($data)) { @@ -268,7 +274,7 @@ class ActivityPub * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isSupportedByContactUrl($url, $update = null) + public static function isSupportedByContactUrl(string $url, $update = null): bool { return !empty(APContact::getByURL($url, $update)); } diff --git a/src/Protocol/ActivityPub/FetchQueue.php b/src/Protocol/ActivityPub/FetchQueue.php new file mode 100644 index 0000000000..dfaa338361 --- /dev/null +++ b/src/Protocol/ActivityPub/FetchQueue.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace Friendica\Protocol\ActivityPub; + +/** + * This class prevents maximum function nesting errors by flattening recursive calls to Processor::fetchMissingActivity + */ +class FetchQueue +{ + /** @var FetchQueueItem[] */ + protected $queue = []; + + public function push(FetchQueueItem $item) + { + array_push($this->queue, $item); + } + + /** + * Processes missing activities one by one. It is possible that a processing call will add additional missing + * activities, they will be processed in subsequent iterations of the loop. + * + * Since this process is self-contained, it isn't suitable to retrieve the URI of a single activity. + * + * The simplest way to get the URI of the first activity and ensures all the parents are fetched is this way: + * + * $fetchQueue = new ActivityPub\FetchQueue(); + * $fetchedUri = ActivityPub\Processor::fetchMissingActivity($fetchQueue, $activityUri); + * $fetchQueue->process(); + */ + public function process() + { + while (count($this->queue)) { + $fetchQueueItem = array_pop($this->queue); + + call_user_func_array([Processor::class, 'fetchMissingActivity'], array_merge([$this], $fetchQueueItem->toParameters())); + } + } +} diff --git a/src/Protocol/ActivityPub/FetchQueueItem.php b/src/Protocol/ActivityPub/FetchQueueItem.php new file mode 100644 index 0000000000..716c231c99 --- /dev/null +++ b/src/Protocol/ActivityPub/FetchQueueItem.php @@ -0,0 +1,62 @@ +. + * + */ + +namespace Friendica\Protocol\ActivityPub; + +class FetchQueueItem +{ + /** @var string */ + private $url; + /** @var array */ + private $child; + /** @var string */ + private $relay_actor; + /** @var int */ + private $completion; + + /** + * This constructor matches the signature of Processor::fetchMissingActivity except for the default $completion value + * + * @param string $url + * @param array $child + * @param string $relay_actor + * @param int $completion + */ + public function __construct(string $url, array $child = [], string $relay_actor = '', int $completion = Receiver::COMPLETION_AUTO) + { + $this->url = $url; + $this->child = $child; + $this->relay_actor = $relay_actor; + $this->completion = $completion; + } + + /** + * Array meant to be used in call_user_function_array([Processor::class, 'fetchMissingActivity']). Caller needs to + * provide an instance of a FetchQueue that isn't included in these parameters. + * + * @see FetchQueue::process() + * @return array + */ + public function toParameters(): array + { + return [$this->url, $this->child, $this->relay_actor, $this->completion]; + } +} diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 9b6dd4d1a6..cc869e00ee 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -71,7 +71,7 @@ class Processor * @param array $languages * @return string language JSON */ - private static function processLanguages(array $languages) + private static function processLanguages(array $languages): string { $codes = array_keys($languages); $lang = []; @@ -88,12 +88,13 @@ class Processor /** * Replaces emojis in the body * - * @param array $emojis + * @param int $uri_id * @param string $body + * @param array $emojis * * @return string with replaced emojis */ - private static function replaceEmojis(int $uri_id, $body, array $emojis) + private static function replaceEmojis(int $uri_id, string $body, array $emojis): string { $body = strtr($body, array_combine( @@ -143,7 +144,7 @@ class Processor * @param array $activity * @param array $item */ - private static function storeAttachments($activity, $item) + private static function storeAttachments(array $activity, array $item) { if (empty($activity['attachments'])) { return; @@ -160,7 +161,7 @@ class Processor * @param array $activity * @param array $item */ - private static function storeQuestion($activity, $item) + private static function storeQuestion(array $activity, array $item) { if (empty($activity['question'])) { return; @@ -188,15 +189,17 @@ class Processor /** * Updates a message * - * @param array $activity Activity array + * @param FetchQueue $fetchQueue + * @param array $activity Activity array * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ - public static function updateItem($activity) + public static function updateItem(FetchQueue $fetchQueue, array $activity) { $item = Post::selectFirst(['uri', 'uri-id', 'thr-parent', 'gravity', 'post-type'], ['uri' => $activity['id']]); if (!DBA::isResult($item)) { Logger::warning('No existing item, item will be created', ['uri' => $activity['id']]); - $item = self::createItem($activity); + $item = self::createItem($fetchQueue, $activity); if (empty($item)) { return; } @@ -257,12 +260,13 @@ class Processor /** * Prepares data for a message * - * @param array $activity Activity array + * @param FetchQueue $fetchQueue + * @param array $activity Activity array * @return array Internal item * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function createItem($activity) + public static function createItem(FetchQueue $fetchQueue, array $activity): array { $item = []; $item['verb'] = Activity::POST; @@ -278,7 +282,12 @@ class Processor if (empty($activity['directmessage']) && ($activity['id'] != $activity['reply-to-id']) && !Post::exists(['uri' => $activity['reply-to-id']])) { Logger::notice('Parent not found. Try to refetch it.', ['parent' => $activity['reply-to-id']]); - self::fetchMissingActivity($activity['reply-to-id'], $activity, '', Receiver::COMPLETION_AUTO); + /** + * Instead of calling recursively self::fetchMissingActivity which can hit PHP's default function nesting + * limit of 256 recursive calls, we push the parent activity fetch parameters in this queue. The initial + * caller is responsible for processing the remaining queue once the original activity has been processed. + */ + $fetchQueue->push(new FetchQueueItem($activity['reply-to-id'], $activity)); } $item['diaspora_signed_text'] = $activity['diaspora:comment'] ?? ''; @@ -411,7 +420,7 @@ class Processor * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function deleteItem($activity) + public static function deleteItem(array $activity) { $owner = Contact::getIdForURL($activity['actor']); @@ -426,7 +435,7 @@ class Processor * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function addTag($activity) + public static function addTag(array $activity) { if (empty($activity['object_content']) || empty($activity['object_id'])) { return; @@ -452,14 +461,15 @@ class Processor /** * Prepare the item array for an activity * - * @param array $activity Activity array - * @param string $verb Activity verb + * @param FetchQueue $fetchQueue + * @param array $activity Activity array + * @param string $verb Activity verb * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function createActivity($activity, $verb) + public static function createActivity(FetchQueue $fetchQueue, array $activity, string $verb) { - $item = self::createItem($activity); + $item = self::createItem($fetchQueue, $activity); if (empty($item)) { return; } @@ -561,7 +571,7 @@ class Processor * @return int event id * @throws \Exception */ - public static function createEvent($activity, $item) + public static function createEvent(array $activity, array $item): int { $event['summary'] = HTML::toBBCode($activity['name'] ?: $activity['summary']); $event['desc'] = HTML::toBBCode($activity['content']); @@ -605,7 +615,7 @@ class Processor * @return array|bool Returns the item array or false if there was an unexpected occurrence * @throws \Exception */ - private static function processContent($activity, $item) + private static function processContent(array $activity, array $item) { if (!empty($activity['mediatype']) && ($activity['mediatype'] == 'text/markdown')) { $item['title'] = strip_tags($activity['name']); @@ -615,8 +625,8 @@ class Processor $content = $activity['content']; } else { // By default assume "text/html" - $item['title'] = HTML::toBBCode($activity['name']); - $content = HTML::toBBCode($activity['content']); + $item['title'] = HTML::toBBCode($activity['name'] ?? ''); + $content = HTML::toBBCode($activity['content'] ?? ''); } $item['title'] = trim(BBCode::toPlaintext($item['title'])); @@ -650,7 +660,7 @@ class Processor $content = self::removeImplicitMentionsFromBody($content, $parent); } - $item['content-warning'] = HTML::toBBCode($activity['summary']); + $item['content-warning'] = HTML::toBBCode($activity['summary'] ?? ''); $item['raw-body'] = $item['body'] = $content; } @@ -689,7 +699,7 @@ class Processor * @param string $url message URL * @return string with GUID */ - private static function getGUIDByURL(string $url) + private static function getGUIDByURL(string $url): string { $parsed = parse_url($url); @@ -710,7 +720,7 @@ class Processor * @param array $item * @return boolean Is the message wanted? */ - private static function isSolicitedMessage(array $activity, array $item) + private static function isSolicitedMessage(array $activity, array $item): bool { // The checks are split to improve the support when searching why a message was accepted. if (count($activity['receiver']) != 1) { @@ -971,7 +981,7 @@ class Processor * @return int|bool New mail table row id or false on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function postMail($activity, $item) + private static function postMail(array $activity, array $item) { if (($item['gravity'] != GRAVITY_PARENT) && !DBA::exists('mail', ['uri' => $item['thr-parent'], 'uid' => $item['uid']])) { Logger::info('Parent not found, mail will be discarded.', ['uid' => $item['uid'], 'uri' => $item['thr-parent']]); @@ -1105,14 +1115,16 @@ class Processor /** * Fetches missing posts * - * @param string $url message URL - * @param array $child activity array with the child of this message - * @param string $relay_actor Relay actor - * @param int $completion Completion mode, see Receiver::COMPLETION_* + * @param FetchQueue $fetchQueue + * @param string $url message URL + * @param array $child activity array with the child of this message + * @param string $relay_actor Relay actor + * @param int $completion Completion mode, see Receiver::COMPLETION_* * @return string fetched message URL * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ - public static function fetchMissingActivity(string $url, array $child = [], string $relay_actor = '', int $completion = Receiver::COMPLETION_MANUAL) + public static function fetchMissingActivity(FetchQueue $fetchQueue, string $url, array $child = [], string $relay_actor = '', int $completion = Receiver::COMPLETION_MANUAL): string { if (!empty($child['receiver'])) { $uid = ActivityPub\Receiver::getFirstUserFromReceivers($child['receiver']); @@ -1193,7 +1205,7 @@ class Processor return ''; } - ActivityPub\Receiver::processActivity($ldactivity, json_encode($activity), $uid, true, false, $signer); + ActivityPub\Receiver::processActivity($fetchQueue, $ldactivity, json_encode($activity), $uid, true, false, $signer); Logger::notice('Activity had been fetched and processed.', ['url' => $url, 'object' => $activity['id']]); @@ -1207,7 +1219,7 @@ class Processor * @param string $id object ID * @return boolean true if message is accepted */ - private static function acceptIncomingMessage(array $activity, string $id) + private static function acceptIncomingMessage(array $activity, string $id): bool { if (empty($activity['as:object'])) { Logger::info('No object field in activity - accepted', ['id' => $id]); @@ -1215,7 +1227,7 @@ class Processor } $replyto = JsonLD::fetchElement($activity['as:object'], 'as:inReplyTo', '@id'); - $uriid = ItemURI::getIdByURI($replyto); + $uriid = ItemURI::getIdByURI($replyto ?? ''); if (Post::exists(['uri-id' => $uriid])) { Logger::info('Post is a reply to an existing post - accepted', ['id' => $id, 'uri-id' => $uriid, 'replyto' => $replyto]); return true; @@ -1224,7 +1236,7 @@ class Processor $attributed_to = JsonLD::fetchElement($activity['as:object'], 'as:attributedTo', '@id'); $authorid = Contact::getIdForURL($attributed_to); - $body = HTML::toBBCode(JsonLD::fetchElement($activity['as:object'], 'as:content', '@value')); + $body = HTML::toBBCode(JsonLD::fetchElement($activity['as:object'], 'as:content', '@value') ?? ''); $messageTags = []; $tags = Receiver::processTags(JsonLD::fetchElementArray($activity['as:object'], 'as:tag') ?? []); @@ -1244,10 +1256,11 @@ class Processor * perform a "follow" request * * @param array $activity + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function followUser($activity) + public static function followUser(array $activity) { $uid = User::getIdForURL($activity['object_id']); if (empty($uid)) { @@ -1265,8 +1278,10 @@ class Processor Contact::update(['hub-verify' => $activity['id'], 'protocol' => Protocol::ACTIVITYPUB], ['id' => $cid]); } - $item = ['author-id' => Contact::getIdForURL($activity['actor']), - 'author-link' => $activity['actor']]; + $item = [ + 'author-id' => Contact::getIdForURL($activity['actor']), + 'author-link' => $activity['actor'], + ]; // Ensure that the contact has got the right network type self::switchContact($item['author-id']); @@ -1295,8 +1310,8 @@ class Processor /** * Transmit pending events to the new follower * - * @param integer $cid - * @param integer $uid + * @param integer $cid Contact id + * @param integer $uid User id * @return void */ private static function transmitPendingEvents(int $cid, int $uid) @@ -1325,7 +1340,7 @@ class Processor * @param array $activity * @throws \Exception */ - public static function updatePerson($activity) + public static function updatePerson(array $activity) { if (empty($activity['object_id'])) { return; @@ -1339,9 +1354,10 @@ class Processor * Delete the given profile * * @param array $activity + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function deletePerson($activity) + public static function deletePerson(array $activity) { if (empty($activity['object_id']) || empty($activity['actor'])) { Logger::info('Empty object id or actor.'); @@ -1366,9 +1382,10 @@ class Processor * Blocks the user by the contact * * @param array $activity + * @return void * @throws \Exception */ - public static function blockAccount($activity) + public static function blockAccount(array $activity) { $cid = Contact::getIdForURL($activity['actor']); if (empty($cid)) { @@ -1389,9 +1406,10 @@ class Processor * Unblocks the user by the contact * * @param array $activity + * @return void * @throws \Exception */ - public static function unblockAccount($activity) + public static function unblockAccount(array $activity) { $cid = Contact::getIdForURL($activity['actor']); if (empty($cid)) { @@ -1415,7 +1433,7 @@ class Processor * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function acceptFollowUser($activity) + public static function acceptFollowUser(array $activity) { $uid = User::getIdForURL($activity['object_actor']); if (empty($uid)) { @@ -1449,7 +1467,7 @@ class Processor * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function rejectFollowUser($activity) + public static function rejectFollowUser(array $activity) { $uid = User::getIdForURL($activity['object_actor']); if (empty($uid)) { @@ -1482,7 +1500,7 @@ class Processor * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function undoActivity($activity) + public static function undoActivity(array $activity) { if (empty($activity['object_id'])) { return; @@ -1507,7 +1525,7 @@ class Processor * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function undoFollowUser($activity) + public static function undoFollowUser(array $activity) { $uid = User::getIdForURL($activity['object_object']); if (empty($uid)) { @@ -1540,9 +1558,10 @@ class Processor * Switches a contact to AP if needed * * @param integer $cid Contact ID + * @return void * @throws \Exception */ - private static function switchContact($cid) + private static function switchContact(int $cid) { $contact = DBA::selectFirst('contact', ['network', 'url'], ['id' => $cid]); if (!DBA::isResult($contact) || in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN]) || Contact::isLocal($contact['url'])) { @@ -1562,7 +1581,7 @@ class Processor * @return array * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function getImplicitMentionList(array $parent) + private static function getImplicitMentionList(array $parent): array { $parent_terms = Tag::getByURIId($parent['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION]); @@ -1600,7 +1619,7 @@ class Processor * @param array $parent * @return string */ - private static function removeImplicitMentionsFromBody(string $body, array $parent) + private static function removeImplicitMentionsFromBody(string $body, array $parent): string { if (DI::config()->get('system', 'disable_implicit_mentions')) { return $body; diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 4a13872983..2a56e9e5e7 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -80,12 +80,13 @@ class Receiver /** * Checks incoming message from the inbox * - * @param $body - * @param $header + * @param string $body Body string + * @param array $header Header lines * @param integer $uid User ID + * @return void * @throws \Exception */ - public static function processInbox($body, $header, $uid) + public static function processInbox(string $body, array $header, int $uid) { $activity = json_decode($body, true); if (empty($activity)) { @@ -95,9 +96,9 @@ class Receiver $ldactivity = JsonLD::compact($activity); - $actor = JsonLD::fetchElement($ldactivity, 'as:actor', '@id'); - + $actor = JsonLD::fetchElement($ldactivity, 'as:actor', '@id') ?? ''; $apcontact = APContact::getByURL($actor); + if (empty($apcontact)) { Logger::notice('Unable to retrieve AP contact for actor - message is discarded', ['actor' => $actor]); return; @@ -151,7 +152,9 @@ class Receiver $trust_source = false; } - self::processActivity($ldactivity, $body, $uid, $trust_source, true, $signer); + $fetchQueue = new FetchQueue(); + self::processActivity($fetchQueue, $ldactivity, $body, $uid, $trust_source, true, $signer); + $fetchQueue->process(); } /** @@ -199,12 +202,16 @@ class Receiver return; } - $id = Processor::fetchMissingActivity($object_id, [], $actor, self::COMPLETION_RELAY); + $fetchQueue = new FetchQueue(); + + $id = Processor::fetchMissingActivity($fetchQueue, $object_id, [], $actor, self::COMPLETION_RELAY); if (empty($id)) { Logger::notice('Relayed message had not been fetched', ['id' => $object_id]); return; } + $fetchQueue->process(); + $item_id = Item::searchByLink($object_id); if ($item_id) { Logger::info('Relayed message had been fetched and stored', ['id' => $object_id, 'item' => $item_id]); @@ -220,11 +227,11 @@ class Receiver * @param string $object_id Object ID of the the provided object * @param integer $uid User ID * - * @return string with object type + * @return string with object type or NULL * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function fetchObjectType($activity, $object_id, $uid = 0) + private static function fetchObjectType(array $activity, string $object_id, int $uid = 0) { if (!empty($activity['as:object'])) { $object_type = JsonLD::fetchElement($activity['as:object'], '@type'); @@ -268,7 +275,7 @@ class Receiver * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function prepareObjectData($activity, $uid, $push, &$trust_source) + public static function prepareObjectData(array $activity, int $uid, bool $push, bool &$trust_source): array { $id = JsonLD::fetchElement($activity, '@id'); if (!empty($id) && !$trust_source) { @@ -458,7 +465,7 @@ class Receiver * @param array $receivers Array with receivers * @return integer user id; */ - public static function getFirstUserFromReceivers($receivers) + public static function getFirstUserFromReceivers(array $receivers): int { foreach ($receivers as $receiver) { if (!empty($receiver)) { @@ -471,15 +478,17 @@ class Receiver /** * Processes the activity object * - * @param array $activity Array with activity data - * @param string $body The unprocessed body - * @param integer $uid User ID - * @param boolean $trust_source Do we trust the source? - * @param boolean $push Message had been pushed to our system - * @param array $signer The signer of the post - * @throws \Exception + * @param FetchQueue $fetchQueue + * @param array $activity Array with activity data + * @param string $body The unprocessed body + * @param int|null $uid User ID + * @param boolean $trust_source Do we trust the source? + * @param boolean $push Message had been pushed to our system + * @param array $signer The signer of the post + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ - public static function processActivity($activity, string $body = '', int $uid = null, bool $trust_source = false, bool $push = false, array $signer = []) + public static function processActivity(FetchQueue $fetchQueue, array $activity, string $body = '', int $uid = null, bool $trust_source = false, bool $push = false, array $signer = []) { $type = JsonLD::fetchElement($activity, '@type'); if (!$type) { @@ -560,7 +569,7 @@ class Receiver switch ($type) { case 'as:Create': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - $item = ActivityPub\Processor::createItem($object_data); + $item = ActivityPub\Processor::createItem($fetchQueue, $object_data); ActivityPub\Processor::postItem($object_data, $item); } elseif (in_array($object_data['object_type'], ['pt:CacheFile'])) { // Unhandled Peertube activity @@ -571,7 +580,7 @@ class Receiver case 'as:Invite': if (in_array($object_data['object_type'], ['as:Event'])) { - $item = ActivityPub\Processor::createItem($object_data); + $item = ActivityPub\Processor::createItem($fetchQueue, $object_data); ActivityPub\Processor::postItem($object_data, $item); } else { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); @@ -595,7 +604,7 @@ class Receiver $object_data['thread-completion'] = Contact::getIdForURL($actor); $object_data['completion-mode'] = self::COMPLETION_ANNOUCE; - $item = ActivityPub\Processor::createItem($object_data); + $item = ActivityPub\Processor::createItem($fetchQueue, $object_data); if (empty($item)) { return; } @@ -614,7 +623,7 @@ class Receiver $announce_object_data['raw'] = $body; } - ActivityPub\Processor::createActivity($announce_object_data, Activity::ANNOUNCE); + ActivityPub\Processor::createActivity($fetchQueue, $announce_object_data, Activity::ANNOUNCE); } else { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); } @@ -622,7 +631,7 @@ class Receiver case 'as:Like': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::createActivity($object_data, Activity::LIKE); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::LIKE); } elseif ($object_data['object_type'] == '') { // The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity. } else { @@ -632,7 +641,7 @@ class Receiver case 'as:Dislike': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::createActivity($object_data, Activity::DISLIKE); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::DISLIKE); } elseif ($object_data['object_type'] == '') { // The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity. } else { @@ -642,7 +651,7 @@ class Receiver case 'as:TentativeAccept': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::createActivity($object_data, Activity::ATTENDMAYBE); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::ATTENDMAYBE); } else { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); } @@ -650,7 +659,7 @@ class Receiver case 'as:Update': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::updateItem($object_data); + ActivityPub\Processor::updateItem($fetchQueue, $object_data); } elseif (in_array($object_data['object_type'], self::ACCOUNT_TYPES)) { ActivityPub\Processor::updatePerson($object_data); } elseif (in_array($object_data['object_type'], ['pt:CacheFile'])) { @@ -695,7 +704,7 @@ class Receiver ActivityPub\Processor::followUser($object_data); } elseif (in_array($object_data['object_type'], self::CONTENT_TYPES)) { $object_data['reply-to-id'] = $object_data['object_id']; - ActivityPub\Processor::createActivity($object_data, Activity::FOLLOW); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::FOLLOW); } else { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); } @@ -705,7 +714,7 @@ class Receiver if ($object_data['object_type'] == 'as:Follow') { ActivityPub\Processor::acceptFollowUser($object_data); } elseif (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::createActivity($object_data, Activity::ATTEND); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::ATTEND); } else { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); } @@ -715,7 +724,7 @@ class Receiver if ($object_data['object_type'] == 'as:Follow') { ActivityPub\Processor::rejectFollowUser($object_data); } elseif (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::createActivity($object_data, Activity::ATTENDNO); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::ATTENDNO); } else { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer); } @@ -750,7 +759,7 @@ class Receiver case 'as:View': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::createActivity($object_data, Activity::VIEW); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::VIEW); } elseif ($object_data['object_type'] == '') { // The object type couldn't be determined. Most likely we don't have it here. We ignore this activity. } else { @@ -760,7 +769,7 @@ class Receiver case 'litepub:EmojiReact': if (in_array($object_data['object_type'], self::CONTENT_TYPES)) { - ActivityPub\Processor::createActivity($object_data, Activity::EMOJIREACT); + ActivityPub\Processor::createActivity($fetchQueue, $object_data, Activity::EMOJIREACT); } elseif ($object_data['object_type'] == '') { // The object type couldn't be determined. We don't have it and we can't fetch it. We ignore this activity. } else { @@ -818,7 +827,7 @@ class Receiver * * @return int user id */ - public static function getBestUserForActivity(array $activity) + public static function getBestUserForActivity(array $activity): int { $uid = 0; $actor = JsonLD::fetchElement($activity, 'as:actor', '@id') ?? ''; @@ -844,7 +853,8 @@ class Receiver return $uid; } - public static function getReceiverURL($activity) + // @TODO Missing documentation + public static function getReceiverURL(array $activity): array { $urls = []; @@ -876,9 +886,9 @@ class Receiver * @return array with receivers (user id) * @throws \Exception */ - private static function getReceivers($activity, $actor, $tags = [], $fetch_unlisted = false) + private static function getReceivers(array $activity, string $actor, array $tags = [], bool $fetch_unlisted = false): array { - $reply = $receivers = []; + $reply = $receivers = $profile = []; // When it is an answer, we inherite the receivers from the parent $replyto = JsonLD::fetchElement($activity, 'as:inReplyTo', '@id'); @@ -1005,7 +1015,7 @@ class Receiver * @return array with receivers (user id) * @throws \Exception */ - private static function getReceiverForActor($actor, $tags, $receivers, $target_type, $profile) + private static function getReceiverForActor(string $actor, array $tags, array $receivers, int $target_type, array $profile): array { $basecondition = ['rel' => [Contact::SHARING, Contact::FRIEND, Contact::FOLLOWER], 'network' => Protocol::FEDERATED, 'archive' => false, 'pending' => false]; @@ -1047,13 +1057,12 @@ class Receiver * Tests if the contact is a valid receiver for this actor * * @param array $contact - * @param string $actor * @param array $tags * * @return bool with receivers (user id) * @throws \Exception */ - private static function isValidReceiverForActor($contact, $tags) + private static function isValidReceiverForActor(array $contact, array $tags): bool { // Are we following the contact? Then this is a valid receiver if (in_array($contact['rel'], [Contact::SHARING, Contact::FRIEND])) { @@ -1086,10 +1095,11 @@ class Receiver * @param integer $cid Contact ID * @param integer $uid User ID * @param string $url Profile URL + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function switchContact($cid, $uid, $url) + public static function switchContact(int $cid, int $uid, string $url) { if (DBA::exists('contact', ['id' => $cid, 'network' => Protocol::ACTIVITYPUB])) { Logger::info('Contact is already ActivityPub', ['id' => $cid, 'uid' => $uid, 'url' => $url]); @@ -1108,10 +1118,11 @@ class Receiver } /** - * + * @TODO Fix documentation and type-hints * * @param $receivers * @param $actor + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ @@ -1135,14 +1146,14 @@ class Receiver } /** - * + * @TODO Fix documentation and type-hints * * @param $object_data * @param array $activity * * @return mixed */ - private static function addActivityFields($object_data, $activity) + private static function addActivityFields($object_data, array $activity) { if (!empty($activity['published']) && empty($object_data['published'])) { $object_data['published'] = JsonLD::fetchElement($activity, 'as:published', '@value'); @@ -1262,7 +1273,7 @@ class Receiver * @param array $languages * @return array Languages */ - public static function processLanguages(array $languages) + public static function processLanguages(array $languages): array { if (empty($languages)) { return []; @@ -1285,7 +1296,7 @@ class Receiver * * @return array with tags in a simplified format */ - public static function processTags(array $tags) + public static function processTags(array $tags): array { $taglist = []; @@ -1317,7 +1328,7 @@ class Receiver * @param array $emojis * @return array with emojis in a simplified format */ - private static function processEmojis(array $emojis) + private static function processEmojis(array $emojis): array { $emojilist = []; @@ -1343,7 +1354,7 @@ class Receiver * * @return array Attachments in a simplified format */ - private static function processAttachments(array $attachments) + private static function processAttachments(array $attachments): array { $attachlist = []; @@ -1460,7 +1471,7 @@ class Receiver * * @return array Questions in a simplified format */ - private static function processQuestion(array $object) + private static function processQuestion(array $object): array { $question = []; @@ -1518,10 +1529,10 @@ class Receiver * @param array $object * @param array $object_data * - * @return array + * @return array Object data (?) * @throws \Exception */ - private static function getSource($object, $object_data) + private static function getSource(array $object, array $object_data): array { $object_data['source'] = JsonLD::fetchElement($object, 'as:source', 'as:content', 'as:mediaType', 'text/bbcode'); $object_data['source'] = JsonLD::fetchElement($object_data, 'source', '@value'); @@ -1650,10 +1661,10 @@ class Receiver * * @param array $object * - * @return array + * @return array|bool Object data or FALSE if $object does not contain @id element * @throws \Exception */ - private static function processObject($object) + private static function processObject(array $object) { if (!JsonLD::fetchElement($object, '@id')) { return false; @@ -1767,7 +1778,7 @@ class Receiver $object_data['question'] = self::processQuestion($object); } - $receiverdata = self::getReceivers($object, $object_data['actor'], $object_data['tags'], true); + $receiverdata = self::getReceivers($object, $object_data['actor'] ?? '', $object_data['tags'], true); $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 023bd5c83c..a9c163964e 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -68,7 +68,7 @@ class Transmitter * @param array $inboxes * @return array inboxes with added relay servers */ - public static function addRelayServerInboxes(array $inboxes = []) + public static function addRelayServerInboxes(array $inboxes = []): array { foreach (Relay::getList(['inbox']) as $contact) { $inboxes[$contact['inbox']] = $contact['inbox']; @@ -83,7 +83,7 @@ class Transmitter * @param array $inboxes * @return array inboxes with added relay servers */ - public static function addRelayServerInboxesForItem(int $item_id, array $inboxes = []) + public static function addRelayServerInboxesForItem(int $item_id, array $inboxes = []): array { $item = Post::selectFirst(['uid'], ['id' => $item_id]); if (empty($item)) { @@ -103,12 +103,12 @@ class Transmitter } /** - * Subscribe to a relay + * Subscribe to a relay and updates contact on success * * @param string $url Subscribe actor url * @return bool success */ - public static function sendRelayFollow(string $url) + public static function sendRelayFollow(string $url): bool { $contact = Contact::getByURL($url); if (empty($contact)) { @@ -125,13 +125,13 @@ class Transmitter } /** - * Unsubscribe from a relay + * Unsubscribe from a relay and updates contact on success or forced * * @param string $url Subscribe actor url * @param bool $force Set the relay status as non follower even if unsubscribe hadn't worked * @return bool success */ - public static function sendRelayUndoFollow(string $url, bool $force = false) + public static function sendRelayUndoFollow(string $url, bool $force = false): bool { $contact = Contact::getByURL($url); if (empty($contact)) { @@ -139,6 +139,7 @@ class Transmitter } $success = self::sendContactUndo($url, $contact['id'], 0); + if ($success || $force) { Contact::update(['rel' => Contact::NOTHING], ['id' => $contact['id']]); } @@ -155,11 +156,10 @@ class Transmitter * @param integer $page Page number * @param string $requester URL of the requester * @param boolean $nocache Wether to bypass caching - * * @return array of owners * @throws \Exception */ - public static function getContacts(array $owner, array $rel, string $module, int $page = null, string $requester = null, $nocache = false) + public static function getContacts(array $owner, array $rel, string $module, int $page = null, string $requester = null, bool $nocache = false): array { if (empty($page)) { $cachekey = self::CACHEKEY_CONTACTS . $module . ':'. $owner['uid']; @@ -246,12 +246,11 @@ class Transmitter * @param integer $page Page number * @param string $requester URL of requesting account * @param boolean $nocache Wether to bypass caching - * * @return array of posts * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getOutbox(array $owner, int $page = null, string $requester = '', $nocache = false) + public static function getOutbox(array $owner, int $page = null, string $requester = '', bool $nocache = false): array { if (empty($page)) { $cachekey = self::CACHEKEY_OUTBOX . $owner['uid']; @@ -274,15 +273,16 @@ class Transmitter } } - $condition = array_merge($condition, - ['uid' => $owner['uid'], + $condition = array_merge($condition, [ + 'uid' => $owner['uid'], 'author-id' => Contact::getIdForURL($owner['url'], 0, false), 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'network' => Protocol::FEDERATED, 'parent-network' => Protocol::FEDERATED, 'origin' => true, 'deleted' => false, - 'visible' => true]); + 'visible' => true + ]); $count = Post::count($condition); @@ -340,7 +340,7 @@ class Transmitter * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getFeatured(array $owner, int $page = null, $nocache = false) + public static function getFeatured(array $owner, int $page = null, bool $nocache = false): array { if (empty($page)) { $cachekey = self::CACHEKEY_FEATURED . $owner['uid']; @@ -355,8 +355,8 @@ class Transmitter $condition = ["`uri-id` IN (SELECT `uri-id` FROM `collection-view` WHERE `cid` = ? AND `type` = ?)", $owner_cid, Post\Collection::FEATURED]; - $condition = DBA::mergeConditions($condition, - ['uid' => $owner['uid'], + $condition = DBA::mergeConditions($condition, [ + 'uid' => $owner['uid'], 'author-id' => $owner_cid, 'private' => [Item::PUBLIC, Item::UNLISTED], 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], @@ -364,7 +364,8 @@ class Transmitter 'parent-network' => Protocol::FEDERATED, 'origin' => true, 'deleted' => false, - 'visible' => true]); + 'visible' => true + ]); $count = Post::count($condition); @@ -418,11 +419,13 @@ class Transmitter * * @return array with service data */ - private static function getService() + private static function getService(): array { - return ['type' => 'Service', + return [ + 'type' => 'Service', 'name' => FRIENDICA_PLATFORM . " '" . FRIENDICA_CODENAME . "' " . FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION, - 'url' => DI::baseUrl()->get()]; + 'url' => DI::baseUrl()->get() + ]; } /** @@ -537,7 +540,7 @@ class Transmitter * @return array * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getDeletedUser($username) + public static function getDeletedUser(string $username): array { return [ '@context' => ActivityPub::CONTEXT, @@ -559,7 +562,7 @@ class Transmitter * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function fetchPermissionBlockFromThreadParent(array $item, bool $is_forum_thread) + private static function fetchPermissionBlockFromThreadParent(array $item, bool $is_forum_thread): array { if (empty($item['thr-parent-id'])) { return []; @@ -606,7 +609,7 @@ class Transmitter * @param integer $item_id * @return boolean "true" if the post is from ActivityPub */ - private static function isAPPost(int $item_id) + private static function isAPPost(int $item_id): bool { if (empty($item_id)) { return false; @@ -626,7 +629,7 @@ class Transmitter * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function createPermissionBlockForItem($item, $blindcopy, $last_id = 0) + private static function createPermissionBlockForItem(array $item, bool $blindcopy, int $last_id = 0): array { if ($last_id == 0) { $last_id = $item['id']; @@ -858,10 +861,9 @@ class Transmitter * Check if an inbox is archived * * @param string $url Inbox url - * * @return boolean "true" if inbox is archived */ - public static function archivedInbox($url) + public static function archivedInbox(string $url): bool { return DBA::exists('inbox-status', ['url' => $url, 'archive' => true]); } @@ -869,12 +871,12 @@ class Transmitter /** * Check if a given contact should be delivered via AP * - * @param array $contact - * @param array $networks - * @return bool + * @param array $contact Contact array + * @param array $networks Array with networks + * @return bool Whether the used protocol matches ACTIVITYPUB * @throws Exception */ - private static function isAPContact(array $contact, array $networks) + private static function isAPContact(array $contact, array $networks): bool { if (in_array($contact['network'], $networks) || ($contact['protocol'] == Protocol::ACTIVITYPUB)) { return true; @@ -889,12 +891,11 @@ class Transmitter * @param integer $uid User ID * @param boolean $personal fetch personal inboxes * @param boolean $all_ap Retrieve all AP enabled inboxes - * * @return array of follower inboxes * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function fetchTargetInboxesforUser($uid, $personal = false, bool $all_ap = false) + public static function fetchTargetInboxesforUser(int $uid, bool $personal = false, bool $all_ap = false): array { $inboxes = []; @@ -915,7 +916,13 @@ class Transmitter $networks = [Protocol::ACTIVITYPUB, Protocol::OSTATUS]; } - $condition = ['uid' => $uid, 'archive' => false, 'pending' => false, 'blocked' => false, 'network' => Protocol::FEDERATED]; + $condition = [ + 'uid' => $uid, + 'archive' => false, + 'pending' => false, + 'blocked' => false, + 'network' => Protocol::FEDERATED, + ]; if (!empty($uid)) { $condition['rel'] = [Contact::FOLLOWER, Contact::FRIEND]; @@ -963,7 +970,7 @@ class Transmitter * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function fetchTargetInboxes($item, $uid, $personal = false, $last_id = 0) + public static function fetchTargetInboxes(array $item, int $uid, bool $personal = false, int $last_id = 0): array { $permissions = self::createPermissionBlockForItem($item, true, $last_id); if (empty($permissions)) { @@ -1022,12 +1029,11 @@ class Transmitter /** * Creates an array in the structure of the item table for a given mail id * - * @param integer $mail_id - * + * @param integer $mail_id Mail id * @return array * @throws \Exception */ - public static function ItemArrayFromMail($mail_id, $use_title = false) + public static function getItemArrayFromMail(int $mail_id, bool $use_title = false): array { $mail = DBA::selectFirst('mail', [], ['id' => $mail_id]); if (!DBA::isResult($mail)) { @@ -1079,9 +1085,9 @@ class Transmitter * @return array of activity * @throws \Exception */ - public static function createActivityFromMail($mail_id, $object_mode = false) + public static function createActivityFromMail(int $mail_id, bool $object_mode = false): array { - $mail = self::ItemArrayFromMail($mail_id); + $mail = self::getItemArrayFromMail($mail_id); if (empty($mail)) { return []; } @@ -1133,18 +1139,17 @@ class Transmitter /** * Returns the activity type of a given item * - * @param array $item - * + * @param array $item Item array * @return string with activity type * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function getTypeOfItem($item) + private static function getTypeOfItem(array $item): string { $reshared = false; // Only check for a reshare, if it is a real reshare and no quoted reshare - if (strpos($item['body'], "[share") === 0) { + if (strpos($item['body'], '[share') === 0) { $announce = self::getAnnounceArray($item); $reshared = !empty($announce); } @@ -1183,13 +1188,12 @@ class Transmitter /** * Creates the activity or fetches it from the cache * - * @param integer $item_id + * @param integer $item_id Item id * @param boolean $force Force new cache entry - * - * @return array with the activity + * @return array|false activity or false on failure * @throws \Exception */ - public static function createCachedActivityFromItem($item_id, $force = false) + public static function createCachedActivityFromItem(int $item_id, bool $force = false) { $cachekey = 'APDelivery:createActivity:' . $item_id; @@ -1211,7 +1215,6 @@ class Transmitter * * @param integer $item_id * @param boolean $object_mode Is the activity item is used inside another object? - * * @return false|array * @throws \Exception */ @@ -1268,7 +1271,7 @@ class Transmitter } if ($type == 'Delete') { - $data['id'] = Item::newURI($item['uid'], $item['guid']) . '/' . $type;; + $data['id'] = Item::newURI($item['guid']) . '/' . $type;; } elseif (($item['gravity'] == GRAVITY_ACTIVITY) && ($type != 'Undo')) { $data['id'] = $item['uri']; } else { @@ -1335,11 +1338,10 @@ class Transmitter /** * Creates a location entry for a given item array * - * @param array $item - * + * @param array $item Item array * @return array with location array */ - private static function createLocation($item) + private static function createLocation(array $item): array { $location = ['type' => 'Place']; @@ -1369,12 +1371,11 @@ class Transmitter /** * Returns a tag array for a given item array * - * @param array $item - * + * @param array $item Item array * @return array of tags * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function createTagList($item) + private static function createTagList(array $item): array { $tags = []; @@ -1416,7 +1417,7 @@ class Transmitter * @return array with attachment data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function createAttachmentList($item, $type) + private static function createAttachmentList(array $item, string $type): array { $attachments = []; @@ -1468,7 +1469,7 @@ class Transmitter * @return string Replaced mention * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function mentionAddrCallback($match) + private static function mentionAddrCallback(array $match): string { if (empty($match[1])) { return ''; @@ -1485,11 +1486,10 @@ class Transmitter /** * Remove image elements since they are added as attachment * - * @param string $body - * + * @param string $body HTML code * @return string with removed images */ - private static function removePictures($body) + private static function removePictures(string $body): string { // Simplify image codes $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); @@ -1518,12 +1518,11 @@ class Transmitter /** * Fetches the "context" value for a givem item array from the "conversation" table * - * @param array $item - * + * @param array $item Item array * @return string with context url * @throws \Exception */ - private static function fetchContextURLForItem($item) + private static function fetchContextURLForItem(array $item): string { $conversation = DBA::selectFirst('conversation', ['conversation-href', 'conversation-uri'], ['item-uri' => $item['parent-uri']]); if (DBA::isResult($conversation) && !empty($conversation['conversation-href'])) { @@ -1539,12 +1538,11 @@ class Transmitter /** * Returns if the post contains sensitive content ("nsfw") * - * @param integer $uri_id - * - * @return boolean + * @param integer $uri_id URI id + * @return boolean Whether URI id was found * @throws \Exception */ - private static function isSensitive($uri_id) + private static function isSensitive(int $uri_id): bool { return DBA::exists('tag-view', ['uri-id' => $uri_id, 'name' => 'nsfw', 'type' => Tag::HASHTAG]); } @@ -1552,12 +1550,11 @@ class Transmitter /** * Creates event data * - * @param array $item - * + * @param array $item Item array * @return array with the event data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function createEvent($item) + private static function createEvent(array $item): array { $event = []; $event['name'] = $item['event-summary']; @@ -1583,12 +1580,11 @@ class Transmitter * Creates a note/article object array * * @param array $item - * * @return array with the object data * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function createNote($item) + public static function createNote(array $item): array { if (empty($item)) { return []; @@ -1739,10 +1735,9 @@ class Transmitter * Fetches the language from the post, the user or the system. * * @param array $item - * * @return string language string */ - private static function getLanguage(array $item) + private static function getLanguage(array $item): string { // Try to fetch the language from the post itself if (!empty($item['language'])) { @@ -1767,74 +1762,71 @@ class Transmitter /** * Creates an an "add tag" entry * - * @param array $item - * @param array $data activity data - * + * @param array $item Item array + * @param array $activity activity data * @return array with activity data for adding tags * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function createAddTag($item, $data) + private static function createAddTag(array $item, array $activity): array { $object = XML::parseString($item['object']); - $target = XML::parseString($item["target"]); + $target = XML::parseString($item['target']); - $data['diaspora:guid'] = $item['guid']; - $data['actor'] = $item['author-link']; - $data['target'] = (string)$target->id; - $data['summary'] = BBCode::toPlaintext($item['body']); - $data['object'] = ['id' => (string)$object->id, 'type' => 'tag', 'name' => (string)$object->title, 'content' => (string)$object->content]; + $activity['diaspora:guid'] = $item['guid']; + $activity['actor'] = $item['author-link']; + $activity['target'] = (string)$target->id; + $activity['summary'] = BBCode::toPlaintext($item['body']); + $activity['object'] = ['id' => (string)$object->id, 'type' => 'tag', 'name' => (string)$object->title, 'content' => (string)$object->content]; - return $data; + return $activity; } /** * Creates an announce object entry * - * @param array $item - * @param array $data activity data - * + * @param array $item Item array + * @param array $activity activity data * @return array with activity data * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function createAnnounce($item, $data) + private static function createAnnounce(array $item, array $activity): array { $orig_body = $item['body']; $announce = self::getAnnounceArray($item); if (empty($announce)) { - $data['type'] = 'Create'; - $data['object'] = self::createNote($item); - return $data; + $activity['type'] = 'Create'; + $activity['object'] = self::createNote($item); + return $activity; } if (empty($announce['comment'])) { // Pure announce, without a quote - $data['type'] = 'Announce'; - $data['object'] = $announce['object']['uri']; - return $data; + $activity['type'] = 'Announce'; + $activity['object'] = $announce['object']['uri']; + return $activity; } // Quote - $data['type'] = 'Create'; + $activity['type'] = 'Create'; $item['body'] = $announce['comment'] . "\n" . $announce['object']['plink']; - $data['object'] = self::createNote($item); + $activity['object'] = self::createNote($item); /// @todo Finally descide how to implement this in AP. This is a possible way: - $data['object']['attachment'][] = self::createNote($announce['object']); + $activity['object']['attachment'][] = self::createNote($announce['object']); - $data['object']['source']['content'] = $orig_body; - return $data; + $activity['object']['source']['content'] = $orig_body; + return $activity; } /** * Return announce related data if the item is an annunce * * @param array $item - * - * @return array + * @return array Announcement array */ - public static function getAnnounceArray($item) + public static function getAnnounceArray(array $item): array { $reshared = Item::getShareArray($item); if (empty($reshared['guid'])) { @@ -1861,11 +1853,10 @@ class Transmitter /** * Checks if the provided item array is an announce * - * @param array $item - * - * @return boolean + * @param array $item Item array + * @return boolean Whether item is an announcement */ - public static function isAnnounce($item) + public static function isAnnounce(array $item): bool { if (!empty($item['verb']) && ($item['verb'] == Activity::ANNOUNCE)) { return true; @@ -1886,7 +1877,7 @@ class Transmitter * * @return bool|string activity id */ - public static function activityIDFromContact($cid) + public static function activityIDFromContact(int $cid) { $contact = DBA::selectFirst('contact', ['uid', 'id', 'created'], ['id' => $cid]); if (!DBA::isResult($contact)) { @@ -1904,17 +1895,17 @@ class Transmitter * @param integer $uid User ID * @param string $inbox Target inbox * @param integer $suggestion_id Suggestion ID - * * @return boolean was the transmission successful? * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function sendContactSuggestion($uid, $inbox, $suggestion_id) + public static function sendContactSuggestion(int $uid, string $inbox, int $suggestion_id): bool { $owner = User::getOwnerDataById($uid); $suggestion = DI::fsuggest()->selectOneById($suggestion_id); - $data = ['@context' => ActivityPub::CONTEXT, + $data = [ + '@context' => ActivityPub::CONTEXT, 'id' => DI::baseUrl() . '/activity/' . System::createGUID(), 'type' => 'Announce', 'actor' => $owner['url'], @@ -1922,7 +1913,8 @@ class Transmitter 'content' => $suggestion->note, 'instrument' => self::getService(), 'to' => [ActivityPub::PUBLIC_COLLECTION], - 'cc' => []]; + 'cc' => [] + ]; $signed = LDSignature::sign($data, $owner); @@ -1935,15 +1927,15 @@ class Transmitter * * @param integer $uid User ID * @param string $inbox Target inbox - * * @return boolean was the transmission successful? * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function sendProfileRelocation($uid, $inbox) + public static function sendProfileRelocation(int $uid, string $inbox): bool { $owner = User::getOwnerDataById($uid); - $data = ['@context' => ActivityPub::CONTEXT, + $data = [ + '@context' => ActivityPub::CONTEXT, 'id' => DI::baseUrl() . '/activity/' . System::createGUID(), 'type' => 'dfrn:relocate', 'actor' => $owner['url'], @@ -1951,7 +1943,8 @@ class Transmitter 'published' => DateTimeFormat::utcNow(DateTimeFormat::ATOM), 'instrument' => self::getService(), 'to' => [ActivityPub::PUBLIC_COLLECTION], - 'cc' => []]; + 'cc' => [] + ]; $signed = LDSignature::sign($data, $owner); @@ -1964,11 +1957,10 @@ class Transmitter * * @param integer $uid User ID * @param string $inbox Target inbox - * * @return boolean was the transmission successful? * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function sendProfileDeletion($uid, $inbox) + public static function sendProfileDeletion(int $uid, string $inbox): bool { $owner = User::getOwnerDataById($uid); @@ -2003,7 +1995,6 @@ class Transmitter * * @param integer $uid User ID * @param string $inbox Target inbox - * * @return boolean was the transmission successful? * @throws HTTPException\InternalServerErrorException * @throws HTTPException\NotFoundException @@ -2036,17 +2027,18 @@ class Transmitter * @param string $activity Type name * @param string $target Target profile * @param integer $uid User ID + * @param string $id Activity-identifier * @return bool * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException * @throws \Exception */ - public static function sendActivity($activity, $target, $uid, $id = '') + public static function sendActivity(string $activity, string $target, int $uid, string $id = ''): bool { $profile = APContact::getByURL($target); if (empty($profile['inbox'])) { Logger::warning('No inbox found for target', ['target' => $target, 'profile' => $profile]); - return; + return false; } $owner = User::getOwnerDataById($uid); @@ -2055,13 +2047,15 @@ class Transmitter $id = DI::baseUrl() . '/activity/' . System::createGUID(); } - $data = ['@context' => ActivityPub::CONTEXT, + $data = [ + '@context' => ActivityPub::CONTEXT, 'id' => $id, 'type' => $activity, 'actor' => $owner['url'], 'object' => $profile['url'], 'instrument' => self::getService(), - 'to' => [$profile['url']]]; + 'to' => [$profile['url']], + ]; Logger::info('Sending activity ' . $activity . ' to ' . $target . ' for user ' . $uid); @@ -2081,12 +2075,12 @@ class Transmitter * @throws \ImagickException * @throws \Exception */ - public static function sendFollowObject($object, $target, $uid = 0) + public static function sendFollowObject(string $object, string $target, int $uid = 0): bool { $profile = APContact::getByURL($target); if (empty($profile['inbox'])) { Logger::warning('No inbox found for target', ['target' => $target, 'profile' => $profile]); - return; + return false; } if (empty($uid)) { @@ -2108,13 +2102,15 @@ class Transmitter $owner = User::getOwnerDataById($uid); - $data = ['@context' => ActivityPub::CONTEXT, + $data = [ + '@context' => ActivityPub::CONTEXT, 'id' => DI::baseUrl() . '/activity/' . System::createGUID(), 'type' => 'Follow', 'actor' => $owner['url'], 'object' => $object, 'instrument' => self::getService(), - 'to' => [$profile['url']]]; + 'to' => [$profile['url']], + ]; Logger::info('Sending follow ' . $object . ' to ' . $target . ' for user ' . $uid); @@ -2126,12 +2122,13 @@ class Transmitter * Transmit a message that the contact request had been accepted * * @param string $target Target profile - * @param $id + * @param string $id Object id * @param integer $uid User ID + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function sendContactAccept($target, $id, $uid) + public static function sendContactAccept(string $target, string $id, int $uid) { $profile = APContact::getByURL($target); if (empty($profile['inbox'])) { @@ -2140,18 +2137,20 @@ class Transmitter } $owner = User::getOwnerDataById($uid); - $data = ['@context' => ActivityPub::CONTEXT, + $data = [ + '@context' => ActivityPub::CONTEXT, 'id' => DI::baseUrl() . '/activity/' . System::createGUID(), 'type' => 'Accept', 'actor' => $owner['url'], 'object' => [ - 'id' => (string)$id, + 'id' => $id, 'type' => 'Follow', 'actor' => $profile['url'], 'object' => $owner['url'] ], 'instrument' => self::getService(), - 'to' => [$profile['url']]]; + 'to' => [$profile['url']], + ]; Logger::debug('Sending accept to ' . $target . ' for user ' . $uid . ' with id ' . $id); @@ -2162,14 +2161,14 @@ class Transmitter /** * Reject a contact request or terminates the contact relation * - * @param string $target Target profile - * @param $id - * @param integer $uid User ID + * @param string $target Target profile + * @param string $objectId Object id + * @param int $uid User ID * @return bool Operation success * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function sendContactReject($target, $id, $uid): bool + public static function sendContactReject(string $target, string $objectId, int $uid): bool { $profile = APContact::getByURL($target); if (empty($profile['inbox'])) { @@ -2178,20 +2177,22 @@ class Transmitter } $owner = User::getOwnerDataById($uid); - $data = ['@context' => ActivityPub::CONTEXT, + $data = [ + '@context' => ActivityPub::CONTEXT, 'id' => DI::baseUrl() . '/activity/' . System::createGUID(), 'type' => 'Reject', - 'actor' => $owner['url'], + 'actor' => $owner['url'], 'object' => [ - 'id' => (string)$id, + 'id' => $objectId, 'type' => 'Follow', 'actor' => $profile['url'], 'object' => $owner['url'] ], 'instrument' => self::getService(), - 'to' => [$profile['url']]]; + 'to' => [$profile['url']], + ]; - Logger::debug('Sending reject to ' . $target . ' for user ' . $uid . ' with id ' . $id); + Logger::debug('Sending reject to ' . $target . ' for user ' . $uid . ' with id ' . $objectId); $signed = LDSignature::sign($data, $owner); return HTTPSignature::transmit($signed, $profile['inbox'], $uid); @@ -2201,13 +2202,14 @@ class Transmitter * Transmits a message that we don't want to follow this contact anymore * * @param string $target Target profile + * @param integer $cid Contact id * @param integer $uid User ID + * @return bool success * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException * @throws \Exception - * @return bool success */ - public static function sendContactUndo($target, $cid, $uid) + public static function sendContactUndo(string $target, int $cid, int $uid): bool { $profile = APContact::getByURL($target); if (empty($profile['inbox'])) { @@ -2220,26 +2222,39 @@ class Transmitter return false; } - $id = DI::baseUrl() . '/activity/' . System::createGUID(); + $objectId = DI::baseUrl() . '/activity/' . System::createGUID(); $owner = User::getOwnerDataById($uid); - $data = ['@context' => ActivityPub::CONTEXT, - 'id' => $id, + $data = [ + '@context' => ActivityPub::CONTEXT, + 'id' => $objectId, 'type' => 'Undo', 'actor' => $owner['url'], - 'object' => ['id' => $object_id, 'type' => 'Follow', + 'object' => [ + 'id' => $object_id, + 'type' => 'Follow', 'actor' => $owner['url'], - 'object' => $profile['url']], + 'object' => $profile['url'] + ], 'instrument' => self::getService(), - 'to' => [$profile['url']]]; + 'to' => [$profile['url']], + ]; - Logger::info('Sending undo to ' . $target . ' for user ' . $uid . ' with id ' . $id); + Logger::info('Sending undo to ' . $target . ' for user ' . $uid . ' with id ' . $objectId); $signed = LDSignature::sign($data, $owner); return HTTPSignature::transmit($signed, $profile['inbox'], $uid); } - private static function prependMentions($body, int $uriid, string $authorLink) + /** + * Prepends mentions (@) to $body variable + * + * @param string $body HTML code + * @param int $uriId + * @param string $authorLink Author link + * @return string HTML code with prepended mentions + */ + private static function prependMentions(string $body, int $uriid, string $authorLink): string { $mentions = []; diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 0fb7394579..edd6c1450e 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -22,6 +22,8 @@ namespace Friendica\Protocol; use DOMDocument; +use DOMElement; +use DOMNode; use DOMXPath; use Friendica\Content\Text\BBCode; use Friendica\Core\Logger; @@ -72,7 +74,7 @@ class DFRN * @return array importer * @throws \Exception */ - public static function getImporter($cid, $uid = 0) + public static function getImporter(int $cid, int $uid = 0): array { $condition = ['id' => $cid, 'blocked' => false, 'pending' => false]; $contact = DBA::selectFirst('contact', [], $condition); @@ -115,12 +117,12 @@ class DFRN * @throws \ImagickException * @todo Find proper type-hints */ - public static function entries($items, $owner) + public static function entries(array $items, array $owner): string { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; - $root = self::addHeader($doc, $owner, "dfrn:owner", "", false); + $root = self::addHeader($doc, $owner, 'dfrn:owner', '', false); if (! count($items)) { return trim($doc->saveXML()); @@ -129,10 +131,10 @@ class DFRN foreach ($items as $item) { // These values aren't sent when sending from the queue. /// @todo Check if we can set these values from the queue or if they are needed at all. - $item["entry:comment-allow"] = ($item["entry:comment-allow"] ?? '') ?: true; - $item["entry:cid"] = $item["entry:cid"] ?? 0; + $item['entry:comment-allow'] = ($item['entry:comment-allow'] ?? '') ?: true; + $item['entry:cid'] = $item['entry:cid'] ?? 0; - $entry = self::entry($doc, "text", $item, $owner, $item["entry:comment-allow"], $item["entry:cid"]); + $entry = self::entry($doc, 'text', $item, $owner, $item['entry:comment-allow'], $item['entry:cid']); if (isset($entry)) { $root->appendChild($entry); } @@ -152,7 +154,7 @@ class DFRN * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function itemFeed(int $uri_id, int $uid, bool $conversation = false) + public static function itemFeed(int $uri_id, int $uid, bool $conversation = false): string { if ($conversation) { $condition = ['parent-uri-id' => $uri_id]; @@ -186,17 +188,15 @@ class DFRN $root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed'); $doc->appendChild($root); - $root->setAttribute("xmlns:thr", ActivityNamespace::THREAD); - $root->setAttribute("xmlns:at", ActivityNamespace::TOMB); - $root->setAttribute("xmlns:media", ActivityNamespace::MEDIA); - $root->setAttribute("xmlns:dfrn", ActivityNamespace::DFRN); - $root->setAttribute("xmlns:activity", ActivityNamespace::ACTIVITY); - $root->setAttribute("xmlns:georss", ActivityNamespace::GEORSS); - $root->setAttribute("xmlns:poco", ActivityNamespace::POCO); - $root->setAttribute("xmlns:ostatus", ActivityNamespace::OSTATUS); - $root->setAttribute("xmlns:statusnet", ActivityNamespace::STATUSNET); - - //$root = self::addHeader($doc, $owner, "dfrn:owner", "", false); + $root->setAttribute('xmlns:thr', ActivityNamespace::THREAD); + $root->setAttribute('xmlns:at', ActivityNamespace::TOMB); + $root->setAttribute('xmlns:media', ActivityNamespace::MEDIA); + $root->setAttribute('xmlns:dfrn', ActivityNamespace::DFRN); + $root->setAttribute('xmlns:activity', ActivityNamespace::ACTIVITY); + $root->setAttribute('xmlns:georss', ActivityNamespace::GEORSS); + $root->setAttribute('xmlns:poco', ActivityNamespace::POCO); + $root->setAttribute('xmlns:ostatus', ActivityNamespace::OSTATUS); + $root->setAttribute('xmlns:statusnet', ActivityNamespace::STATUSNET); foreach ($items as $item) { $entry = self::entry($doc, $type, $item, $owner, true, 0); @@ -222,27 +222,27 @@ class DFRN * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Find proper type-hints */ - public static function mail(array $mail, array $owner) + public static function mail(array $mail, array $owner): string { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; - $root = self::addHeader($doc, $owner, "dfrn:owner", "", false); + $root = self::addHeader($doc, $owner, 'dfrn:owner', '', false); - $mailElement = $doc->createElement("dfrn:mail"); - $senderElement = $doc->createElement("dfrn:sender"); + $mailElement = $doc->createElement('dfrn:mail'); + $senderElement = $doc->createElement('dfrn:sender'); - XML::addElement($doc, $senderElement, "dfrn:name", $owner['name']); - XML::addElement($doc, $senderElement, "dfrn:uri", $owner['url']); - XML::addElement($doc, $senderElement, "dfrn:avatar", $owner['thumb']); + XML::addElement($doc, $senderElement, 'dfrn:name', $owner['name']); + XML::addElement($doc, $senderElement, 'dfrn:uri', $owner['url']); + XML::addElement($doc, $senderElement, 'dfrn:avatar', $owner['thumb']); $mailElement->appendChild($senderElement); - XML::addElement($doc, $mailElement, "dfrn:id", $mail['uri']); - XML::addElement($doc, $mailElement, "dfrn:in-reply-to", $mail['parent-uri']); - XML::addElement($doc, $mailElement, "dfrn:sentdate", DateTimeFormat::utc($mail['created'] . '+00:00', DateTimeFormat::ATOM)); - XML::addElement($doc, $mailElement, "dfrn:subject", $mail['title']); - XML::addElement($doc, $mailElement, "dfrn:content", $mail['body']); + XML::addElement($doc, $mailElement, 'dfrn:id', $mail['uri']); + XML::addElement($doc, $mailElement, 'dfrn:in-reply-to', $mail['parent-uri']); + XML::addElement($doc, $mailElement, 'dfrn:sentdate', DateTimeFormat::utc($mail['created'] . '+00:00', DateTimeFormat::ATOM)); + XML::addElement($doc, $mailElement, 'dfrn:subject', $mail['title']); + XML::addElement($doc, $mailElement, 'dfrn:content', $mail['body']); $root->appendChild($mailElement); @@ -259,20 +259,20 @@ class DFRN * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Find proper type-hints */ - public static function fsuggest($item, $owner) + public static function fsuggest(array $item, array $owner): string { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; - $root = self::addHeader($doc, $owner, "dfrn:owner", "", false); + $root = self::addHeader($doc, $owner, 'dfrn:owner', '', false); - $suggest = $doc->createElement("dfrn:suggest"); + $suggest = $doc->createElement('dfrn:suggest'); - XML::addElement($doc, $suggest, "dfrn:url", $item['url']); - XML::addElement($doc, $suggest, "dfrn:name", $item['name']); - XML::addElement($doc, $suggest, "dfrn:photo", $item['photo']); - XML::addElement($doc, $suggest, "dfrn:request", $item['request']); - XML::addElement($doc, $suggest, "dfrn:note", $item['note']); + XML::addElement($doc, $suggest, 'dfrn:url', $item['url']); + XML::addElement($doc, $suggest, 'dfrn:name', $item['name']); + XML::addElement($doc, $suggest, 'dfrn:photo', $item['photo']); + XML::addElement($doc, $suggest, 'dfrn:request', $item['request']); + XML::addElement($doc, $suggest, 'dfrn:note', $item['note']); $root->appendChild($suggest); @@ -289,7 +289,7 @@ class DFRN * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Find proper type-hints */ - public static function relocate($owner, $uid) + public static function relocate(array $owner, int $uid): string { /* get site pubkey. this could be a new installation with no site keys*/ @@ -313,22 +313,22 @@ class DFRN $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; - $root = self::addHeader($doc, $owner, "dfrn:owner", "", false); + $root = self::addHeader($doc, $owner, 'dfrn:owner', '', false); - $relocate = $doc->createElement("dfrn:relocate"); + $relocate = $doc->createElement('dfrn:relocate'); - XML::addElement($doc, $relocate, "dfrn:url", $owner['url']); - XML::addElement($doc, $relocate, "dfrn:name", $owner['name']); - XML::addElement($doc, $relocate, "dfrn:addr", $owner['addr']); - XML::addElement($doc, $relocate, "dfrn:avatar", $owner['avatar']); - XML::addElement($doc, $relocate, "dfrn:photo", $photos[4]); - XML::addElement($doc, $relocate, "dfrn:thumb", $photos[5]); - XML::addElement($doc, $relocate, "dfrn:micro", $photos[6]); - XML::addElement($doc, $relocate, "dfrn:request", $owner['request']); - XML::addElement($doc, $relocate, "dfrn:confirm", $owner['confirm']); - XML::addElement($doc, $relocate, "dfrn:notify", $owner['notify']); - XML::addElement($doc, $relocate, "dfrn:poll", $owner['poll']); - XML::addElement($doc, $relocate, "dfrn:sitepubkey", DI::config()->get('system', 'site_pubkey')); + XML::addElement($doc, $relocate, 'dfrn:url', $owner['url']); + XML::addElement($doc, $relocate, 'dfrn:name', $owner['name']); + XML::addElement($doc, $relocate, 'dfrn:addr', $owner['addr']); + XML::addElement($doc, $relocate, 'dfrn:avatar', $owner['avatar']); + XML::addElement($doc, $relocate, 'dfrn:photo', $photos[4]); + XML::addElement($doc, $relocate, 'dfrn:thumb', $photos[5]); + XML::addElement($doc, $relocate, 'dfrn:micro', $photos[6]); + XML::addElement($doc, $relocate, 'dfrn:request', $owner['request']); + XML::addElement($doc, $relocate, 'dfrn:confirm', $owner['confirm']); + XML::addElement($doc, $relocate, 'dfrn:notify', $owner['notify']); + XML::addElement($doc, $relocate, 'dfrn:poll', $owner['poll']); + XML::addElement($doc, $relocate, 'dfrn:sitepubkey', DI::config()->get('system', 'site_pubkey')); $root->appendChild($relocate); @@ -343,69 +343,67 @@ class DFRN * @param string $authorelement Element name for the author * @param string $alternatelink link to profile or category * @param bool $public Is it a header for public posts? - * - * @return object XML root object + * @return DOMElement XML root element * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @todo Find proper type-hints + * @todo Find proper type-hint for returned type */ - private static function addHeader(DOMDocument $doc, $owner, $authorelement, $alternatelink = "", $public = false) + private static function addHeader(DOMDocument $doc, array $owner, string $authorelement, string $alternatelink = '', bool $public = false): DOMElement { - - if ($alternatelink == "") { + if ($alternatelink == '') { $alternatelink = $owner['url']; } $root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed'); $doc->appendChild($root); - $root->setAttribute("xmlns:thr", ActivityNamespace::THREAD); - $root->setAttribute("xmlns:at", ActivityNamespace::TOMB); - $root->setAttribute("xmlns:media", ActivityNamespace::MEDIA); - $root->setAttribute("xmlns:dfrn", ActivityNamespace::DFRN); - $root->setAttribute("xmlns:activity", ActivityNamespace::ACTIVITY); - $root->setAttribute("xmlns:georss", ActivityNamespace::GEORSS); - $root->setAttribute("xmlns:poco", ActivityNamespace::POCO); - $root->setAttribute("xmlns:ostatus", ActivityNamespace::OSTATUS); - $root->setAttribute("xmlns:statusnet", ActivityNamespace::STATUSNET); + $root->setAttribute('xmlns:thr', ActivityNamespace::THREAD); + $root->setAttribute('xmlns:at', ActivityNamespace::TOMB); + $root->setAttribute('xmlns:media', ActivityNamespace::MEDIA); + $root->setAttribute('xmlns:dfrn', ActivityNamespace::DFRN); + $root->setAttribute('xmlns:activity', ActivityNamespace::ACTIVITY); + $root->setAttribute('xmlns:georss', ActivityNamespace::GEORSS); + $root->setAttribute('xmlns:poco', ActivityNamespace::POCO); + $root->setAttribute('xmlns:ostatus', ActivityNamespace::OSTATUS); + $root->setAttribute('xmlns:statusnet', ActivityNamespace::STATUSNET); - XML::addElement($doc, $root, "id", DI::baseUrl()."/profile/".$owner["nick"]); - XML::addElement($doc, $root, "title", $owner["name"]); + XML::addElement($doc, $root, 'id', DI::baseUrl() . '/profile/' . $owner['nick']); + XML::addElement($doc, $root, 'title', $owner['name']); - $attributes = ["uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION."-".DB_UPDATE_VERSION]; - XML::addElement($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); + $attributes = ['uri' => 'https://friendi.ca', 'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION]; + XML::addElement($doc, $root, 'generator', FRIENDICA_PLATFORM, $attributes); - $attributes = ["rel" => "license", "href" => "http://creativecommons.org/licenses/by/3.0/"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['rel' => 'license', 'href' => 'http://creativecommons.org/licenses/by/3.0/']; + XML::addElement($doc, $root, 'link', '', $attributes); - $attributes = ["rel" => "alternate", "type" => "text/html", "href" => $alternatelink]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['rel' => 'alternate', 'type' => 'text/html', 'href' => $alternatelink]; + XML::addElement($doc, $root, 'link', '', $attributes); if ($public) { // DFRN itself doesn't uses this. But maybe someone else wants to subscribe to the public feed. - OStatus::hublinks($doc, $root, $owner["nick"]); + OStatus::addHubLink($doc, $root, $owner['nick']); - $attributes = ["rel" => "salmon", "href" => DI::baseUrl()."/salmon/".$owner["nick"]]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['rel' => 'salmon', 'href' => DI::baseUrl() . '/salmon/' . $owner['nick']]; + XML::addElement($doc, $root, 'link', '', $attributes); - $attributes = ["rel" => "http://salmon-protocol.org/ns/salmon-replies", "href" => DI::baseUrl()."/salmon/".$owner["nick"]]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['rel' => 'http://salmon-protocol.org/ns/salmon-replies', 'href' => DI::baseUrl() . '/salmon/' . $owner['nick']]; + XML::addElement($doc, $root, 'link', '', $attributes); - $attributes = ["rel" => "http://salmon-protocol.org/ns/salmon-mention", "href" => DI::baseUrl()."/salmon/".$owner["nick"]]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['rel' => 'http://salmon-protocol.org/ns/salmon-mention', 'href' => DI::baseUrl() . '/salmon/' . $owner['nick']]; + XML::addElement($doc, $root, 'link', '', $attributes); } // For backward compatibility we keep this element if ($owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY) { - XML::addElement($doc, $root, "dfrn:community", 1); + XML::addElement($doc, $root, 'dfrn:community', 1); } // The former element is replaced by this one - XML::addElement($doc, $root, "dfrn:account_type", $owner["account-type"]); + XML::addElement($doc, $root, 'dfrn:account_type', $owner['account-type']); /// @todo We need a way to transmit the different page flags like "User::PAGE_FLAGS_PRVGROUP" - XML::addElement($doc, $root, "updated", DateTimeFormat::utcNow(DateTimeFormat::ATOM)); + XML::addElement($doc, $root, 'updated', DateTimeFormat::utcNow(DateTimeFormat::ATOM)); $author = self::addAuthor($doc, $owner, $authorelement, $public); $root->appendChild($author); @@ -428,8 +426,12 @@ class DFRN * viewer's timezone also, but first we are going to convert it from the birthday * person's timezone to GMT - so the viewer may find the birthday starting at * 6:00PM the day before, but that will correspond to midnight to the birthday person. + * + * @param int $uid User id + * @param string $tz Time zone string, like UTC + * @return string Formatted birthday string */ - private static function determineNextBirthday($uid, $tz) + private static function determineNextBirthday(int $uid, string $tz): string { $birthday = ''; @@ -462,12 +464,11 @@ class DFRN * @param array $owner Owner record * @param string $authorelement Element name for the author * @param boolean $public boolean - * - * @return \DOMElement XML author object + * @return DOMElement XML author object * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Find proper type-hints */ - private static function addAuthor(DOMDocument $doc, array $owner, $authorelement, $public) + private static function addAuthor(DOMDocument $doc, array $owner, string $authorelement, bool $public): DOMElement { // Should the profile be "unsearchable" in the net? Then add the "hide" element $hide = DBA::exists('profile', ['uid' => $owner['uid'], 'net-publish' => false]); @@ -480,28 +481,32 @@ class DFRN $attributes = []; if (!$public || !$hide) { - $attributes = ["dfrn:updated" => $namdate]; + $attributes = ['dfrn:updated' => $namdate]; } - XML::addElement($doc, $author, "name", $owner["name"], $attributes); - XML::addElement($doc, $author, "uri", DI::baseUrl().'/profile/'.$owner["nickname"], $attributes); - XML::addElement($doc, $author, "dfrn:handle", $owner["addr"], $attributes); + XML::addElement($doc, $author, 'name', $owner['name'], $attributes); + XML::addElement($doc, $author, 'uri', DI::baseUrl().'/profile/' . $owner['nickname'], $attributes); + XML::addElement($doc, $author, 'dfrn:handle', $owner['addr'], $attributes); - $attributes = ["rel" => "photo", "type" => "image/jpeg", - "media:width" => Proxy::PIXEL_SMALL, "media:height" => Proxy::PIXEL_SMALL, - "href" => User::getAvatarUrl($owner, Proxy::SIZE_SMALL)]; + $attributes = [ + 'rel' => 'photo', + 'type' => 'image/jpeg', + 'media:width' => Proxy::PIXEL_SMALL, + 'media:height' => Proxy::PIXEL_SMALL, + 'href' => User::getAvatarUrl($owner, Proxy::SIZE_SMALL), + ]; if (!$public || !$hide) { - $attributes["dfrn:updated"] = $picdate; + $attributes['dfrn:updated'] = $picdate; } - XML::addElement($doc, $author, "link", "", $attributes); + XML::addElement($doc, $author, 'link', '', $attributes); - $attributes["rel"] = "avatar"; - XML::addElement($doc, $author, "link", "", $attributes); + $attributes['rel'] = 'avatar'; + XML::addElement($doc, $author, 'link', '', $attributes); if ($hide) { - XML::addElement($doc, $author, "dfrn:hide", "true"); + XML::addElement($doc, $author, 'dfrn:hide', 'true'); } // The following fields will only be generated if the data isn't meant for a public feed @@ -512,7 +517,7 @@ class DFRN $birthday = self::determineNextBirthday($owner['uid'], $owner['timezone']); if ($birthday) { - XML::addElement($doc, $author, "dfrn:birthday", $birthday); + XML::addElement($doc, $author, 'dfrn:birthday', $birthday); } // Only show contact details when we are allowed to @@ -520,57 +525,57 @@ class DFRN ['about', 'name', 'homepage', 'nickname', 'timezone', 'locality', 'region', 'country-name', 'pub_keywords', 'xmpp', 'dob'], ['uid' => $owner['uid'], 'hidewall' => false]); if (DBA::isResult($profile)) { - XML::addElement($doc, $author, "poco:displayName", $profile["name"]); - XML::addElement($doc, $author, "poco:updated", $namdate); + XML::addElement($doc, $author, 'poco:displayName', $profile['name']); + XML::addElement($doc, $author, 'poco:updated', $namdate); - if (trim($profile["dob"]) > DBA::NULL_DATE) { - XML::addElement($doc, $author, "poco:birthday", "0000-".date("m-d", strtotime($profile["dob"]))); + if (trim($profile['dob']) > DBA::NULL_DATE) { + XML::addElement($doc, $author, 'poco:birthday', '0000-'.date('m-d', strtotime($profile['dob']))); } - XML::addElement($doc, $author, "poco:note", $profile["about"]); - XML::addElement($doc, $author, "poco:preferredUsername", $profile["nickname"]); + XML::addElement($doc, $author, 'poco:note', $profile['about']); + XML::addElement($doc, $author, 'poco:preferredUsername', $profile['nickname']); - XML::addElement($doc, $author, "poco:utcOffset", DateTimeFormat::timezoneNow($profile["timezone"], "P")); + XML::addElement($doc, $author, 'poco:utcOffset', DateTimeFormat::timezoneNow($profile['timezone'], 'P')); - if (trim($profile["homepage"]) != "") { - $urls = $doc->createElement("poco:urls"); - XML::addElement($doc, $urls, "poco:type", "homepage"); - XML::addElement($doc, $urls, "poco:value", $profile["homepage"]); - XML::addElement($doc, $urls, "poco:primary", "true"); + if (trim($profile['homepage']) != '') { + $urls = $doc->createElement('poco:urls'); + XML::addElement($doc, $urls, 'poco:type', 'homepage'); + XML::addElement($doc, $urls, 'poco:value', $profile['homepage']); + XML::addElement($doc, $urls, 'poco:primary', 'true'); $author->appendChild($urls); } - if (trim($profile["pub_keywords"]) != "") { - $keywords = explode(",", $profile["pub_keywords"]); + if (trim($profile['pub_keywords']) != '') { + $keywords = explode(',', $profile['pub_keywords']); foreach ($keywords as $keyword) { - XML::addElement($doc, $author, "poco:tags", trim($keyword)); + XML::addElement($doc, $author, 'poco:tags', trim($keyword)); } } - if (trim($profile["xmpp"]) != "") { - $ims = $doc->createElement("poco:ims"); - XML::addElement($doc, $ims, "poco:type", "xmpp"); - XML::addElement($doc, $ims, "poco:value", $profile["xmpp"]); - XML::addElement($doc, $ims, "poco:primary", "true"); + if (trim($profile['xmpp']) != '') { + $ims = $doc->createElement('poco:ims'); + XML::addElement($doc, $ims, 'poco:type', 'xmpp'); + XML::addElement($doc, $ims, 'poco:value', $profile['xmpp']); + XML::addElement($doc, $ims, 'poco:primary', 'true'); $author->appendChild($ims); } - if (trim($profile["locality"].$profile["region"].$profile["country-name"]) != "") { - $element = $doc->createElement("poco:address"); + if (trim($profile['locality'] . $profile['region'] . $profile['country-name']) != '') { + $element = $doc->createElement('poco:address'); - XML::addElement($doc, $element, "poco:formatted", Profile::formatLocation($profile)); + XML::addElement($doc, $element, 'poco:formatted', Profile::formatLocation($profile)); - if (trim($profile["locality"]) != "") { - XML::addElement($doc, $element, "poco:locality", $profile["locality"]); + if (trim($profile['locality']) != '') { + XML::addElement($doc, $element, 'poco:locality', $profile['locality']); } - if (trim($profile["region"]) != "") { - XML::addElement($doc, $element, "poco:region", $profile["region"]); + if (trim($profile['region']) != '') { + XML::addElement($doc, $element, 'poco:region', $profile['region']); } - if (trim($profile["country-name"]) != "") { - XML::addElement($doc, $element, "poco:country", $profile["country-name"]); + if (trim($profile['country-name']) != '') { + XML::addElement($doc, $element, 'poco:country', $profile['country-name']); } $author->appendChild($element); @@ -584,42 +589,43 @@ class DFRN * Adds the author elements in the "entry" elements of the DFRN protocol * * @param DOMDocument $doc XML document - * @param string $element Element name for the author - * @param string $contact_url Link of the contact - * @param array $item Item elements - * - * @return \DOMElement XML author object + * @param string $element Element name for the author + * @param string $contact_url Link of the contact + * @param array $item Item elements + * @return DOMElement XML author object * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Find proper type-hints */ - private static function addEntryAuthor(DOMDocument $doc, $element, $contact_url, $item) + private static function addEntryAuthor(DOMDocument $doc, string $element, string $contact_url, array $item): DOMElement { $author = $doc->createElement($element); - $contact = Contact::getByURLForUser($contact_url, $item["uid"], false, ['url', 'name', 'addr', 'photo']); + $contact = Contact::getByURLForUser($contact_url, $item['uid'], false, ['url', 'name', 'addr', 'photo']); if (!empty($contact)) { - XML::addElement($doc, $author, "name", $contact["name"]); - XML::addElement($doc, $author, "uri", $contact["url"]); - XML::addElement($doc, $author, "dfrn:handle", $contact["addr"]); + XML::addElement($doc, $author, 'name', $contact['name']); + XML::addElement($doc, $author, 'uri', $contact['url']); + XML::addElement($doc, $author, 'dfrn:handle', $contact['addr']); /// @Todo /// - Check real image type and image size /// - Check which of these boths elements we should use $attributes = [ - "rel" => "photo", - "type" => "image/jpeg", - "media:width" => 80, - "media:height" => 80, - "href" => $contact["photo"]]; - XML::addElement($doc, $author, "link", "", $attributes); + 'rel' => 'photo', + 'type' => 'image/jpeg', + 'media:width' => 80, + 'media:height' => 80, + 'href' => $contact['photo'], + ]; + XML::addElement($doc, $author, 'link', '', $attributes); $attributes = [ - "rel" => "avatar", - "type" => "image/jpeg", - "media:width" => 80, - "media:height" => 80, - "href" => $contact["photo"]]; - XML::addElement($doc, $author, "link", "", $attributes); + 'rel' => 'avatar', + 'type' => 'image/jpeg', + 'media:width' => 80, + 'media:height' => 80, + 'href' => $contact['photo'], + ]; + XML::addElement($doc, $author, 'link', '', $attributes); } return $author; @@ -632,12 +638,11 @@ class DFRN * @param string $element Element name for the activity * @param string $activity activity value * @param int $uriid Uri-Id of the post - * - * @return \DOMElement XML activity object + * @return DOMElement XML activity object * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo Find proper type-hints */ - private static function createActivity(DOMDocument $doc, $element, $activity, $uriid) + private static function createActivity(DOMDocument $doc, string $element, string $activity, int $uriid) { if ($activity) { $entry = $doc->createElement($element); @@ -703,7 +708,7 @@ class DFRN * @return void XML attachment object * @todo Find proper type-hints */ - private static function getAttachment($doc, $root, $item) + private static function getAttachment($doc, $root, array $item) { foreach (Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]) as $attachment) { $attributes = ['rel' => 'enclosure', @@ -737,7 +742,7 @@ class DFRN * @throws \ImagickException * @todo Find proper type-hints */ - private static function entry(DOMDocument $doc, $type, array $item, array $owner, $comment = false, $cid = 0, $single = false) + private static function entry(DOMDocument $doc, string $type, array $item, array $owner, bool $comment = false, int $cid = 0, bool $single = false) { $mentioned = []; @@ -821,91 +826,95 @@ class DFRN } $attributes = [ - "href" => $conversation_href, - "ref" => $conversation_uri]; + 'href' => $conversation_href, + 'ref' => $conversation_uri, + ]; - XML::addElement($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes); + XML::addElement($doc, $entry, 'ostatus:conversation', $conversation_uri, $attributes); - XML::addElement($doc, $entry, "id", $item["uri"]); - XML::addElement($doc, $entry, "title", $item["title"]); + XML::addElement($doc, $entry, 'id', $item['uri']); + XML::addElement($doc, $entry, 'title', $item['title']); - XML::addElement($doc, $entry, "published", DateTimeFormat::utc($item["created"] . "+00:00", DateTimeFormat::ATOM)); - XML::addElement($doc, $entry, "updated", DateTimeFormat::utc($item["edited"] . "+00:00", DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'published', DateTimeFormat::utc($item['created'] . '+00:00', DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'updated', DateTimeFormat::utc($item['edited'] . '+00:00', DateTimeFormat::ATOM)); // "dfrn:env" is used to read the content - XML::addElement($doc, $entry, "dfrn:env", Strings::base64UrlEncode($body, true)); + XML::addElement($doc, $entry, 'dfrn:env', Strings::base64UrlEncode($body, true)); // The "content" field is not read by the receiver. We could remove it when the type is "text" // We keep it at the moment, maybe there is some old version that doesn't read "dfrn:env" - XML::addElement($doc, $entry, "content", (($type == 'html') ? $htmlbody : $body), ["type" => $type]); + XML::addElement($doc, $entry, 'content', (($type == 'html') ? $htmlbody : $body), ['type' => $type]); // We save this value in "plink". Maybe we should read it from there as well? XML::addElement( $doc, $entry, - "link", - "", - ["rel" => "alternate", "type" => "text/html", - "href" => DI::baseUrl() . "/display/" . $item["guid"]] + 'link', + '', + [ + 'rel' => 'alternate', + 'type' => 'text/html', + 'href' => DI::baseUrl() . '/display/' . $item['guid'] + ], ); // "comment-allow" is some old fashioned stuff for old Friendica versions. // It is included in the rewritten code for completeness if ($comment) { - XML::addElement($doc, $entry, "dfrn:comment-allow", 1); + XML::addElement($doc, $entry, 'dfrn:comment-allow', 1); } if ($item['location']) { - XML::addElement($doc, $entry, "dfrn:location", $item['location']); + XML::addElement($doc, $entry, 'dfrn:location', $item['location']); } if ($item['coord']) { - XML::addElement($doc, $entry, "georss:point", $item['coord']); + XML::addElement($doc, $entry, 'georss:point', $item['coord']); } if ($item['private']) { // Friendica versions prior to 2020.3 can't handle "unlisted" properly. So we can only transmit public and private - XML::addElement($doc, $entry, "dfrn:private", ($item['private'] == Item::PRIVATE ? Item::PRIVATE : Item::PUBLIC)); - XML::addElement($doc, $entry, "dfrn:unlisted", $item['private'] == Item::UNLISTED); + XML::addElement($doc, $entry, 'dfrn:private', ($item['private'] == Item::PRIVATE ? Item::PRIVATE : Item::PUBLIC)); + XML::addElement($doc, $entry, 'dfrn:unlisted', $item['private'] == Item::UNLISTED); } if ($item['extid']) { - XML::addElement($doc, $entry, "dfrn:extid", $item['extid']); + XML::addElement($doc, $entry, 'dfrn:extid', $item['extid']); } if ($item['post-type'] == Item::PT_PAGE) { - XML::addElement($doc, $entry, "dfrn:bookmark", "true"); + XML::addElement($doc, $entry, 'dfrn:bookmark', 'true'); } if ($item['app']) { - XML::addElement($doc, $entry, "statusnet:notice_info", "", ["local_id" => $item['id'], "source" => $item['app']]); + XML::addElement($doc, $entry, 'statusnet:notice_info', '', ['local_id' => $item['id'], 'source' => $item['app']]); } - XML::addElement($doc, $entry, "dfrn:diaspora_guid", $item["guid"]); + XML::addElement($doc, $entry, 'dfrn:diaspora_guid', $item['guid']); // The signed text contains the content in Markdown, the sender handle and the signatur for the content // It is needed for relayed comments to Diaspora. if ($item['signed_text']) { $sign = base64_encode(json_encode(['signed_text' => $item['signed_text'],'signature' => '','signer' => ''])); - XML::addElement($doc, $entry, "dfrn:diaspora_signature", $sign); + XML::addElement($doc, $entry, 'dfrn:diaspora_signature', $sign); } - XML::addElement($doc, $entry, "activity:verb", self::constructVerb($item)); + XML::addElement($doc, $entry, 'activity:verb', self::constructVerb($item)); - if ($item['object-type'] != "") { - XML::addElement($doc, $entry, "activity:object-type", $item['object-type']); + if ($item['object-type'] != '') { + XML::addElement($doc, $entry, 'activity:object-type', $item['object-type']); } elseif ($item['gravity'] == GRAVITY_PARENT) { - XML::addElement($doc, $entry, "activity:object-type", Activity\ObjectType::NOTE); + XML::addElement($doc, $entry, 'activity:object-type', Activity\ObjectType::NOTE); } else { - XML::addElement($doc, $entry, "activity:object-type", Activity\ObjectType::COMMENT); + XML::addElement($doc, $entry, 'activity:object-type', Activity\ObjectType::COMMENT); } - $actobj = self::createActivity($doc, "activity:object", $item['object'], $item['uri-id']); + $actobj = self::createActivity($doc, 'activity:object', $item['object'] ?? '', $item['uri-id']); if ($actobj) { $entry->appendChild($actobj); } - $actarg = self::createActivity($doc, "activity:target", $item['target'], $item['uri-id']); + $actarg = self::createActivity($doc, 'activity:target', $item['target'] ?? '', $item['uri-id']); if ($actarg) { $entry->appendChild($actarg); } @@ -915,7 +924,7 @@ class DFRN if (count($tags)) { foreach ($tags as $tag) { if (($type != 'html') || ($tag['type'] == Tag::HASHTAG)) { - XML::addElement($doc, $entry, "category", "", ["scheme" => "X-DFRN:" . Tag::TAG_CHARACTER[$tag['type']] . ":" . $tag['url'], "term" => $tag['name']]); + XML::addElement($doc, $entry, 'category', '', ['scheme' => 'X-DFRN:' . Tag::TAG_CHARACTER[$tag['type']] . ':' . $tag['url'], 'term' => $tag['name']]); } if ($tag['type'] != Tag::HASHTAG) { $mentioned[$tag['url']] = $tag['url']; @@ -924,28 +933,32 @@ class DFRN } foreach ($mentioned as $mention) { - $condition = ['uid' => $owner["uid"], 'nurl' => Strings::normaliseLink($mention)]; + $condition = ['uid' => $owner['uid'], 'nurl' => Strings::normaliseLink($mention)]; $contact = DBA::selectFirst('contact', ['contact-type'], $condition); if (DBA::isResult($contact) && ($contact['contact-type'] == Contact::TYPE_COMMUNITY)) { XML::addElement( $doc, $entry, - "link", - "", - ["rel" => "mentioned", - "ostatus:object-type" => Activity\ObjectType::GROUP, - "href" => $mention] + 'link', + '', + [ + 'rel' => 'mentioned', + 'ostatus:object-type' => Activity\ObjectType::GROUP, + 'href' => $mention, + ], ); } else { XML::addElement( $doc, $entry, - "link", - "", - ["rel" => "mentioned", - "ostatus:object-type" => Activity\ObjectType::PERSON, - "href" => $mention] + 'link', + '', + [ + 'rel' => 'mentioned', + 'ostatus:object-type' => Activity\ObjectType::PERSON, + 'href' => $mention, + ], ); } } @@ -961,13 +974,12 @@ class DFRN * @param array $owner Owner record * @param array $contact Contact record of the receiver * @param string $atom Content that will be transmitted - * * @param bool $public_batch * @return int Deliver status. Negative values mean an error. * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function transmit($owner, $contact, $atom, $public_batch = false) + public static function transmit(array $owner, array $contact, string $atom, bool $public_batch = false) { if (!$public_batch) { if (empty($contact['addr'])) { @@ -996,22 +1008,22 @@ class DFRN $envelope = Diaspora::buildMessage($atom, $owner, $contact, $owner['uprvkey'], $pubkey, $public_batch); // Create the endpoint for public posts. This is some WIP and should later be added to the probing - if ($public_batch && empty($contact["batch"])) { - $parts = parse_url($contact["notify"]); + if ($public_batch && empty($contact['batch'])) { + $parts = parse_url($contact['notify']); $path_parts = explode('/', $parts['path']); array_pop($path_parts); $parts['path'] = implode('/', $path_parts); - $contact["batch"] = Network::unparseURL($parts); + $contact['batch'] = Network::unparseURL($parts); } - $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); + $dest_url = ($public_batch ? $contact['batch'] : $contact['notify']); if (empty($dest_url)) { Logger::info('Empty destination', ['public' => $public_batch, 'contact' => $contact]); return -24; } - $content_type = ($public_batch ? "application/magic-envelope+xml" : "application/json"); + $content_type = ($public_batch ? 'application/magic-envelope+xml' : 'application/json'); $postResult = DI::httpClient()->post($dest_url, $envelope, ['Content-Type' => $content_type]); $xml = $postResult->getBody(); @@ -1060,7 +1072,7 @@ class DFRN * @throws \ImagickException * @todo Find good type-hints for all parameter */ - private static function fetchauthor(\DOMXPath $xpath, \DOMNode $context, $importer, $element, $onlyfetch, $xml = "") + private static function fetchauthor(\DOMXPath $xpath, \DOMNode $context, array $importer, string $element, bool $onlyfetch, string $xml = ''): array { $author = []; $author["name"] = XML::getFirstNodeValue($xpath, $element."/atom:name/text()", $context); @@ -1280,7 +1292,7 @@ class DFRN * @return string XML string * @todo Find good type-hints for all parameter */ - private static function transformActivity($xpath, $activity, $element) + private static function transformActivity($xpath, $activity, string $element): string { if (!is_object($activity)) { return ""; @@ -1328,28 +1340,27 @@ class DFRN /** * Processes the mail elements * - * @param object $xpath XPath object - * @param object $mail mail elements - * @param array $importer Record of the importer user mixed with contact of the content + * @param DOMXPath $xpath XPath object + * @param DOMNode $mail mail elements + * @param array $importer Record of the importer user mixed with contact of the content * @return void * @throws \Exception - * @todo Find good type-hints for all parameter */ - private static function processMail($xpath, $mail, $importer) + private static function processMail(DOMXPath $xpath, DOMNode $mail, array $importer) { Logger::notice("Processing mails"); $msg = []; - $msg["uid"] = $importer["importer_uid"]; - $msg["from-name"] = XML::getFirstValue($xpath, "dfrn:sender/dfrn:name/text()", $mail); - $msg["from-url"] = XML::getFirstValue($xpath, "dfrn:sender/dfrn:uri/text()", $mail); - $msg["from-photo"] = XML::getFirstValue($xpath, "dfrn:sender/dfrn:avatar/text()", $mail); - $msg["contact-id"] = $importer["id"]; - $msg["uri"] = XML::getFirstValue($xpath, "dfrn:id/text()", $mail); - $msg["parent-uri"] = XML::getFirstValue($xpath, "dfrn:in-reply-to/text()", $mail); - $msg["created"] = DateTimeFormat::utc(XML::getFirstValue($xpath, "dfrn:sentdate/text()", $mail)); - $msg["title"] = XML::getFirstValue($xpath, "dfrn:subject/text()", $mail); - $msg["body"] = XML::getFirstValue($xpath, "dfrn:content/text()", $mail); + $msg['uid'] = $importer['importer_uid']; + $msg['from-name'] = XML::getFirstValue($xpath, 'dfrn:sender/dfrn:name/text()', $mail); + $msg['from-url'] = XML::getFirstValue($xpath, 'dfrn:sender/dfrn:uri/text()', $mail); + $msg['from-photo'] = XML::getFirstValue($xpath, 'dfrn:sender/dfrn:avatar/text()', $mail); + $msg['contact-id'] = $importer['id']; + $msg['uri'] = XML::getFirstValue($xpath, 'dfrn:id/text()', $mail); + $msg['parent-uri'] = XML::getFirstValue($xpath, 'dfrn:in-reply-to/text()', $mail); + $msg['created'] = DateTimeFormat::utc(XML::getFirstValue($xpath, 'dfrn:sentdate/text()', $mail)); + $msg['title'] = XML::getFirstValue($xpath, 'dfrn:subject/text()', $mail); + $msg['body'] = XML::getFirstValue($xpath, 'dfrn:content/text()', $mail); Mail::insert($msg); } @@ -1357,14 +1368,13 @@ class DFRN /** * Processes the suggestion elements * - * @param object $xpath XPath object - * @param object $suggestion suggestion elements - * @param array $importer Record of the importer user mixed with contact of the content + * @param DOMXPath $xpath XPath object + * @param DOMNode $suggestion suggestion elements + * @param array $importer Record of the importer user mixed with contact of the content * @return boolean * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @todo Find good type-hints for all parameter */ - private static function processSuggestion($xpath, $suggestion, $importer) + private static function processSuggestion(DOMXPath $xpath, DOMNode $suggestion, array $importer) { Logger::notice('Processing suggestions'); @@ -1383,7 +1393,7 @@ class DFRN * @param integer $from_cid * @return bool Was the adding successful? */ - private static function addSuggestion(int $uid, int $cid, int $from_cid, string $note = '') + private static function addSuggestion(int $uid, int $cid, int $from_cid, string $note = ''): bool { $owner = User::getOwnerDataById($uid); $contact = Contact::getById($cid); @@ -1432,45 +1442,45 @@ class DFRN /** * Processes the relocation elements * - * @param object $xpath XPath object - * @param object $relocation relocation elements - * @param array $importer Record of the importer user mixed with contact of the content + * @param DOMXPath $xpath XPath object + * @param DOMNode $relocation relocation elements + * @param array $importer Record of the importer user mixed with contact of the content * @return boolean * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException * @todo Find good type-hints for all parameter */ - private static function processRelocation($xpath, $relocation, $importer) + private static function processRelocation(DOMXPath $xpath, DOMNode $relocation, array $importer): bool { Logger::notice("Processing relocations"); /// @TODO Rewrite this to one statement $relocate = []; - $relocate["uid"] = $importer["importer_uid"]; - $relocate["cid"] = $importer["id"]; - $relocate["url"] = $xpath->query("dfrn:url/text()", $relocation)->item(0)->nodeValue; - $relocate["addr"] = $xpath->query("dfrn:addr/text()", $relocation)->item(0)->nodeValue; - $relocate["name"] = $xpath->query("dfrn:name/text()", $relocation)->item(0)->nodeValue; - $relocate["avatar"] = $xpath->query("dfrn:avatar/text()", $relocation)->item(0)->nodeValue; - $relocate["photo"] = $xpath->query("dfrn:photo/text()", $relocation)->item(0)->nodeValue; - $relocate["thumb"] = $xpath->query("dfrn:thumb/text()", $relocation)->item(0)->nodeValue; - $relocate["micro"] = $xpath->query("dfrn:micro/text()", $relocation)->item(0)->nodeValue; - $relocate["request"] = $xpath->query("dfrn:request/text()", $relocation)->item(0)->nodeValue; - $relocate["confirm"] = $xpath->query("dfrn:confirm/text()", $relocation)->item(0)->nodeValue; - $relocate["notify"] = $xpath->query("dfrn:notify/text()", $relocation)->item(0)->nodeValue; - $relocate["poll"] = $xpath->query("dfrn:poll/text()", $relocation)->item(0)->nodeValue; - $relocate["sitepubkey"] = $xpath->query("dfrn:sitepubkey/text()", $relocation)->item(0)->nodeValue; + $relocate['uid'] = $importer['importer_uid']; + $relocate['cid'] = $importer['id']; + $relocate['url'] = $xpath->query('dfrn:url/text()', $relocation)->item(0)->nodeValue; + $relocate['addr'] = $xpath->query('dfrn:addr/text()', $relocation)->item(0)->nodeValue; + $relocate['name'] = $xpath->query('dfrn:name/text()', $relocation)->item(0)->nodeValue; + $relocate['avatar'] = $xpath->query('dfrn:avatar/text()', $relocation)->item(0)->nodeValue; + $relocate['photo'] = $xpath->query('dfrn:photo/text()', $relocation)->item(0)->nodeValue; + $relocate['thumb'] = $xpath->query('dfrn:thumb/text()', $relocation)->item(0)->nodeValue; + $relocate['micro'] = $xpath->query('dfrn:micro/text()', $relocation)->item(0)->nodeValue; + $relocate['request'] = $xpath->query('dfrn:request/text()', $relocation)->item(0)->nodeValue; + $relocate['confirm'] = $xpath->query('dfrn:confirm/text()', $relocation)->item(0)->nodeValue; + $relocate['notify'] = $xpath->query('dfrn:notify/text()', $relocation)->item(0)->nodeValue; + $relocate['poll'] = $xpath->query('dfrn:poll/text()', $relocation)->item(0)->nodeValue; + $relocate['sitepubkey'] = $xpath->query('dfrn:sitepubkey/text()', $relocation)->item(0)->nodeValue; - if (($relocate["avatar"] == "") && ($relocate["photo"] != "")) { - $relocate["avatar"] = $relocate["photo"]; + if (($relocate['avatar'] == '') && ($relocate['photo'] != '')) { + $relocate['avatar'] = $relocate['photo']; } - if ($relocate["addr"] == "") { - $relocate["addr"] = preg_replace("=(https?://)(.*)/profile/(.*)=ism", "$3@$2", $relocate["url"]); + if ($relocate['addr'] == '') { + $relocate['addr'] = preg_replace("=(https?://)(.*)/profile/(.*)=ism", '$3@$2', $relocate['url']); } // update contact - $old = Contact::selectFirst(['photo', 'url'], ['id' => $importer["id"], 'uid' => $importer["importer_uid"]]); + $old = Contact::selectFirst(['photo', 'url'], ['id' => $importer['id'], 'uid' => $importer['importer_uid']]); if (!DBA::isResult($old)) { Logger::notice("Query failed to execute, no result returned in " . __FUNCTION__); @@ -1478,16 +1488,23 @@ class DFRN } // Update the contact table. We try to find every entry. - $fields = ['name' => $relocate["name"], 'avatar' => $relocate["avatar"], - 'url' => $relocate["url"], 'nurl' => Strings::normaliseLink($relocate["url"]), - 'addr' => $relocate["addr"], 'request' => $relocate["request"], - 'confirm' => $relocate["confirm"], 'notify' => $relocate["notify"], - 'poll' => $relocate["poll"], 'site-pubkey' => $relocate["sitepubkey"]]; - $condition = ["(`id` = ?) OR (`nurl` = ?)", $importer["id"], Strings::normaliseLink($old["url"])]; + $fields = [ + 'name' => $relocate['name'], + 'avatar' => $relocate['avatar'], + 'url' => $relocate['url'], + 'nurl' => Strings::normaliseLink($relocate['url']), + 'addr' => $relocate['addr'], + 'request' => $relocate['request'], + 'confirm' => $relocate['confirm'], + 'notify' => $relocate['notify'], + 'poll' => $relocate['poll'], + 'site-pubkey' => $relocate['sitepubkey'], + ]; + $condition = ["(`id` = ?) OR (`nurl` = ?)", $importer['id'], Strings::normaliseLink($old['url'])]; Contact::update($fields, $condition); - Contact::updateAvatar($importer["id"], $relocate["avatar"], true); + Contact::updateAvatar($importer['id'], $relocate['avatar'], true); Logger::notice('Contacts are updated.'); @@ -1510,21 +1527,24 @@ class DFRN * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @todo set proper type-hints (array?) */ - private static function updateContent($current, $item, $importer, $entrytype) + private static function updateContent(array $current, array $item, array $importer, int $entrytype) { $changed = false; if (self::isEditedTimestampNewer($current, $item)) { // do not accept (ignore) an earlier edit than one we currently have. - if (DateTimeFormat::utc($item["edited"]) < $current["edited"]) { + if (DateTimeFormat::utc($item['edited']) < $current['edited']) { return false; } - $fields = ['title' => $item['title'] ?? '', 'body' => $item['body'] ?? '', - 'changed' => DateTimeFormat::utcNow(), - 'edited' => DateTimeFormat::utc($item["edited"])]; + $fields = [ + 'title' => $item['title'] ?? '', + 'body' => $item['body'] ?? '', + 'changed' => DateTimeFormat::utcNow(), + 'edited' => DateTimeFormat::utc($item['edited']), + ]; - $condition = ["`uri` = ? AND `uid` IN (0, ?)", $item["uri"], $importer["importer_uid"]]; + $condition = ["`uri` = ? AND `uid` IN (0, ?)", $item['uri'], $importer['importer_uid']]; Item::update($fields, $condition); $changed = true; @@ -1542,13 +1562,13 @@ class DFRN * @throws \Exception * @todo set proper type-hints (array?) */ - private static function getEntryType($importer, $item) + private static function getEntryType(array $importer, array $item): int { - if ($item["thr-parent"] != $item["uri"]) { + if ($item['thr-parent'] != $item['uri']) { $community = false; if ($importer['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) { - $sql_extra = ""; + $sql_extra = ''; $community = true; Logger::notice("possible community action"); } else { @@ -1558,7 +1578,7 @@ class DFRN // was the top-level post for this action written by somebody on this site? // Specifically, the recipient? $parent = Post::selectFirst(['wall'], - ["`uri` = ? AND `uid` = ?" . $sql_extra, $item["thr-parent"], $importer["importer_uid"]]); + ["`uri` = ? AND `uid` = ?" . $sql_extra, $item['thr-parent'], $importer['importer_uid']]); $is_a_remote_action = DBA::isResult($parent); @@ -1583,43 +1603,44 @@ class DFRN */ private static function doPoke(array $item, array $importer) { - $verb = urldecode(substr($item["verb"], strpos($item["verb"], "#")+1)); + $verb = urldecode(substr($item['verb'], strpos($item['verb'], '#')+1)); if (!$verb) { return; } - $xo = XML::parseString($item["object"]); + $xo = XML::parseString($item['object']); if (($xo->type == Activity\ObjectType::PERSON) && ($xo->id)) { // somebody was poked/prodded. Was it me? $Blink = ''; foreach ($xo->link as $l) { $atts = $l->attributes(); - switch ($atts["rel"]) { - case "alternate": - $Blink = $atts["href"]; + switch ($atts['rel']) { + case 'alternate': + $Blink = $atts['href']; break; + default: break; } } - if ($Blink && Strings::compareLink($Blink, DI::baseUrl() . "/profile/" . $importer["nickname"])) { + if ($Blink && Strings::compareLink($Blink, DI::baseUrl() . '/profile/' . $importer['nickname'])) { $author = DBA::selectFirst('contact', ['id', 'name', 'thumb', 'url'], ['id' => $item['author-id']]); - $parent = Post::selectFirst(['id'], ['uri' => $item['thr-parent'], 'uid' => $importer["importer_uid"]]); + $parent = Post::selectFirst(['id'], ['uri' => $item['thr-parent'], 'uid' => $importer['importer_uid']]); $item['parent'] = $parent['id']; // send a notification DI::notify()->createFromArray( [ - "type" => Notification\Type::POKE, - "otype" => Notification\ObjectType::PERSON, - "activity" => $verb, - "verb" => $item["verb"], - "uid" => $importer["importer_uid"], - "cid" => $author["id"], - "item" => $item, - "link" => DI::baseUrl() . "/display/" . urlencode($item['guid']), + 'type' => Notification\Type::POKE, + 'otype' => Notification\ObjectType::PERSON, + 'activity' => $verb, + 'verb' => $item['verb'], + 'uid' => $importer['importer_uid'], + 'cid' => $author['id'], + 'item' => $item, + 'link' => DI::baseUrl() . '/display/' . urlencode($item['guid']), ] ); } @@ -1636,11 +1657,10 @@ class DFRN * * @return bool Should the processing of the entries be continued? * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @todo set proper type-hints (array?) */ - private static function processVerbs($entrytype, $importer, &$item, &$is_like) + private static function processVerbs(int $entrytype, array $importer, array &$item, bool &$is_like) { - Logger::info("Process verb ".$item["verb"]." and object-type ".$item["object-type"]." for entrytype ".$entrytype); + Logger::info('Process verb ' . $item['verb'] . ' and object-type ' . $item['object-type'] . ' for entrytype ' . $entrytype); if (($entrytype == DFRN::TOP_LEVEL) && !empty($importer['id'])) { // The filling of the the "contact" variable is done for legcy reasons @@ -1651,65 +1671,70 @@ class DFRN // Big question: Do we need these functions? They were part of the "consume_feed" function. // This function once was responsible for DFRN and OStatus. - if ($activity->match($item["verb"], Activity::FOLLOW)) { + if ($activity->match($item['verb'], Activity::FOLLOW)) { Logger::notice("New follower"); Contact::addRelationship($importer, $contact, $item); return false; } - if ($activity->match($item["verb"], Activity::UNFOLLOW)) { + if ($activity->match($item['verb'], Activity::UNFOLLOW)) { Logger::notice("Lost follower"); Contact::removeFollower($contact); return false; } - if ($activity->match($item["verb"], Activity::REQ_FRIEND)) { + if ($activity->match($item['verb'], Activity::REQ_FRIEND)) { Logger::notice("New friend request"); Contact::addRelationship($importer, $contact, $item, true); return false; } - if ($activity->match($item["verb"], Activity::UNFRIEND)) { + if ($activity->match($item['verb'], Activity::UNFRIEND)) { Logger::notice("Lost sharer"); Contact::removeSharer($contact); return false; } } else { - if (($item["verb"] == Activity::LIKE) - || ($item["verb"] == Activity::DISLIKE) - || ($item["verb"] == Activity::ATTEND) - || ($item["verb"] == Activity::ATTENDNO) - || ($item["verb"] == Activity::ATTENDMAYBE) - || ($item["verb"] == Activity::ANNOUNCE) + if (($item['verb'] == Activity::LIKE) + || ($item['verb'] == Activity::DISLIKE) + || ($item['verb'] == Activity::ATTEND) + || ($item['verb'] == Activity::ATTENDNO) + || ($item['verb'] == Activity::ATTENDMAYBE) + || ($item['verb'] == Activity::ANNOUNCE) ) { $is_like = true; - $item["gravity"] = GRAVITY_ACTIVITY; + $item['gravity'] = GRAVITY_ACTIVITY; // only one like or dislike per person // split into two queries for performance issues - $condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"], 'gravity' => GRAVITY_ACTIVITY, - 'verb' => $item['verb'], 'parent-uri' => $item['thr-parent']]; + $condition = [ + 'uid' => $item['uid'], + 'author-id' => $item['author-id'], + 'gravity' => GRAVITY_ACTIVITY, + 'verb' => $item['verb'], + 'parent-uri' => $item['thr-parent'], + ]; if (Post::exists($condition)) { return false; } - $condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"], 'gravity' => GRAVITY_ACTIVITY, + $condition = ['uid' => $item['uid'], 'author-id' => $item['author-id'], 'gravity' => GRAVITY_ACTIVITY, 'verb' => $item['verb'], 'thr-parent' => $item['thr-parent']]; if (Post::exists($condition)) { return false; } // The owner of an activity must be the author - $item["owner-name"] = $item["author-name"]; - $item["owner-link"] = $item["author-link"]; - $item["owner-avatar"] = $item["author-avatar"]; - $item["owner-id"] = $item["author-id"]; + $item['owner-name'] = $item['author-name']; + $item['owner-link'] = $item['author-link']; + $item['owner-avatar'] = $item['author-avatar']; + $item['owner-id'] = $item['author-id']; } else { $is_like = false; } - if (($item["verb"] == Activity::TAG) && ($item["object-type"] == Activity\ObjectType::TAGTERM)) { - $xo = XML::parseString($item["object"]); - $xt = XML::parseString($item["target"]); + if (($item['verb'] == Activity::TAG) && ($item['object-type'] == Activity\ObjectType::TAGTERM)) { + $xo = XML::parseString($item['object']); + $xt = XML::parseString($item['target']); if ($xt->type == Activity\ObjectType::NOTE) { - $item_tag = Post::selectFirst(['id', 'uri-id'], ['uri' => $xt->id, 'uid' => $importer["importer_uid"]]); + $item_tag = Post::selectFirst(['id', 'uri-id'], ['uri' => $xt->id, 'uid' => $importer['importer_uid']]); if (!DBA::isResult($item_tag)) { Logger::notice("Query failed to execute, no result returned in " . __FUNCTION__); @@ -1734,29 +1759,30 @@ class DFRN * @return void * @todo set proper type-hints */ - private static function parseLinks($links, &$item) + private static function parseLinks($links, array &$item) { - $rel = ""; - $href = ""; + $rel = ''; + $href = ''; $type = null; $length = null; $title = null; foreach ($links as $link) { foreach ($link->attributes as $attributes) { switch ($attributes->name) { - case "href" : $href = $attributes->textContent; break; - case "rel" : $rel = $attributes->textContent; break; - case "type" : $type = $attributes->textContent; break; - case "length": $length = $attributes->textContent; break; - case "title" : $title = $attributes->textContent; break; + case 'href' : $href = $attributes->textContent; break; + case 'rel' : $rel = $attributes->textContent; break; + case 'type' : $type = $attributes->textContent; break; + case 'length': $length = $attributes->textContent; break; + case 'title' : $title = $attributes->textContent; break; } } - if (($rel != "") && ($href != "")) { + if (($rel != '') && ($href != '')) { switch ($rel) { - case "alternate": - $item["plink"] = $href; + case 'alternate': + $item['plink'] = $href; break; - case "enclosure": + + case 'enclosure': Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::DOCUMENT, 'url' => $href, 'mimetype' => $type, 'size' => $length, 'description' => $title]); break; @@ -1772,7 +1798,7 @@ class DFRN * @param array $imporer * @return boolean Is the message wanted? */ - private static function isSolicitedMessage(array $item, array $importer) + private static function isSolicitedMessage(array $item, array $importer): bool { if (DBA::exists('contact', ["`nurl` = ? AND `uid` != ? AND `rel` IN (?, ?)", Strings::normaliseLink($item["author-link"]), 0, Contact::FRIEND, Contact::SHARING])) { @@ -1802,161 +1828,159 @@ class DFRN /** * Processes the entry elements which contain the items and comments * - * @param array $header Array of the header elements that always stay the same - * @param object $xpath XPath object - * @param object $entry entry elements - * @param array $importer Record of the importer user mixed with contact of the content - * @param string $xml xml + * @param array $header Array of the header elements that always stay the same + * @param DOMXPath $xpath XPath object + * @param DOMNode $entry entry elements + * @param array $importer Record of the importer user mixed with contact of the content + * @param string $xml XML + * @param int $protocol Protocol * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException * @todo Add type-hints */ - private static function processEntry($header, $xpath, $entry, $importer, $xml, $protocol) + private static function processEntry(array $header, DOMXPath $xpath, DOMNode $entry, array $importer, string $xml, int $protocol) { Logger::notice("Processing entries"); $item = $header; - $item["protocol"] = $protocol; + $item['protocol'] = $protocol; - $item["source"] = $xml; + $item['source'] = $xml; // Get the uri - $item["uri"] = XML::getFirstNodeValue($xpath, "atom:id/text()", $entry); + $item['uri'] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry); - $item["edited"] = XML::getFirstNodeValue($xpath, "atom:updated/text()", $entry); + $item['edited'] = XML::getFirstNodeValue($xpath, 'atom:updated/text()', $entry); $current = Post::selectFirst(['id', 'uid', 'edited', 'body'], - ['uri' => $item["uri"], 'uid' => $importer["importer_uid"]] + ['uri' => $item['uri'], 'uid' => $importer['importer_uid']] ); // Is there an existing item? if (DBA::isResult($current) && !self::isEditedTimestampNewer($current, $item)) { - Logger::info("Item ".$item["uri"]." (".$item['edited'].") already existed."); + Logger::info("Item " . $item['uri'] . " (" . $item['edited'] . ") already existed."); return; } // Fetch the owner - $owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true, $xml); + $owner = self::fetchauthor($xpath, $entry, $importer, 'dfrn:owner', true, $xml); - $owner_unknown = (isset($owner["contact-unknown"]) && $owner["contact-unknown"]); + $owner_unknown = (isset($owner['contact-unknown']) && $owner['contact-unknown']); - $item["owner-name"] = $owner["name"]; - $item["owner-link"] = $owner["link"]; - $item["owner-avatar"] = $owner["avatar"]; - $item["owner-id"] = Contact::getIdForURL($owner["link"], 0); + $item['owner-name'] = $owner['name']; + $item['owner-link'] = $owner['link']; + $item['owner-avatar'] = $owner['avatar']; + $item['owner-id'] = Contact::getIdForURL($owner['link'], 0); // fetch the author - $author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true, $xml); + $author = self::fetchauthor($xpath, $entry, $importer, 'atom:author', true, $xml); - $item["author-name"] = $author["name"]; - $item["author-link"] = $author["link"]; - $item["author-avatar"] = $author["avatar"]; - $item["author-id"] = Contact::getIdForURL($author["link"], 0); + $item['author-name'] = $author['name']; + $item['author-link'] = $author['link']; + $item['author-avatar'] = $author['avatar']; + $item['author-id'] = Contact::getIdForURL($author['link'], 0); - $item["title"] = XML::getFirstNodeValue($xpath, "atom:title/text()", $entry); + $item['title'] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); - if (!empty($item["title"])) { - $item["post-type"] = Item::PT_ARTICLE; + if (!empty($item['title'])) { + $item['post-type'] = Item::PT_ARTICLE; } else { - $item["post-type"] = Item::PT_NOTE; + $item['post-type'] = Item::PT_NOTE; } - $item["created"] = XML::getFirstNodeValue($xpath, "atom:published/text()", $entry); + $item['created'] = XML::getFirstNodeValue($xpath, 'atom:published/text()', $entry); - $item["body"] = XML::getFirstNodeValue($xpath, "dfrn:env/text()", $entry); - $item["body"] = str_replace([' ',"\t","\r","\n"], ['','','',''], $item["body"]); + $item['body'] = XML::getFirstNodeValue($xpath, 'dfrn:env/text()', $entry); + $item['body'] = str_replace([' ',"\t","\r","\n"], ['','','',''], $item['body']); - $item["body"] = Strings::base64UrlDecode($item["body"]); + $item['body'] = Strings::base64UrlDecode($item['body']); - $item["body"] = BBCode::limitBodySize($item["body"]); + $item['body'] = BBCode::limitBodySize($item['body']); /// @todo We should check for a repeated post and if we know the repeated author. // We don't need the content element since "dfrn:env" is always present - //$item["body"] = $xpath->query("atom:content/text()", $entry)->item(0)->nodeValue; + //$item['body'] = $xpath->query('atom:content/text()', $entry)->item(0)->nodeValue; + $item['location'] = XML::getFirstNodeValue($xpath, 'dfrn:location/text()', $entry); + $item['coord'] = XML::getFirstNodeValue($xpath, 'georss:point', $entry); + $item['private'] = XML::getFirstNodeValue($xpath, 'dfrn:private/text()', $entry); - $item["location"] = XML::getFirstNodeValue($xpath, "dfrn:location/text()", $entry); - - $item["coord"] = XML::getFirstNodeValue($xpath, "georss:point", $entry); - - $item["private"] = XML::getFirstNodeValue($xpath, "dfrn:private/text()", $entry); - - $unlisted = XML::getFirstNodeValue($xpath, "dfrn:unlisted/text()", $entry); + $unlisted = XML::getFirstNodeValue($xpath, 'dfrn:unlisted/text()', $entry); if (!empty($unlisted) && ($item['private'] != Item::PRIVATE)) { $item['private'] = Item::UNLISTED; } - $item["extid"] = XML::getFirstNodeValue($xpath, "dfrn:extid/text()", $entry); + $item['extid'] = XML::getFirstNodeValue($xpath, 'dfrn:extid/text()', $entry); - if (XML::getFirstNodeValue($xpath, "dfrn:bookmark/text()", $entry) == "true") { - $item["post-type"] = Item::PT_PAGE; + if (XML::getFirstNodeValue($xpath, 'dfrn:bookmark/text()', $entry) == 'true') { + $item['post-type'] = Item::PT_PAGE; } - $notice_info = $xpath->query("statusnet:notice_info", $entry); + $notice_info = $xpath->query('statusnet:notice_info', $entry); if ($notice_info && ($notice_info->length > 0)) { foreach ($notice_info->item(0)->attributes as $attributes) { - if ($attributes->name == "source") { - $item["app"] = strip_tags($attributes->textContent); + if ($attributes->name == 'source') { + $item['app'] = strip_tags($attributes->textContent); } } } - $item["guid"] = XML::getFirstNodeValue($xpath, "dfrn:diaspora_guid/text()", $entry); + $item['guid'] = XML::getFirstNodeValue($xpath, 'dfrn:diaspora_guid/text()', $entry); $item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]); - $item["body"] = Item::improveSharedDataInBody($item); + $item['body'] = Item::improveSharedDataInBody($item); - Tag::storeFromBody($item['uri-id'], $item["body"]); + Tag::storeFromBody($item['uri-id'], $item['body']); // We store the data from "dfrn:diaspora_signature" in a different table, this is done in "Item::insert" - $dsprsig = XML::unescape(XML::getFirstNodeValue($xpath, "dfrn:diaspora_signature/text()", $entry)); - if ($dsprsig != "") { + $dsprsig = XML::unescape(XML::getFirstNodeValue($xpath, 'dfrn:diaspora_signature/text()', $entry)); + if ($dsprsig != '') { $signature = json_decode(base64_decode($dsprsig)); // We don't store the old style signatures anymore that also contained the "signature" and "signer" if (!empty($signature->signed_text) && empty($signature->signature) && empty($signature->signer)) { - $item["diaspora_signed_text"] = $signature->signed_text; + $item['diaspora_signed_text'] = $signature->signed_text; } } - $item["verb"] = XML::getFirstNodeValue($xpath, "activity:verb/text()", $entry); + $item['verb'] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $entry); - if (XML::getFirstNodeValue($xpath, "activity:object-type/text()", $entry) != "") { - $item["object-type"] = XML::getFirstNodeValue($xpath, "activity:object-type/text()", $entry); + if (XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $entry) != '') { + $item['object-type'] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $entry); } - $object = $xpath->query("activity:object", $entry)->item(0); - $item["object"] = self::transformActivity($xpath, $object, "object"); + $object = $xpath->query('activity:object', $entry)->item(0); + $item['object'] = self::transformActivity($xpath, $object, 'object'); - if (trim($item["object"]) != "") { - $r = XML::parseString($item["object"]); + if (trim($item['object']) != '') { + $r = XML::parseString($item['object']); if (isset($r->type)) { - $item["object-type"] = $r->type; + $item['object-type'] = $r->type; } } - $target = $xpath->query("activity:target", $entry)->item(0); - $item["target"] = self::transformActivity($xpath, $target, "target"); + $target = $xpath->query('activity:target', $entry)->item(0); + $item['target'] = self::transformActivity($xpath, $target, 'target'); - $categories = $xpath->query("atom:category", $entry); + $categories = $xpath->query('atom:category', $entry); if ($categories) { foreach ($categories as $category) { - $term = ""; - $scheme = ""; + $term = ''; + $scheme = ''; foreach ($category->attributes as $attributes) { - if ($attributes->name == "term") { + if ($attributes->name == 'term') { $term = $attributes->textContent; } - if ($attributes->name == "scheme") { + if ($attributes->name == 'scheme') { $scheme = $attributes->textContent; } } - if (($term != "") && ($scheme != "")) { - $parts = explode(":", $scheme); - if ((count($parts) >= 4) && (array_shift($parts) == "X-DFRN")) { + if (($term != '') && ($scheme != '')) { + $parts = explode(':', $scheme); + if ((count($parts) >= 4) && (array_shift($parts) == 'X-DFRN')) { $termurl = array_pop($parts); $termurl = array_pop($parts) . ':' . $termurl; Tag::store($item['uri-id'], Tag::IMPLICIT_MENTION, $term, $termurl); @@ -1965,7 +1989,7 @@ class DFRN } } - $links = $xpath->query("atom:link", $entry); + $links = $xpath->query('atom:link', $entry); if ($links) { self::parseLinks($links, $item); } @@ -1975,10 +1999,10 @@ class DFRN $conv = $xpath->query('ostatus:conversation', $entry); if (is_object($conv->item(0))) { foreach ($conv->item(0)->attributes as $attributes) { - if ($attributes->name == "ref") { + if ($attributes->name == 'ref') { $item['conversation-uri'] = $attributes->textContent; } - if ($attributes->name == "href") { + if ($attributes->name == 'href') { $item['conversation-href'] = $attributes->textContent; } } @@ -1987,10 +2011,10 @@ class DFRN // Is it a reply or a top level posting? $item['thr-parent'] = $item['uri']; - $inreplyto = $xpath->query("thr:in-reply-to", $entry); + $inreplyto = $xpath->query('thr:in-reply-to', $entry); if (is_object($inreplyto->item(0))) { foreach ($inreplyto->item(0)->attributes as $attributes) { - if ($attributes->name == "ref") { + if ($attributes->name == 'ref') { $item['thr-parent'] = $attributes->textContent; } } @@ -2007,24 +2031,24 @@ class DFRN // Now assign the rest of the values that depend on the type of the message if (in_array($entrytype, [DFRN::REPLY, DFRN::REPLY_RC])) { - if (!isset($item["object-type"])) { - $item["object-type"] = Activity\ObjectType::COMMENT; + if (!isset($item['object-type'])) { + $item['object-type'] = Activity\ObjectType::COMMENT; } - if ($item["contact-id"] != $owner["contact-id"]) { - $item["contact-id"] = $owner["contact-id"]; + if ($item['contact-id'] != $owner['contact-id']) { + $item['contact-id'] = $owner['contact-id']; } - if (($item["network"] != $owner["network"]) && ($owner["network"] != "")) { - $item["network"] = $owner["network"]; + if (($item['network'] != $owner['network']) && ($owner['network'] != '')) { + $item['network'] = $owner['network']; } - if ($item["contact-id"] != $author["contact-id"]) { - $item["contact-id"] = $author["contact-id"]; + if ($item['contact-id'] != $author['contact-id']) { + $item['contact-id'] = $author['contact-id']; } - if (($item["network"] != $author["network"]) && ($author["network"] != "")) { - $item["network"] = $author["network"]; + if (($item['network'] != $author['network']) && ($author['network'] != '')) { + $item['network'] = $author['network']; } } @@ -2032,34 +2056,34 @@ class DFRN $item = Item::addShareDataFromOriginal($item); if ($entrytype == DFRN::REPLY_RC) { - $item["wall"] = 1; + $item['wall'] = 1; } elseif ($entrytype == DFRN::TOP_LEVEL) { - if (!isset($item["object-type"])) { - $item["object-type"] = Activity\ObjectType::NOTE; + if (!isset($item['object-type'])) { + $item['object-type'] = Activity\ObjectType::NOTE; } // Is it an event? - if (($item["object-type"] == Activity\ObjectType::EVENT) && !$owner_unknown) { - Logger::info("Item ".$item["uri"]." seems to contain an event."); - $ev = Event::fromBBCode($item["body"]); + if (($item['object-type'] == Activity\ObjectType::EVENT) && !$owner_unknown) { + Logger::info("Item " . $item['uri'] . " seems to contain an event."); + $ev = Event::fromBBCode($item['body']); if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) { - Logger::info("Event in item ".$item["uri"]." was found."); - $ev["cid"] = $importer["id"]; - $ev["uid"] = $importer["importer_uid"]; - $ev["uri"] = $item["uri"]; - $ev["edited"] = $item["edited"]; - $ev["private"] = $item["private"]; - $ev["guid"] = $item["guid"]; - $ev["plink"] = $item["plink"]; - $ev["network"] = $item["network"]; - $ev["protocol"] = $item["protocol"]; - $ev["direction"] = $item["direction"]; - $ev["source"] = $item["source"]; + Logger::info("Event in item " . $item['uri'] . " was found."); + $ev['cid'] = $importer['id']; + $ev['uid'] = $importer['importer_uid']; + $ev['uri'] = $item['uri']; + $ev['edited'] = $item['edited']; + $ev['private'] = $item['private']; + $ev['guid'] = $item['guid']; + $ev['plink'] = $item['plink']; + $ev['network'] = $item['network']; + $ev['protocol'] = $item['protocol']; + $ev['direction'] = $item['direction']; + $ev['source'] = $item['source']; - $condition = ['uri' => $item["uri"], 'uid' => $importer["importer_uid"]]; + $condition = ['uri' => $item['uri'], 'uid' => $importer['importer_uid']]; $event = DBA::selectFirst('event', ['id'], $condition); if (DBA::isResult($event)) { - $ev["id"] = $event["id"]; + $ev['id'] = $event['id']; } $event_id = Event::store($ev); @@ -2070,6 +2094,9 @@ class DFRN } } + // Need to initialize variable, otherwise E_NOTICE will happen + $is_like = false; + if (!self::processVerbs($entrytype, $importer, $item, $is_like)) { Logger::info("Exiting because 'processVerbs' told us so"); return; @@ -2077,7 +2104,7 @@ class DFRN // This check is done here to be able to receive connection requests in "processVerbs" if (($entrytype == DFRN::TOP_LEVEL) && $owner_unknown) { - Logger::info("Item won't be stored because user " . $importer["importer_uid"] . " doesn't follow " . $item["owner-link"] . "."); + Logger::info("Item won't be stored because user " . $importer['importer_uid'] . " doesn't follow " . $item['owner-link'] . "."); return; } @@ -2085,9 +2112,9 @@ class DFRN // Update content if 'updated' changes if (DBA::isResult($current)) { if (self::updateContent($current, $item, $importer, $entrytype)) { - Logger::info("Item ".$item["uri"]." was updated."); + Logger::info("Item " . $item['uri'] . " was updated."); } else { - Logger::info("Item " . $item["uri"] . " already existed."); + Logger::info("Item " . $item['uri'] . " already existed."); } return; } @@ -2100,7 +2127,7 @@ class DFRN $posted_id = Item::insert($item); if ($posted_id) { - Logger::info("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id); + Logger::info("Reply from contact " . $item['contact-id'] . " was stored with id " . $posted_id); if ($item['uid'] == 0) { Item::distribute($posted_id); @@ -2109,11 +2136,11 @@ class DFRN return true; } } else { // $entrytype == DFRN::TOP_LEVEL - if (($importer["uid"] == 0) && ($importer["importer_uid"] != 0)) { - Logger::info("Contact ".$importer["id"]." isn't known to user ".$importer["importer_uid"].". The post will be ignored."); + if (($importer['uid'] == 0) && ($importer['importer_uid'] != 0)) { + Logger::info("Contact " . $importer['id'] . " isn't known to user " . $importer['importer_uid'] . ". The post will be ignored."); return; } - if (!Strings::compareLink($item["owner-link"], $importer["url"])) { + if (!Strings::compareLink($item['owner-link'], $importer['url'])) { /* * The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, * but otherwise there's a possible data mixup on the sender's system. @@ -2121,12 +2148,12 @@ class DFRN * but we're going to unconditionally correct it here so that the post will always be owned by our contact. */ Logger::info('Correcting item owner.'); - $item["owner-link"] = $importer["url"]; - $item["owner-id"] = Contact::getIdForURL($importer["url"], 0); + $item['owner-link'] = $importer['url']; + $item['owner-id'] = Contact::getIdForURL($importer['url'], 0); } - if (($importer["rel"] == Contact::FOLLOWER) && (!self::tgroupCheck($importer["importer_uid"], $item))) { - Logger::info("Contact ".$importer["id"]." is only follower and tgroup check was negative."); + if (($importer['rel'] == Contact::FOLLOWER) && (!self::tgroupCheck($importer['importer_uid'], $item))) { + Logger::info("Contact " . $importer['id'] . " is only follower and tgroup check was negative."); return; } @@ -2140,13 +2167,13 @@ class DFRN $posted_id = $notify; } - Logger::info("Item was stored with id ".$posted_id); + Logger::info("Item was stored with id " . $posted_id); if ($item['uid'] == 0) { Item::distribute($posted_id); } - if (stristr($item["verb"], Activity::POKE)) { + if (stristr($item['verb'], Activity::POKE)) { $item['id'] = $posted_id; self::doPoke($item, $importer); } @@ -2156,56 +2183,55 @@ class DFRN /** * Deletes items * - * @param object $xpath XPath object - * @param object $deletion deletion elements - * @param array $importer Record of the importer user mixed with contact of the content + * @param DOMXPath $xpath XPath object + * @param DOMNode $deletion deletion elements + * @param array $importer Record of the importer user mixed with contact of the content * @return void * @throws \Exception - * @todo set proper type-hints */ - private static function processDeletion($xpath, $deletion, $importer) + private static function processDeletion(DOMXPath $xpath, DOMNode $deletion, array $importer) { Logger::notice("Processing deletions"); $uri = null; foreach ($deletion->attributes as $attributes) { - if ($attributes->name == "ref") { + if ($attributes->name == 'ref') { $uri = $attributes->textContent; } } - if (!$uri || !$importer["id"]) { + if (!$uri || !$importer['id']) { return false; } - $condition = ['uri' => $uri, 'uid' => $importer["importer_uid"]]; + $condition = ['uri' => $uri, 'uid' => $importer['importer_uid']]; $item = Post::selectFirst(['id', 'parent', 'contact-id', 'uri-id', 'deleted', 'gravity'], $condition); if (!DBA::isResult($item)) { - Logger::info("Item with uri " . $uri . " for user " . $importer["importer_uid"] . " wasn't found."); + Logger::info('Item with URI ' . $uri . ' for user ' . $importer['importer_uid'] . ' was not found.'); return; } if (DBA::exists('post-category', ['uri-id' => $item['uri-id'], 'uid' => $importer['importer_uid'], 'type' => Post\Category::FILE])) { - Logger::notice("Item is filed. It won't be deleted.", ['uri' => $uri, 'uri-id' => $item['uri_id'], 'uid' => $importer["importer_uid"]]); + Logger::notice('Item is filed. It will not be deleted.', ['uri' => $uri, 'uri-id' => $item['uri_id'], 'uid' => $importer['importer_uid']]); return; } // When it is a starting post it has to belong to the person that wants to delete it - if (($item['gravity'] == GRAVITY_PARENT) && ($item['contact-id'] != $importer["id"])) { - Logger::info("Item with uri " . $uri . " don't belong to contact " . $importer["id"] . " - ignoring deletion."); + if (($item['gravity'] == GRAVITY_PARENT) && ($item['contact-id'] != $importer['id'])) { + Logger::info('Item with URI ' . $uri . ' do not belong to contact ' . $importer['id'] . ' - ignoring deletion.'); return; } // Comments can be deleted by the thread owner or comment owner - if (($item['gravity'] != GRAVITY_PARENT) && ($item['contact-id'] != $importer["id"])) { - $condition = ['id' => $item['parent'], 'contact-id' => $importer["id"]]; + if (($item['gravity'] != GRAVITY_PARENT) && ($item['contact-id'] != $importer['id'])) { + $condition = ['id' => $item['parent'], 'contact-id' => $importer['id']]; if (!Post::exists($condition)) { - Logger::info("Item with uri " . $uri . " wasn't found or mustn't be deleted by contact " . $importer["id"] . " - ignoring deletion."); + Logger::info('Item with URI ' . $uri . ' was not found or must not be deleted by contact ' . $importer['id'] . ' - ignoring deletion.'); return; } } - if ($item["deleted"]) { + if ($item['deleted']) { return; } @@ -2224,11 +2250,10 @@ class DFRN * @return integer Import status * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException - * @todo set proper type-hints */ - public static function import($xml, $importer, $protocol, $direction) + public static function import(string $xml, array $importer, int $protocol, int $direction): int { - if ($xml == "") { + if ($xml == '') { return 400; } @@ -2236,24 +2261,24 @@ class DFRN @$doc->loadXML($xml); $xpath = new DOMXPath($doc); - $xpath->registerNamespace("atom", ActivityNamespace::ATOM1); - $xpath->registerNamespace("thr", ActivityNamespace::THREAD); - $xpath->registerNamespace("at", ActivityNamespace::TOMB); - $xpath->registerNamespace("media", ActivityNamespace::MEDIA); - $xpath->registerNamespace("dfrn", ActivityNamespace::DFRN); - $xpath->registerNamespace("activity", ActivityNamespace::ACTIVITY); - $xpath->registerNamespace("georss", ActivityNamespace::GEORSS); - $xpath->registerNamespace("poco", ActivityNamespace::POCO); - $xpath->registerNamespace("ostatus", ActivityNamespace::OSTATUS); - $xpath->registerNamespace("statusnet", ActivityNamespace::STATUSNET); + $xpath->registerNamespace('atom', ActivityNamespace::ATOM1); + $xpath->registerNamespace('thr', ActivityNamespace::THREAD); + $xpath->registerNamespace('at', ActivityNamespace::TOMB); + $xpath->registerNamespace('media', ActivityNamespace::MEDIA); + $xpath->registerNamespace('dfrn', ActivityNamespace::DFRN); + $xpath->registerNamespace('activity', ActivityNamespace::ACTIVITY); + $xpath->registerNamespace('georss', ActivityNamespace::GEORSS); + $xpath->registerNamespace('poco', ActivityNamespace::POCO); + $xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS); + $xpath->registerNamespace('statusnet', ActivityNamespace::STATUSNET); $header = []; - $header["uid"] = $importer["importer_uid"]; - $header["network"] = Protocol::DFRN; - $header["wall"] = 0; - $header["origin"] = 0; - $header["contact-id"] = $importer["id"]; - $header["direction"] = $direction; + $header['uid'] = $importer['importer_uid']; + $header['network'] = Protocol::DFRN; + $header['wall'] = 0; + $header['origin'] = 0; + $header['contact-id'] = $importer['id']; + $header['direction'] = $direction; if ($direction === Conversation::RELAY) { $header['post-reason'] = Item::PR_RELAY; @@ -2262,31 +2287,31 @@ class DFRN // Update the contact table if the data has changed // The "atom:author" is only present in feeds - if ($xpath->query("/atom:feed/atom:author")->length > 0) { - self::fetchauthor($xpath, $doc->firstChild, $importer, "atom:author", false, $xml); + if ($xpath->query('/atom:feed/atom:author')->length > 0) { + self::fetchauthor($xpath, $doc->firstChild, $importer, 'atom:author', false, $xml); } // Only the "dfrn:owner" in the head section contains all data - if ($xpath->query("/atom:feed/dfrn:owner")->length > 0) { - self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", false, $xml); + if ($xpath->query('/atom:feed/dfrn:owner')->length > 0) { + self::fetchauthor($xpath, $doc->firstChild, $importer, 'dfrn:owner', false, $xml); } - Logger::info("Import DFRN message for user " . $importer["importer_uid"] . " from contact " . $importer["id"]); + Logger::info("Import DFRN message for user " . $importer['importer_uid'] . " from contact " . $importer['id']); if (!empty($importer['gsid']) && ($protocol == Conversation::PARCEL_DIASPORA_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()")); + $forum = 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) { + if ($xpath->query('/atom:feed/dfrn:account_type')->length > 0) { // Hint: We are using separate update calls for uid=0 and uid!=0 since a combined call is bad for the database performance - $accounttype = intval(XML::getFirstNodeValue($xpath, "/atom:feed/dfrn:account_type/text()")); + $accounttype = intval(XML::getFirstNodeValue($xpath, '/atom:feed/dfrn:account_type/text()')); - if ($accounttype != $importer["contact-type"]) { + if ($accounttype != $importer['contact-type']) { Contact::update(['contact-type' => $accounttype], ['id' => $importer['id']]); // Updating the public contact as well @@ -2310,8 +2335,8 @@ 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"]]; + } elseif ($forum != $importer['forum']) { // Deprecated since 3.5.1 + $condition = ['`forum` != ? AND `id` = ?', $forum, $importer['id']]; Contact::update(['forum' => $forum], $condition); // Updating the public contact as well @@ -2321,40 +2346,40 @@ class DFRN // We are processing relocations even if we are ignoring a contact - $relocations = $xpath->query("/atom:feed/dfrn:relocate"); + $relocations = $xpath->query('/atom:feed/dfrn:relocate'); foreach ($relocations as $relocation) { self::processRelocation($xpath, $relocation, $importer); } - if (($importer["uid"] != 0) && !$importer["readonly"]) { - $mails = $xpath->query("/atom:feed/dfrn:mail"); + if (($importer['uid'] != 0) && !$importer['readonly']) { + $mails = $xpath->query('/atom:feed/dfrn:mail'); foreach ($mails as $mail) { self::processMail($xpath, $mail, $importer); } - $suggestions = $xpath->query("/atom:feed/dfrn:suggest"); + $suggestions = $xpath->query('/atom:feed/dfrn:suggest'); foreach ($suggestions as $suggestion) { self::processSuggestion($xpath, $suggestion, $importer); } } - $deletions = $xpath->query("/atom:feed/at:deleted-entry"); + $deletions = $xpath->query('/atom:feed/at:deleted-entry'); if (!empty($deletions)) { foreach ($deletions as $deletion) { self::processDeletion($xpath, $deletion, $importer); } if (count($deletions) > 0) { - Logger::notice('Deletions had been processed'); + Logger::notice(count($deletions) . ' deletions had been processed'); return 200; } } - $entries = $xpath->query("/atom:feed/atom:entry"); + $entries = $xpath->query('/atom:feed/atom:entry'); foreach ($entries as $entry) { self::processEntry($header, $xpath, $entry, $importer, $xml, $protocol); } - Logger::info("Import done for user " . $importer["importer_uid"] . " from contact " . $importer["id"]); + Logger::info("Import done for user " . $importer['importer_uid'] . " from contact " . $importer['id']); return 200; } @@ -2365,7 +2390,7 @@ class DFRN * * @return string activity verb */ - private static function constructVerb(array $item) + private static function constructVerb(array $item): string { if ($item['verb']) { return $item['verb']; @@ -2373,7 +2398,8 @@ class DFRN return Activity::POST; } - private static function tgroupCheck($uid, $item) + // @TODO Documentation missing + private static function tgroupCheck(int $uid, array $item): bool { $mention = false; @@ -2421,12 +2447,12 @@ class DFRN * item is assumed to be up-to-date. If the timestamps are equal it * assumes the update has been seen before and should be ignored. * - * @param $existing - * @param $update + * @param array $existing + * @param array $update * @return bool * @throws \Exception */ - private static function isEditedTimestampNewer($existing, $update) + private static function isEditedTimestampNewer(array $existing, array $update): bool { if (empty($existing['edited'])) { return true; @@ -2449,7 +2475,7 @@ class DFRN * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isSupportedByContactUrl($url) + public static function isSupportedByContactUrl(string $url): bool { $probe = Probe::uri($url, Protocol::DFRN); return $probe['network'] == Protocol::DFRN; diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 70fd0f1f8d..838d405505 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -74,9 +74,9 @@ class Diaspora * @return array of relay servers * @throws \Exception */ - public static function participantsForThread(array $item, array $contacts) + public static function participantsForThread(array $item, array $contacts): array { - if (!in_array($item['private'], [Item::PUBLIC, Item::UNLISTED]) || in_array($item["verb"], [Activity::FOLLOW, Activity::TAG])) { + if (!in_array($item['private'], [Item::PUBLIC, Item::UNLISTED]) || in_array($item['verb'], [Activity::FOLLOW, Activity::TAG])) { Logger::info('Item is private or a participation request. It will not be relayed', ['guid' => $item['guid'], 'private' => $item['private'], 'verb' => $item['verb']]); return $contacts; } @@ -114,11 +114,11 @@ class Diaspora * * @param string $envelope The magic envelope * - * @return string verified data + * @return string|bool verified data or false on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function verifyMagicEnvelope($envelope) + private static function verifyMagicEnvelope(string $envelope) { $basedom = XML::parseString($envelope, true); @@ -145,14 +145,14 @@ class Diaspora $sig = Strings::base64UrlDecode($children->sig); $key_id = $children->sig->attributes()->key_id[0]; - if ($key_id != "") { + if ($key_id != '') { $handle = Strings::base64UrlDecode($key_id); } $b64url_data = Strings::base64UrlEncode($data); - $msg = str_replace(["\n", "\r", " ", "\t"], ["", "", "", ""], $b64url_data); + $msg = str_replace(["\n", "\r", " ", "\t"], ['', '', '', ''], $b64url_data); - $signable_data = $msg.".".Strings::base64UrlEncode($type).".".Strings::base64UrlEncode($encoding).".".Strings::base64UrlEncode($alg); + $signable_data = $msg . '.' . Strings::base64UrlEncode($type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($alg); if ($handle == '') { Logger::notice('No author could be decoded. Discarding. Message: ' . $envelope); @@ -183,7 +183,7 @@ class Diaspora * * @return string encrypted data */ - private static function aesEncrypt($key, $iv, $data) + private static function aesEncrypt(string $key, string $iv, string $data): string { return openssl_encrypt($data, 'aes-256-cbc', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0")); } @@ -197,19 +197,19 @@ class Diaspora * * @return string decrypted data */ - private static function aesDecrypt($key, $iv, $encrypted) + private static function aesDecrypt(string $key, string $iv, string $encrypted): string { return openssl_decrypt($encrypted, 'aes-256-cbc', str_pad($key, 32, "\0"), OPENSSL_RAW_DATA, str_pad($iv, 16, "\0")); } /** - * Decodes incoming Diaspora message in the new format + * Decodes incoming Diaspora message in the new format. This method returns false on an error. * * @param string $raw raw post message * @param string $privKey The private key of the importer * @param boolean $no_exit Don't do an http exit on error * - * @return array + * @return bool|array * 'message' -> decoded Diaspora XML message * 'author' -> author diaspora handle * 'key' -> author public key (converted to pkcs#8) @@ -260,13 +260,13 @@ class Diaspora $base = $basedom->children(ActivityNamespace::SALMON_ME); // Not sure if this cleaning is needed - $data = str_replace([" ", "\t", "\r", "\n"], ["", "", "", ""], $base->data); + $data = str_replace([" ", "\t", "\r", "\n"], ['', '', '', ''], $base->data); // Build the signed data $type = $base->data[0]->attributes()->type[0]; $encoding = $base->encoding; $alg = $base->alg; - $signed_data = $data.'.'.Strings::base64UrlEncode($type).'.'.Strings::base64UrlEncode($encoding).'.'.Strings::base64UrlEncode($alg); + $signed_data = $data . '.' . Strings::base64UrlEncode($type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($alg); // This is the signature $signature = Strings::base64UrlDecode($base->sig); @@ -303,9 +303,11 @@ class Diaspora } } - return ['message' => (string)Strings::base64UrlDecode($base->data), - 'author' => XML::unescape($author_addr), - 'key' => (string)$key]; + return [ + 'message' => (string)Strings::base64UrlDecode($base->data), + 'author' => XML::unescape($author_addr), + 'key' => (string)$key + ]; } /** @@ -394,7 +396,7 @@ class Diaspora // unpack the data // strip whitespace so our data element will return to one big base64 blob - $data = str_replace([" ", "\t", "\r", "\n"], ["", "", "", ""], $base->data); + $data = str_replace([" ", "\t", "\r", "\n"], ['', '', '', ''], $base->data); // stash away some other stuff for later @@ -445,9 +447,11 @@ class Diaspora Logger::notice('Message verified.'); - return ['message' => (string)$inner_decrypted, - 'author' => XML::unescape($author_link), - 'key' => (string)$key]; + return [ + 'message' => (string)$inner_decrypted, + 'author' => XML::unescape($author_link), + 'key' => (string)$key + ]; } @@ -457,11 +461,11 @@ class Diaspora * @param array $msg The post that will be dispatched * @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH) * - * @return int The message id of the generated message, "true" or "false" if there was an error + * @return int|bool The message id of the generated message, "true" or "false" if there was an error * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function dispatchPublic($msg, int $direction) + public static function dispatchPublic(array $msg, int $direction) { $enabled = intval(DI::config()->get("system", "diaspora_enabled")); if (!$enabled) { @@ -474,7 +478,10 @@ class Diaspora return false; } - $importer = ["uid" => 0, "page-flags" => User::PAGE_FLAGS_FREELOVE]; + $importer = [ + 'uid' => 0, + 'page-flags' => User::PAGE_FLAGS_FREELOVE + ]; $success = self::dispatch($importer, $msg, $fields, $direction); return $success; @@ -488,15 +495,15 @@ class Diaspora * @param SimpleXMLElement $fields SimpleXML object that contains the message * @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH) * - * @return int The message id of the generated message, "true" or "false" if there was an error + * @return int|bool The message id of the generated message, "true" or "false" if there was an error * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function dispatch(array $importer, $msg, SimpleXMLElement $fields = null, int $direction = self::PUSHED) + public static function dispatch(array $importer, array $msg, SimpleXMLElement $fields = null, int $direction = self::PUSHED) { // The sender is the handle of the contact that sent the message. // This will often be different with relayed messages (for example "like" and "comment") - $sender = $msg["author"]; + $sender = $msg['author']; // This is only needed for private postings since this is already done for public ones before if (is_null($fields)) { @@ -511,77 +518,77 @@ class Diaspora $type = $fields->getName(); - Logger::info('Received message', ['type' => $type, 'sender' => $sender, 'user' => $importer["uid"]]); + Logger::info('Received message', ['type' => $type, 'sender' => $sender, 'user' => $importer['uid']]); switch ($type) { - case "account_migration": + case 'account_migration': if (!$private) { Logger::notice('Message with type ' . $type . ' is not private, quitting.'); return false; } return self::receiveAccountMigration($importer, $fields); - case "account_deletion": + case 'account_deletion': return self::receiveAccountDeletion($fields); - case "comment": - return self::receiveComment($importer, $sender, $fields, $msg["message"], $direction); + case 'comment': + return self::receiveComment($importer, $sender, $fields, $msg['message'], $direction); - case "contact": + case 'contact': if (!$private) { Logger::notice('Message with type ' . $type . ' is not private, quitting.'); return false; } return self::receiveContactRequest($importer, $fields); - case "conversation": + case 'conversation': if (!$private) { Logger::notice('Message with type ' . $type . ' is not private, quitting.'); return false; } return self::receiveConversation($importer, $msg, $fields); - case "like": + case 'like': return self::receiveLike($importer, $sender, $fields, $direction); - case "message": + case 'message': if (!$private) { Logger::notice('Message with type ' . $type . ' is not private, quitting.'); return false; } return self::receiveMessage($importer, $fields); - case "participation": + case 'participation': if (!$private) { Logger::notice('Message with type ' . $type . ' is not private, quitting.'); return false; } return self::receiveParticipation($importer, $fields, $direction); - case "photo": // Not implemented + case 'photo': // Not implemented return self::receivePhoto($importer, $fields); - case "poll_participation": // Not implemented + case 'poll_participation': // Not implemented return self::receivePollParticipation($importer, $fields); - case "profile": + case 'profile': if (!$private) { Logger::notice('Message with type ' . $type . ' is not private, quitting.'); return false; } return self::receiveProfile($importer, $fields); - case "reshare": - return self::receiveReshare($importer, $fields, $msg["message"], $direction); + case 'reshare': + return self::receiveReshare($importer, $fields, $msg['message'], $direction); - case "retraction": + case 'retraction': return self::receiveRetraction($importer, $sender, $fields); - case "status_message": - return self::receiveStatusMessage($importer, $fields, $msg["message"], $direction); + case 'status_message': + return self::receiveStatusMessage($importer, $fields, $msg['message'], $direction); default: - Logger::notice("Unknown message type ".$type); + Logger::notice("Unknown message type " . $type); return false; } } @@ -598,9 +605,9 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function validPosting($msg) + private static function validPosting(array $msg) { - $data = XML::parseString($msg["message"]); + $data = XML::parseString($msg['message']); if (!is_object($data)) { Logger::info('No valid XML', ['message' => $msg['message']]); @@ -608,7 +615,7 @@ class Diaspora } // Is this the new or the old version? - if ($data->getName() == "XML") { + if ($data->getName() == 'XML') { $oldXML = true; foreach ($data->post->children() as $child) { $element = $child; @@ -621,106 +628,106 @@ class Diaspora $type = $element->getName(); $orig_type = $type; - Logger::debug("Got message type ".$type.": ".$msg["message"]); + Logger::debug("Got message type " . $type . ": " . $msg['message']); // All retractions are handled identically from now on. // In the new version there will only be "retraction". - if (in_array($type, ["signed_retraction", "relayable_retraction"])) - $type = "retraction"; + if (in_array($type, ['signed_retraction', 'relayable_retraction'])) + $type = 'retraction'; - if ($type == "request") { - $type = "contact"; + if ($type == 'request') { + $type = 'contact'; } - $fields = new SimpleXMLElement("<".$type."/>"); + $fields = new SimpleXMLElement('<' . $type . '/>'); - $signed_data = ""; + $signed_data = ''; $author_signature = null; $parent_author_signature = null; foreach ($element->children() as $fieldname => $entry) { if ($oldXML) { // Translation for the old XML structure - if ($fieldname == "diaspora_handle") { - $fieldname = "author"; + if ($fieldname == 'diaspora_handle') { + $fieldname = 'author'; } - if ($fieldname == "participant_handles") { - $fieldname = "participants"; + if ($fieldname == 'participant_handles') { + $fieldname = 'participants'; } - if (in_array($type, ["like", "participation"])) { - if ($fieldname == "target_type") { - $fieldname = "parent_type"; + if (in_array($type, ['like', 'participation'])) { + if ($fieldname == 'target_type') { + $fieldname = 'parent_type'; } } - if ($fieldname == "sender_handle") { - $fieldname = "author"; + if ($fieldname == 'sender_handle') { + $fieldname = 'author'; } - if ($fieldname == "recipient_handle") { - $fieldname = "recipient"; + if ($fieldname == 'recipient_handle') { + $fieldname = 'recipient'; } - if ($fieldname == "root_diaspora_id") { - $fieldname = "root_author"; + if ($fieldname == 'root_diaspora_id') { + $fieldname = 'root_author'; } - if ($type == "status_message") { - if ($fieldname == "raw_message") { - $fieldname = "text"; + if ($type == 'status_message') { + if ($fieldname == 'raw_message') { + $fieldname = 'text'; } } - if ($type == "retraction") { - if ($fieldname == "post_guid") { - $fieldname = "target_guid"; + if ($type == 'retraction') { + if ($fieldname == 'post_guid') { + $fieldname = 'target_guid'; } - if ($fieldname == "type") { - $fieldname = "target_type"; + if ($fieldname == 'type') { + $fieldname = 'target_type'; } } } - if (($fieldname == "author_signature") && ($entry != "")) { + if (($fieldname == 'author_signature') && ($entry != '')) { $author_signature = base64_decode($entry); - } elseif (($fieldname == "parent_author_signature") && ($entry != "")) { + } elseif (($fieldname == 'parent_author_signature') && ($entry != '')) { $parent_author_signature = base64_decode($entry); - } elseif (!in_array($fieldname, ["author_signature", "parent_author_signature", "target_author_signature"])) { - if ($signed_data != "") { - $signed_data .= ";"; + } elseif (!in_array($fieldname, ['author_signature', 'parent_author_signature', 'target_author_signature'])) { + if ($signed_data != '') { + $signed_data .= ';'; } $signed_data .= $entry; } - if (!in_array($fieldname, ["parent_author_signature", "target_author_signature"]) - || ($orig_type == "relayable_retraction") + if (!in_array($fieldname, ['parent_author_signature', 'target_author_signature']) + || ($orig_type == 'relayable_retraction') ) { XML::copy($entry, $fields, $fieldname); } } // This is something that shouldn't happen at all. - if (in_array($type, ["status_message", "reshare", "profile"])) { - if ($msg["author"] != $fields->author) { + if (in_array($type, ['status_message', 'reshare', 'profile'])) { + if ($msg['author'] != $fields->author) { Logger::notice("Message handle is not the same as envelope sender. Quitting this message."); return false; } } // Only some message types have signatures. So we quit here for the other types. - if (!in_array($type, ["comment", "like"])) { + if (!in_array($type, ['comment', 'like'])) { return $fields; } // No author_signature? This is a must, so we quit. if (!isset($author_signature)) { - Logger::info("No author signature for type ".$type." - Message: ".$msg["message"]); + Logger::info("No author signature for type " . $type . " - Message: " . $msg['message']); return false; } if (isset($parent_author_signature)) { - $key = self::key($msg["author"]); + $key = self::key($msg['author']); if (empty($key)) { - Logger::info('No key found for parent', ['author' => $msg["author"]]); + Logger::info('No key found for parent', ['author' => $msg['author']]); return false; } - if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) { - Logger::info("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature); + if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, 'sha256')) { + Logger::info("No valid parent author signature for parent author " . $msg['author'] . " in type " . $type . " - signed data: " . $signed_data . " - Message: " . $msg['message'] . " - Signature " . $parent_author_signature); return false; } } @@ -731,8 +738,8 @@ class Diaspora return false; } - if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) { - Logger::info("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature); + if (!Crypto::rsaVerify($signed_data, $author_signature, $key, 'sha256')) { + Logger::info("No valid author signature for author " . $fields->author . " in type " . $type . " - signed data: " . $signed_data . " - Message: " . $msg['message'] . " - Signature " . $author_signature); return false; } else { return $fields; @@ -748,18 +755,18 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function key($handle) + private static function key(string $handle): string { $handle = strval($handle); - Logger::notice("Fetching diaspora key for: ".$handle); + Logger::notice("Fetching diaspora key for: " . $handle); - $r = FContact::getByURL($handle); - if ($r) { - return $r["pubkey"]; + $fcontact = FContact::getByURL($handle); + if ($fcontact) { + return $fcontact['pubkey']; } - return ""; + return ''; } /** @@ -771,7 +778,7 @@ class Diaspora * @return string the handle * @throws \Exception */ - private static function handleFromContact($contact_id, $pcontact_id = 0) + private static function handleFromContact(int $contact_id, int $pcontact_id = 0): string { $handle = ''; @@ -804,7 +811,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function contactByHandle($uid, $handle) + private static function contactByHandle(int $uid, string $handle): array { return Contact::getByURL($handle, null, [], $uid); } @@ -818,7 +825,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isSupportedByContactUrl($url, $update = null) + public static function isSupportedByContactUrl(string $url, $update = null) { return !empty(FContact::getByURL($url, $update)); } @@ -832,7 +839,7 @@ class Diaspora * * @return bool is the contact allowed to post? */ - private static function postAllow(array $importer, array $contact, $is_comment = false) + private static function postAllow(array $importer, array $contact, bool $is_comment = false): bool { /* * Perhaps we were already sharing with this person. Now they're sharing with us. @@ -855,15 +862,15 @@ class Diaspora if (Network::isUrlBlocked($contact['url'])) { return false; // We don't seem to like that person - } elseif ($contact["blocked"]) { + } elseif ($contact['blocked']) { // Maybe blocked, don't accept. return false; // We are following this person? - } elseif (($contact["rel"] == Contact::SHARING) || ($contact["rel"] == Contact::FRIEND)) { + } elseif (($contact['rel'] == Contact::SHARING) || ($contact['rel'] == Contact::FRIEND)) { // Yes, then it is fine. return true; // Is the message a global user or a comment? - } elseif (($importer["uid"] == 0) || $is_comment) { + } elseif (($importer['uid'] == 0) || $is_comment) { // Messages for the global users and comments are always accepted return true; } @@ -878,16 +885,16 @@ class Diaspora * @param string $handle The checked handle in the format user@domain.tld * @param bool $is_comment Is the check for a comment? * - * @return array The contact data + * @return array|bool The contact data or false on error * @throws \Exception */ - private static function allowedContactByHandle(array $importer, $handle, $is_comment = false) + private static function allowedContactByHandle(array $importer, string $handle, bool $is_comment = false) { - $contact = self::contactByHandle($importer["uid"], $handle); + $contact = self::contactByHandle($importer['uid'], $handle); if (!$contact) { - Logger::notice("A Contact for handle ".$handle." and user ".$importer["uid"]." was not found"); + Logger::notice("A Contact for handle " . $handle . " and user " . $importer['uid'] . " was not found"); // If a contact isn't found, we accept it anyway if it is a comment - if ($is_comment && ($importer["uid"] != 0)) { + if ($is_comment && ($importer['uid'] != 0)) { return self::contactByHandle(0, $handle); } elseif ($is_comment) { return $importer; @@ -897,7 +904,7 @@ class Diaspora } if (!self::postAllow($importer, $contact, $is_comment)) { - Logger::notice("The handle: ".$handle." is not allowed to post to user ".$importer["uid"]); + Logger::notice("The handle: " . $handle . " is not allowed to post to user " . $importer['uid']); return false; } return $contact; @@ -912,12 +919,12 @@ class Diaspora * @return int|bool message id if the message already was stored into the system - or false. * @throws \Exception */ - private static function messageExists($uid, $guid) + private static function messageExists(int $uid, string $guid) { $item = Post::selectFirst(['id'], ['uid' => $uid, 'guid' => $guid]); if (DBA::isResult($item)) { - Logger::notice("message ".$guid." already exists for user ".$uid); - return $item["id"]; + Logger::notice("message " . $guid . " already exists for user " . $uid); + return $item['id']; } return false; @@ -931,13 +938,12 @@ class Diaspora */ private static function fetchGuid(array $item) { - $expression = "=diaspora://.*?/post/([0-9A-Za-z\-_@.:]{15,254}[0-9A-Za-z])=ism"; preg_replace_callback( - $expression, + "=diaspora://.*?/post/([0-9A-Za-z\-_@.:]{15,254}[0-9A-Za-z])=ism", function ($match) use ($item) { self::fetchGuidSub($match, $item); }, - $item["body"] + $item['body'] ); preg_replace_callback( @@ -945,7 +951,7 @@ class Diaspora function ($match) use ($item) { self::fetchGuidSub($match, $item); }, - $item["body"] + $item['body'] ); } @@ -958,7 +964,7 @@ class Diaspora * * @return string the replaced string */ - public static function replacePeopleGuid($body, $author_link) + public static function replacePeopleGuid(string $body, string $author_link): string { $return = preg_replace_callback( "&\[url=/people/([^\[\]]*)\](.*)\[\/url\]&Usi", @@ -970,11 +976,11 @@ class Diaspora $handle = FContact::getUrlByGuid($match[1]); if ($handle) { - $return = '@[url='.$handle.']'.$match[2].'[/url]'; + $return = '@[url=' . $handle . ']' . $match[2] . '[/url]'; } else { // No local match, restoring absolute remote URL from author scheme and host $author_url = parse_url($author_link); - $return = '[url='.$author_url['scheme'].'://'.$author_url['host'].'/people/'.$match[1].']'.$match[2].'[/url]'; + $return = '[url=' . $author_url['scheme'] . '://' . $author_url['host'] . '/people/' . $match[1] . ']' . $match[2] . '[/url]'; } return $return; @@ -994,10 +1000,10 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function fetchGuidSub($match, $item) + private static function fetchGuidSub(array $match, array $item) { - if (!self::storeByGuid($match[1], $item["author-link"], true)) { - self::storeByGuid($match[1], $item["owner-link"], true); + if (!self::storeByGuid($match[1], $item['author-link'], true)) { + self::storeByGuid($match[1], $item['owner-link'], true); } } @@ -1008,21 +1014,21 @@ class Diaspora * @param string $server The server address * @param bool $force Forced fetch * - * @return int the message id of the stored message or false + * @return int|bool the message id of the stored message or false * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function storeByGuid($guid, $server, $force) + private static function storeByGuid(string $guid, string $server, bool $force) { $serverparts = parse_url($server); - if (empty($serverparts["host"]) || empty($serverparts["scheme"])) { + if (empty($serverparts['host']) || empty($serverparts['scheme'])) { return false; } - $server = $serverparts["scheme"]."://".$serverparts["host"]; + $server = $serverparts['scheme'] . '://' . $serverparts['host']; - Logger::info("Trying to fetch item ".$guid." from ".$server); + Logger::info("Trying to fetch item " . $guid . " from " . $server); $msg = self::message($guid, $server); @@ -1030,7 +1036,7 @@ class Diaspora return false; } - Logger::info("Successfully fetched item ".$guid." from ".$server); + Logger::info("Successfully fetched item " . $guid . " from " . $server); // Now call the dispatcher return self::dispatchPublic($msg, $force ? self::FORCED_FETCH : self::FETCHED); @@ -1049,16 +1055,16 @@ class Diaspora * 'key' => The public key of the author * @throws \Exception */ - public static function message($guid, $server, $level = 0) + public static function message(string $guid, string $server, int $level = 0) { if ($level > 5) { return false; } // This will work for new Diaspora servers and Friendica servers from 3.5 - $source_url = $server."/fetch/post/".urlencode($guid); + $source_url = $server . '/fetch/post/' . urlencode($guid); - Logger::info("Fetch post from ".$source_url); + Logger::info("Fetch post from " . $source_url); $envelope = DI::httpClient()->fetch($source_url, HttpClientAccept::MAGIC); if ($envelope) { @@ -1098,7 +1104,7 @@ class Diaspora // Fetch the author - for the old and the new Diaspora version if ($source_xml->post->status_message && $source_xml->post->status_message->diaspora_handle) { $author = (string)$source_xml->post->status_message->diaspora_handle; - } elseif ($source_xml->author && ($source_xml->getName() == "status_message")) { + } elseif ($source_xml->author && ($source_xml->getName() == 'status_message')) { $author = (string)$source_xml->author; } @@ -1108,26 +1114,27 @@ class Diaspora return false; } - $msg = ["message" => $x, "author" => $author]; - - $msg["key"] = self::key($msg["author"]); - - return $msg; + return [ + 'message' => $x, + 'author' => $author, + 'key' => self::key($author) + ]; } /** * Fetches an item with a given URL * * @param string $url the message url + * @param int $uid User id * - * @return int the message id of the stored message or false + * @return int|bool the message id of the stored message or false * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function fetchByURL($url, $uid = 0) + public static function fetchByURL(string $url, int $uid = 0) { // Check for Diaspora (and Friendica) typical paths - if (!preg_match("=(https?://.+)/(?:posts|display|objects)/([a-zA-Z0-9-_@.:%]+[a-zA-Z0-9])=i", $url, $matches)) { + if (!preg_match('=(https?://.+)/(?:posts|display|objects)/([a-zA-Z0-9-_@.:%]+[a-zA-Z0-9])=i', $url, $matches)) { Logger::info('Invalid url', ['url' => $url]); return false; } @@ -1162,10 +1169,10 @@ class Diaspora * @param string $author The handle of the item * @param array $contact The contact of the item owner * - * @return array the item record + * @return array|bool the item record or false on failure * @throws \Exception */ - private static function parentItem($uid, $guid, $author, array $contact) + private static function parentItem(int $uid, string $guid, string $author, array $contact) { $fields = ['id', 'parent', 'body', 'wall', 'uri', 'guid', 'private', 'origin', 'author-name', 'author-link', 'author-avatar', 'gravity', @@ -1175,25 +1182,25 @@ class Diaspora if (!DBA::isResult($item)) { $person = FContact::getByURL($author); - $result = self::storeByGuid($guid, $person["url"], false); + $result = self::storeByGuid($guid, $person['url'], false); // We don't have an url for items that arrived at the public dispatcher - if (!$result && !empty($contact["url"])) { - $result = self::storeByGuid($guid, $contact["url"], false); + if (!$result && !empty($contact['url'])) { + $result = self::storeByGuid($guid, $contact['url'], false); } if ($result) { - Logger::info("Fetched missing item ".$guid." - result: ".$result); + Logger::info("Fetched missing item " . $guid . " - result: " . $result); $item = Post::selectFirst($fields, $condition); } } if (!DBA::isResult($item)) { - Logger::notice("parent item not found: parent: ".$guid." - user: ".$uid); + Logger::notice("parent item not found: parent: " . $guid . " - user: " . $uid); return false; } else { - Logger::notice("parent item found: parent: ".$guid." - user: ".$uid); + Logger::notice("parent item found: parent: " . $guid . " - user: " . $uid); return $item; } } @@ -1210,19 +1217,22 @@ class Diaspora * 'network' => network type * @throws \Exception */ - private static function authorContactByUrl($def_contact, $person, $uid) + private static function authorContactByUrl(array $def_contact, array $person, int $uid): array { - $condition = ['nurl' => Strings::normaliseLink($person["url"]), 'uid' => $uid]; + $condition = ['nurl' => Strings::normaliseLink($person['url']), 'uid' => $uid]; $contact = DBA::selectFirst('contact', ['id', 'network'], $condition); if (DBA::isResult($contact)) { - $cid = $contact["id"]; - $network = $contact["network"]; + $cid = $contact['id']; + $network = $contact['network']; } else { - $cid = $def_contact["id"]; + $cid = $def_contact['id']; $network = Protocol::DIASPORA; } - return ["cid" => $cid, "network" => $network]; + return [ + 'cid' => $cid, + 'network' => $network + ]; } /** @@ -1232,9 +1242,9 @@ class Diaspora * * @return bool is it a hubzilla server? */ - private static function isHubzilla($url) + private static function isHubzilla(string $url): bool { - return(strstr($url, '/channel/')); + return strstr($url, '/channel/'); } /** @@ -1248,7 +1258,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function plink(string $addr, string $guid, string $parent_guid = '') + private static function plink(string $addr, string $guid, string $parent_guid = ''): string { $contact = Contact::getByURL($addr); if (empty($contact)) { @@ -1306,30 +1316,30 @@ class Diaspora * Receives account migration * * @param array $importer Array of the importer user - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool Success * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveAccountMigration(array $importer, $data) + private static function receiveAccountMigration(array $importer, SimpleXMLElement $data): bool { $old_handle = XML::unescape($data->author); $new_handle = XML::unescape($data->profile->author); $signature = XML::unescape($data->signature); - $contact = self::contactByHandle($importer["uid"], $old_handle); + $contact = self::contactByHandle($importer['uid'], $old_handle); if (!$contact) { - Logger::notice("cannot find contact for sender: ".$old_handle." and user ".$importer["uid"]); + Logger::notice("cannot find contact for sender: " . $old_handle . " and user " . $importer['uid']); return false; } - Logger::notice("Got migration for ".$old_handle.", to ".$new_handle." with user ".$importer["uid"]); + Logger::notice("Got migration for " . $old_handle . ", to " . $new_handle . " with user " . $importer['uid']); // Check signature - $signed_text = 'AccountMigration:'.$old_handle.':'.$new_handle; + $signed_text = 'AccountMigration:' . $old_handle . ':' . $new_handle; $key = self::key($old_handle); - if (!Crypto::rsaVerify($signed_text, $signature, $key, "sha256")) { + if (!Crypto::rsaVerify($signed_text, $signature, $key, 'sha256')) { Logger::notice('No valid signature for migration.'); return false; } @@ -1340,15 +1350,21 @@ class Diaspora // change the technical stuff in contact $data = Probe::uri($new_handle); if ($data['network'] == Protocol::PHANTOM) { - Logger::notice('Account for '.$new_handle." couldn't be probed."); + Logger::notice("Account for " . $new_handle . " couldn't be probed."); return false; } - $fields = ['url' => $data['url'], 'nurl' => Strings::normaliseLink($data['url']), - 'name' => $data['name'], 'nick' => $data['nick'], - 'addr' => $data['addr'], 'batch' => $data['batch'], - 'notify' => $data['notify'], 'poll' => $data['poll'], - 'network' => $data['network']]; + $fields = [ + 'url' => $data['url'], + 'nurl' => Strings::normaliseLink($data['url']), + 'name' => $data['name'], + 'nick' => $data['nick'], + 'addr' => $data['addr'], + 'batch' => $data['batch'], + 'notify' => $data['notify'], + 'poll' => $data['poll'], + 'network' => $data['network'] + ]; Contact::update($fields, ['addr' => $old_handle]); @@ -1360,18 +1376,18 @@ class Diaspora /** * Processes an account deletion * - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool Success * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function receiveAccountDeletion($data) + private static function receiveAccountDeletion(SimpleXMLElement $data): bool { $author = XML::unescape($data->author); $contacts = DBA::select('contact', ['id'], ['addr' => $author]); while ($contact = DBA::fetch($contacts)) { - Contact::remove($contact["id"]); + Contact::remove($contact['id']); } DBA::close($contacts); @@ -1387,15 +1403,15 @@ class Diaspora * @param string $guid Message guid * @param boolean $onlyfound Only return uri when found in the database * - * @return string The constructed uri or the one from our database + * @return string The constructed uri or the one from our database or empty string on if $onlyfound is true * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function getUriFromGuid($author, $guid, $onlyfound = false) + private static function getUriFromGuid(string $author, string $guid, bool $onlyfound = false): string { $item = Post::selectFirst(['uri'], ['guid' => $guid]); if (DBA::isResult($item)) { - return $item["uri"]; + return $item['uri']; } elseif (!$onlyfound) { $person = FContact::getByURL($author); @@ -1406,7 +1422,7 @@ class Diaspora return $host_url . '/objects/' . $guid; } - return ""; + return ''; } /** @@ -1448,7 +1464,7 @@ class Diaspora * * @param array $importer Array of the importer user * @param string $sender The sender of the message - * @param object $data The message object + * @param SimpleXMLElement $data The message object * @param string $xml The original XML of the message * @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH) * @@ -1456,7 +1472,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveComment(array $importer, $sender, $data, $xml, int $direction) + private static function receiveComment(array $importer, string $sender, SimpleXMLElement $data, string $xml, int $direction): bool { $author = XML::unescape($data->author); $guid = XML::unescape($data->guid); @@ -1471,9 +1487,9 @@ class Diaspora if (isset($data->thread_parent_guid)) { $thread_parent_guid = XML::unescape($data->thread_parent_guid); - $thr_parent = self::getUriFromGuid("", $thread_parent_guid, true); + $thr_parent = self::getUriFromGuid('', $thread_parent_guid, true); } else { - $thr_parent = ""; + $thr_parent = ''; } $contact = self::allowedContactByHandle($importer, $sender, true); @@ -1485,12 +1501,12 @@ class Diaspora GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA); } - $message_id = self::messageExists($importer["uid"], $guid); + $message_id = self::messageExists($importer['uid'], $guid); if ($message_id) { return true; } - $toplevel_parent_item = self::parentItem($importer["uid"], $parent_guid, $author, $contact); + $toplevel_parent_item = self::parentItem($importer['uid'], $parent_guid, $author, $contact); if (!$toplevel_parent_item) { return false; } @@ -1502,60 +1518,60 @@ class Diaspora } // Fetch the contact id - if we know this contact - $author_contact = self::authorContactByUrl($contact, $person, $importer["uid"]); + $author_contact = self::authorContactByUrl($contact, $person, $importer['uid']); $datarray = []; - $datarray["uid"] = $importer["uid"]; - $datarray["contact-id"] = $author_contact["cid"]; - $datarray["network"] = $author_contact["network"]; + $datarray['uid'] = $importer['uid']; + $datarray['contact-id'] = $author_contact['cid']; + $datarray['network'] = $author_contact['network']; - $datarray["author-link"] = $person["url"]; - $datarray["author-id"] = Contact::getIdForURL($person["url"], 0); + $datarray['author-link'] = $person['url']; + $datarray['author-id'] = Contact::getIdForURL($person['url'], 0); - $datarray["owner-link"] = $contact["url"]; - $datarray["owner-id"] = Contact::getIdForURL($contact["url"], 0); + $datarray['owner-link'] = $contact['url']; + $datarray['owner-id'] = Contact::getIdForURL($contact['url'], 0); // Will be overwritten for sharing accounts in Item::insert if (in_array($direction, [self::FETCHED, self::FORCED_FETCH])) { - $datarray["post-reason"] = Item::PR_FETCHED; - } elseif ($datarray["uid"] == 0) { - $datarray["post-reason"] = Item::PR_GLOBAL; + $datarray['post-reason'] = Item::PR_FETCHED; + } elseif ($datarray['uid'] == 0) { + $datarray['post-reason'] = Item::PR_GLOBAL; } else { - $datarray["post-reason"] = Item::PR_COMMENT; + $datarray['post-reason'] = Item::PR_COMMENT; } - $datarray["guid"] = $guid; - $datarray["uri"] = self::getUriFromGuid($author, $guid); + $datarray['guid'] = $guid; + $datarray['uri'] = self::getUriFromGuid($author, $guid); $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); - $datarray["verb"] = Activity::POST; - $datarray["gravity"] = GRAVITY_COMMENT; + $datarray['verb'] = Activity::POST; + $datarray['gravity'] = GRAVITY_COMMENT; $datarray['thr-parent'] = $thr_parent ?: $toplevel_parent_item['uri']; - $datarray["object-type"] = Activity\ObjectType::COMMENT; - $datarray["post-type"] = Item::PT_NOTE; + $datarray['object-type'] = Activity\ObjectType::COMMENT; + $datarray['post-type'] = Item::PT_NOTE; - $datarray["protocol"] = Conversation::PARCEL_DIASPORA; - $datarray["source"] = $xml; - $datarray["direction"] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; + $datarray['protocol'] = Conversation::PARCEL_DIASPORA; + $datarray['source'] = $xml; + $datarray['direction'] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; - $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = $created_at; - $datarray["plink"] = self::plink($author, $guid, $toplevel_parent_item['guid']); + $datarray['plink'] = self::plink($author, $guid, $toplevel_parent_item['guid']); $body = Markdown::toBBCode($text); - $datarray["body"] = self::replacePeopleGuid($body, $person["url"]); + $datarray['body'] = self::replacePeopleGuid($body, $person['url']); self::storeMentions($datarray['uri-id'], $text); - Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray["body"]); + Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray['body']); self::fetchGuid($datarray); // If we are the origin of the parent we store the original data. // We notify our followers during the item storage. - if ($toplevel_parent_item["origin"]) { + if ($toplevel_parent_item['origin']) { $datarray['diaspora_signed_text'] = json_encode($data); } @@ -1571,7 +1587,7 @@ class Diaspora } if ($message_id) { - Logger::info("Stored comment ".$datarray["guid"]." with message id ".$message_id); + Logger::info("Stored comment " . $datarray['guid'] . " with message id " . $message_id); if ($datarray['uid'] == 0) { Item::distribute($message_id, json_encode($data)); } @@ -1585,15 +1601,16 @@ class Diaspora * * @param array $importer Array of the importer user * @param array $contact The contact of the message - * @param object $data The message object + * @param SimpleXMLElement $data The message object * @param array $msg Array of the processed message, author handle and key * @param object $mesg The private message * @param array $conversation The conversation record to which this message belongs * * @return bool "true" if it was successful * @throws \Exception + * @todo Find type-hint for $mesg and update documentation */ - private static function receiveConversationMessage(array $importer, array $contact, $data, $msg, $mesg, $conversation) + private static function receiveConversationMessage(array $importer, array $contact, SimpleXMLElement $data, array $msg, $mesg, array $conversation): bool { $author = XML::unescape($data->author); $guid = XML::unescape($data->guid); @@ -1645,12 +1662,12 @@ class Diaspora * * @param array $importer Array of the importer user * @param array $msg Array of the processed message, author handle and key - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool Success * @throws \Exception */ - private static function receiveConversation(array $importer, $msg, $data) + private static function receiveConversation(array $importer, array $msg, SimpleXMLElement $data) { $author = XML::unescape($data->author); $guid = XML::unescape($data->guid); @@ -1665,7 +1682,7 @@ class Diaspora return false; } - $contact = self::allowedContactByHandle($importer, $msg["author"], true); + $contact = self::allowedContactByHandle($importer, $msg['author'], true); if (!$contact) { return false; } @@ -1674,7 +1691,7 @@ class Diaspora GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA); } - $conversation = DBA::selectFirst('conv', [], ['uid' => $importer["uid"], 'guid' => $guid]); + $conversation = DBA::selectFirst('conv', [], ['uid' => $importer['uid'], 'guid' => $guid]); if (!DBA::isResult($conversation)) { $r = DBA::insert('conv', [ 'uid' => $importer['uid'], @@ -1685,7 +1702,7 @@ class Diaspora 'subject' => $subject, 'recips' => $participants]); if ($r) { - $conversation = DBA::selectFirst('conv', [], ['uid' => $importer["uid"], 'guid' => $guid]); + $conversation = DBA::selectFirst('conv', [], ['uid' => $importer['uid'], 'guid' => $guid]); } } if (!$conversation) { @@ -1705,14 +1722,14 @@ class Diaspora * * @param array $importer Array of the importer user * @param string $sender The sender of the message - * @param object $data The message object + * @param SimpleXMLElement $data The message object * @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH) * - * @return int The message id of the generated like or "false" if there was an error + * @return bool Success or failure * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveLike(array $importer, $sender, $data, int $direction) + private static function receiveLike(array $importer, string $sender, SimpleXMLElement $data, int $direction): bool { $author = XML::unescape($data->author); $guid = XML::unescape($data->guid); @@ -1722,7 +1739,7 @@ class Diaspora // likes on comments aren't supported by Diaspora - only on posts // But maybe this will be supported in the future, so we will accept it. - if (!in_array($parent_type, ["Post", "Comment"])) { + if (!in_array($parent_type, ['Post', 'Comment'])) { return false; } @@ -1735,12 +1752,12 @@ class Diaspora GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA); } - $message_id = self::messageExists($importer["uid"], $guid); + $message_id = self::messageExists($importer['uid'], $guid); if ($message_id) { return true; } - $toplevel_parent_item = self::parentItem($importer["uid"], $parent_guid, $author, $contact); + $toplevel_parent_item = self::parentItem($importer['uid'], $parent_guid, $author, $contact); if (!$toplevel_parent_item) { return false; } @@ -1752,11 +1769,11 @@ class Diaspora } // Fetch the contact id - if we know this contact - $author_contact = self::authorContactByUrl($contact, $person, $importer["uid"]); + $author_contact = self::authorContactByUrl($contact, $person, $importer['uid']); // "positive" = "false" would be a Dislike - wich isn't currently supported by Diaspora // We would accept this anyhow. - if ($positive == "true") { + if ($positive == 'true') { $verb = Activity::LIKE; } else { $verb = Activity::DISLIKE; @@ -1764,36 +1781,36 @@ class Diaspora $datarray = []; - $datarray["protocol"] = Conversation::PARCEL_DIASPORA; - $datarray["direction"] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; + $datarray['protocol'] = Conversation::PARCEL_DIASPORA; + $datarray['direction'] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; - $datarray["uid"] = $importer["uid"]; - $datarray["contact-id"] = $author_contact["cid"]; - $datarray["network"] = $author_contact["network"]; + $datarray['uid'] = $importer['uid']; + $datarray['contact-id'] = $author_contact['cid']; + $datarray['network'] = $author_contact['network']; - $datarray["owner-link"] = $datarray["author-link"] = $person["url"]; - $datarray["owner-id"] = $datarray["author-id"] = Contact::getIdForURL($person["url"], 0); + $datarray['owner-link'] = $datarray['author-link'] = $person['url']; + $datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($person['url'], 0); - $datarray["guid"] = $guid; - $datarray["uri"] = self::getUriFromGuid($author, $guid); + $datarray['guid'] = $guid; + $datarray['uri'] = self::getUriFromGuid($author, $guid); - $datarray["verb"] = $verb; - $datarray["gravity"] = GRAVITY_ACTIVITY; + $datarray['verb'] = $verb; + $datarray['gravity'] = GRAVITY_ACTIVITY; $datarray['thr-parent'] = $toplevel_parent_item['uri']; - $datarray["object-type"] = Activity\ObjectType::NOTE; + $datarray['object-type'] = Activity\ObjectType::NOTE; - $datarray["body"] = $verb; + $datarray['body'] = $verb; // Diaspora doesn't provide a date for likes - $datarray["changed"] = $datarray["created"] = $datarray["edited"] = DateTimeFormat::utcNow(); + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = DateTimeFormat::utcNow(); // like on comments have the comment as parent. So we need to fetch the toplevel parent if ($toplevel_parent_item['gravity'] != GRAVITY_PARENT) { $toplevel = Post::selectFirst(['origin'], ['id' => $toplevel_parent_item['parent']]); - $origin = $toplevel["origin"]; + $origin = $toplevel['origin']; } else { - $origin = $toplevel_parent_item["origin"]; + $origin = $toplevel_parent_item['origin']; } // If we are the origin of the parent we store the original data. @@ -1814,7 +1831,7 @@ class Diaspora } if ($message_id) { - Logger::info("Stored like ".$datarray["guid"]." with message id ".$message_id); + Logger::info("Stored like " . $datarray['guid'] . " with message id " . $message_id); if ($datarray['uid'] == 0) { Item::distribute($message_id, json_encode($data)); } @@ -1827,12 +1844,12 @@ class Diaspora * Processes private messages * * @param array $importer Array of the importer user - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool Success? * @throws \Exception */ - private static function receiveMessage(array $importer, $data) + private static function receiveMessage(array $importer, SimpleXMLElement $data): bool { $author = XML::unescape($data->author); $guid = XML::unescape($data->guid); @@ -1851,7 +1868,7 @@ class Diaspora $conversation = null; - $condition = ['uid' => $importer["uid"], 'guid' => $conversation_guid]; + $condition = ['uid' => $importer['uid'], 'guid' => $conversation_guid]; $conversation = DBA::selectFirst('conv', [], $condition); if (!DBA::isResult($conversation)) { @@ -1859,7 +1876,7 @@ class Diaspora return false; } - $message_uri = $author.":".$guid; + $message_uri = $author . ':' . $guid; $person = FContact::getByURL($author); if (!$person) { @@ -1892,14 +1909,14 @@ class Diaspora * Processes participations - unsupported by now * * @param array $importer Array of the importer user - * @param object $data The message object + * @param SimpleXMLElement $data The message object * @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH) * * @return bool success * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveParticipation(array $importer, $data, int $direction) + private static function receiveParticipation(array $importer, SimpleXMLElement $data, int $direction): bool { $author = strtolower(XML::unescape($data->author)); $guid = XML::unescape($data->guid); @@ -1914,11 +1931,11 @@ class Diaspora GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA); } - if (self::messageExists($importer["uid"], $guid)) { + if (self::messageExists($importer['uid'], $guid)) { return true; } - $toplevel_parent_item = self::parentItem($importer["uid"], $parent_guid, $author, $contact); + $toplevel_parent_item = self::parentItem($importer['uid'], $parent_guid, $author, $contact); if (!$toplevel_parent_item) { return false; } @@ -1934,38 +1951,38 @@ class Diaspora $person = FContact::getByURL($author); if (!is_array($person)) { - Logger::notice("Person not found: ".$author); + Logger::notice("Person not found: " . $author); return false; } - $author_contact = self::authorContactByUrl($contact, $person, $importer["uid"]); + $author_contact = self::authorContactByUrl($contact, $person, $importer['uid']); // Store participation $datarray = []; - $datarray["protocol"] = Conversation::PARCEL_DIASPORA; - $datarray["direction"] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; + $datarray['protocol'] = Conversation::PARCEL_DIASPORA; + $datarray['direction'] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; - $datarray["uid"] = $importer["uid"]; - $datarray["contact-id"] = $author_contact["cid"]; - $datarray["network"] = $author_contact["network"]; + $datarray['uid'] = $importer['uid']; + $datarray['contact-id'] = $author_contact['cid']; + $datarray['network'] = $author_contact['network']; - $datarray["owner-link"] = $datarray["author-link"] = $person["url"]; - $datarray["owner-id"] = $datarray["author-id"] = Contact::getIdForURL($person["url"], 0); + $datarray['owner-link'] = $datarray['author-link'] = $person['url']; + $datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($person['url'], 0); - $datarray["guid"] = $guid; - $datarray["uri"] = self::getUriFromGuid($author, $guid); + $datarray['guid'] = $guid; + $datarray['uri'] = self::getUriFromGuid($author, $guid); - $datarray["verb"] = Activity::FOLLOW; - $datarray["gravity"] = GRAVITY_ACTIVITY; + $datarray['verb'] = Activity::FOLLOW; + $datarray['gravity'] = GRAVITY_ACTIVITY; $datarray['thr-parent'] = $toplevel_parent_item['uri']; - $datarray["object-type"] = Activity\ObjectType::NOTE; + $datarray['object-type'] = Activity\ObjectType::NOTE; - $datarray["body"] = Activity::FOLLOW; + $datarray['body'] = Activity::FOLLOW; // Diaspora doesn't provide a date for a participation - $datarray["changed"] = $datarray["created"] = $datarray["edited"] = DateTimeFormat::utcNow(); + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = DateTimeFormat::utcNow(); if (Item::isTooOld($datarray)) { Logger::info('Participation is too old', ['created' => $datarray['created'], 'uid' => $datarray['uid'], 'guid' => $datarray['guid']]); @@ -1995,8 +2012,8 @@ class Diaspora continue; } - Logger::info('Deliver participation', ['item' => $comment['id'], 'contact' => $author_contact["cid"]]); - if (Worker::add(PRIORITY_HIGH, 'Delivery', Delivery::POST, $comment['id'], $author_contact["cid"])) { + Logger::info('Deliver participation', ['item' => $comment['id'], 'contact' => $author_contact['cid']]); + if (Worker::add(PRIORITY_HIGH, 'Delivery', Delivery::POST, $comment['id'], $author_contact['cid'])) { Post\DeliveryData::incrementQueueCount($comment['uri-id'], 1); } } @@ -2009,7 +2026,7 @@ class Diaspora * Processes photos - unneeded * * @param array $importer Array of the importer user - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool always true */ @@ -2038,68 +2055,69 @@ class Diaspora * Processes incoming profile updates * * @param array $importer Array of the importer user - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool Success * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveProfile(array $importer, $data) + private static function receiveProfile(array $importer, SimpleXMLElement $data): bool { $author = strtolower(XML::unescape($data->author)); - $contact = self::contactByHandle($importer["uid"], $author); + $contact = self::contactByHandle($importer['uid'], $author); if (!$contact) { return false; } - $name = XML::unescape($data->first_name).((strlen($data->last_name)) ? " ".XML::unescape($data->last_name) : ""); + $name = XML::unescape($data->first_name).((strlen($data->last_name)) ? ' ' . XML::unescape($data->last_name) : ''); $image_url = XML::unescape($data->image_url); $birthday = XML::unescape($data->birthday); $about = Markdown::toBBCode(XML::unescape($data->bio)); $location = Markdown::toBBCode(XML::unescape($data->location)); - $searchable = (XML::unescape($data->searchable) == "true"); - $nsfw = (XML::unescape($data->nsfw) == "true"); + $searchable = (XML::unescape($data->searchable) == 'true'); + $nsfw = (XML::unescape($data->nsfw) == 'true'); $tags = XML::unescape($data->tag_string); - $tags = explode("#", $tags); + $tags = explode('#', $tags); $keywords = []; foreach ($tags as $tag) { $tag = trim(strtolower($tag)); - if ($tag != "") { + if ($tag != '') { $keywords[] = $tag; } } - $keywords = implode(", ", $keywords); + $keywords = implode(', ', $keywords); - $handle_parts = explode("@", $author); + $handle_parts = explode('@', $author); $nick = $handle_parts[0]; - if ($name === "") { + if ($name === '') { $name = $handle_parts[0]; } - if (preg_match("|^https?://|", $image_url) === 0) { - $image_url = "http://".$handle_parts[1].$image_url; + if (preg_match('|^https?://|', $image_url) === 0) { + // @TODO No HTTPS here? + $image_url = 'http://' . $handle_parts[1] . $image_url; } - Contact::updateAvatar($contact["id"], $image_url); + Contact::updateAvatar($contact['id'], $image_url); // Generic birthday. We don't know the timezone. The year is irrelevant. - $birthday = str_replace("1000", "1901", $birthday); + $birthday = str_replace('1000', '1901', $birthday); - if ($birthday != "") { - $birthday = DateTimeFormat::utc($birthday, "Y-m-d"); + if ($birthday != '') { + $birthday = DateTimeFormat::utc($birthday, 'Y-m-d'); } // this is to prevent multiple birthday notifications in a single year // if we already have a stored birthday and the 'm-d' part hasn't changed, preserve the entry, which will preserve the notify year - if (substr($birthday, 5) === substr($contact["bd"], 5)) { - $birthday = $contact["bd"]; + if (substr($birthday, 5) === substr($contact['bd'], 5)) { + $birthday = $contact['bd']; } $fields = ['name' => $name, 'location' => $location, @@ -2113,7 +2131,7 @@ class Diaspora Contact::update($fields, ['id' => $contact['id']]); - Logger::info("Profile of contact ".$contact["id"]." stored for user ".$importer["uid"]); + Logger::info("Profile of contact " . $contact['id'] . " stored for user " . $importer['uid']); return true; } @@ -2128,10 +2146,10 @@ class Diaspora */ private static function receiveRequestMakeFriend(array $importer, array $contact) { - if ($contact["rel"] == Contact::SHARING) { + if ($contact['rel'] == Contact::SHARING) { Contact::update( ['rel' => Contact::FRIEND, 'writable' => true], - ['id' => $contact["id"], 'uid' => $importer["uid"]] + ['id' => $contact['id'], 'uid' => $importer['uid']] ); } } @@ -2140,12 +2158,12 @@ class Diaspora * Processes incoming sharing notification * * @param array $importer Array of the importer user - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool Success * @throws \Exception */ - private static function receiveContactRequest(array $importer, $data) + private static function receiveContactRequest(array $importer, SimpleXMLElement $data): bool { $author = XML::unescape($data->author); $recipient = XML::unescape($data->recipient); @@ -2157,64 +2175,64 @@ class Diaspora // the current protocol version doesn't know these fields // That means that we will assume their existance if (isset($data->following)) { - $following = (XML::unescape($data->following) == "true"); + $following = (XML::unescape($data->following) == 'true'); } else { $following = true; } if (isset($data->sharing)) { - $sharing = (XML::unescape($data->sharing) == "true"); + $sharing = (XML::unescape($data->sharing) == 'true'); } else { $sharing = true; } - $contact = self::contactByHandle($importer["uid"], $author); + $contact = self::contactByHandle($importer['uid'], $author); // perhaps we were already sharing with this person. Now they're sharing with us. // That makes us friends. if ($contact) { if ($following) { - Logger::info("Author ".$author." (Contact ".$contact["id"].") wants to follow us."); + Logger::info("Author " . $author . " (Contact " . $contact['id'] . ") wants to follow us."); self::receiveRequestMakeFriend($importer, $contact); // refetch the contact array - $contact = self::contactByHandle($importer["uid"], $author); + $contact = self::contactByHandle($importer['uid'], $author); // If we are now friends, we are sending a share message. // Normally we needn't to do so, but the first message could have been vanished. - if (in_array($contact["rel"], [Contact::FRIEND])) { - $user = DBA::selectFirst('user', [], ['uid' => $importer["uid"]]); + if (in_array($contact['rel'], [Contact::FRIEND])) { + $user = DBA::selectFirst('user', [], ['uid' => $importer['uid']]); if (DBA::isResult($user)) { - Logger::info("Sending share message to author ".$author." - Contact: ".$contact["id"]." - User: ".$importer["uid"]); + Logger::info("Sending share message to author " . $author . " - Contact: " . $contact['id'] . " - User: " . $importer['uid']); self::sendShare($user, $contact); } } return true; } else { - Logger::info("Author ".$author." doesn't want to follow us anymore."); + Logger::info("Author " . $author . " doesn't want to follow us anymore."); Contact::removeFollower($contact); return true; } } - if (!$following && $sharing && in_array($importer["page-flags"], [User::PAGE_FLAGS_SOAPBOX, User::PAGE_FLAGS_NORMAL])) { - Logger::info("Author ".$author." wants to share with us - but doesn't want to listen. Request is ignored."); + if (!$following && $sharing && in_array($importer['page-flags'], [User::PAGE_FLAGS_SOAPBOX, User::PAGE_FLAGS_NORMAL])) { + Logger::info("Author " . $author . " wants to share with us - but doesn't want to listen. Request is ignored."); return false; } elseif (!$following && !$sharing) { - Logger::info("Author ".$author." doesn't want anything - and we don't know the author. Request is ignored."); + Logger::info("Author " . $author . " doesn't want anything - and we don't know the author. Request is ignored."); return false; } elseif (!$following && $sharing) { - Logger::info("Author ".$author." wants to share with us."); + Logger::info("Author " . $author . " wants to share with us."); } elseif ($following && $sharing) { - Logger::info("Author ".$author." wants to have a bidirectional conection."); + Logger::info("Author " . $author . " wants to have a bidirectional conection."); } elseif ($following && !$sharing) { - Logger::info("Author ".$author." wants to listen to us."); + Logger::info("Author " . $author . " wants to listen to us."); } $ret = FContact::getByURL($author); - if (!$ret || ($ret["network"] != Protocol::DIASPORA)) { - Logger::notice("Cannot resolve diaspora handle ".$author." for ".$recipient); + if (!$ret || ($ret['network'] != Protocol::DIASPORA)) { + Logger::notice("Cannot resolve diaspora handle " . $author . " for ".$recipient); return false; } @@ -2233,7 +2251,7 @@ class Diaspora $contact_record = self::contactByHandle($importer['uid'], $author); if (!$contact_record) { Logger::info('unable to locate newly created contact record.'); - return; + return false; } $user = DBA::selectFirst('user', [], ['uid' => $importer['uid']]); @@ -2253,11 +2271,11 @@ class Diaspora * * @param string $guid message guid * @param string $orig_author handle of the original post - * @return array The fetched item + * @return array|bool The fetched item or false on failure * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function originalItem($guid, $orig_author) + public static function originalItem(string $guid, string $orig_author) { if (empty($guid)) { Logger::notice('Empty guid. Quitting.'); @@ -2271,17 +2289,17 @@ class Diaspora $item = Post::selectFirst($fields, $condition); if (DBA::isResult($item)) { - Logger::notice("reshared message ".$guid." already exists on system."); + Logger::notice("reshared message " . $guid . " already exists on system."); // Maybe it is already a reshared item? // Then refetch the content, if it is a reshare from a reshare. // If it is a reshared post from another network then reformat to avoid display problems with two share elements - if (self::isReshare($item["body"], true)) { + if (self::isReshare($item['body'], true)) { $item = []; - } elseif (self::isReshare($item["body"], false) || strstr($item["body"], "[share")) { - $item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"])); + } elseif (self::isReshare($item['body'], false) || strstr($item['body'], '[share')) { + $item['body'] = Markdown::toBBCode(BBCode::toMarkdown($item['body'])); - $item["body"] = self::replacePeopleGuid($item["body"], $item["author-link"]); + $item['body'] = self::replacePeopleGuid($item['body'], $item['author-link']); return $item; } else { @@ -2295,13 +2313,13 @@ class Diaspora return false; } - $server = "https://".substr($orig_author, strpos($orig_author, "@") + 1); - Logger::notice("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server); + $server = 'https://' . substr($orig_author, strpos($orig_author, '@') + 1); + Logger::notice("1st try: reshared message " . $guid . " will be fetched via SSL from the server " . $server); $stored = self::storeByGuid($guid, $server, true); if (!$stored) { - $server = "http://".substr($orig_author, strpos($orig_author, "@") + 1); - Logger::notice("2nd try: reshared message ".$guid." will be fetched without SSL from the server ".$server); + $server = 'http://' . substr($orig_author, strpos($orig_author, '@') + 1); + Logger::notice("2nd try: reshared message " . $guid . " will be fetched without SSL from the server " . $server); $stored = self::storeByGuid($guid, $server, true); } @@ -2313,9 +2331,9 @@ class Diaspora if (DBA::isResult($item)) { // If it is a reshared post from another network then reformat to avoid display problems with two share elements - if (self::isReshare($item["body"], false)) { - $item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"])); - $item["body"] = self::replacePeopleGuid($item["body"], $item["author-link"]); + if (self::isReshare($item['body'], false)) { + $item['body'] = Markdown::toBBCode(BBCode::toMarkdown($item['body'])); + $item['body'] = self::replacePeopleGuid($item['body'], $item['author-link']); } return $item; @@ -2333,7 +2351,7 @@ class Diaspora * @param string $guid GUID string of reshare action * @param string $author Author handle */ - private static function addReshareActivity($item, $parent_message_id, $guid, $author) + private static function addReshareActivity(array $item, int $parent_message_id, string $guid, string $author) { $parent = Post::selectFirst(['uri', 'guid'], ['id' => $parent_message_id]); @@ -2384,15 +2402,15 @@ class Diaspora * Processes a reshare message * * @param array $importer Array of the importer user - * @param object $data The message object + * @param SimpleXMLElement $data The message object * @param string $xml The original XML of the message * @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH) * - * @return int the message id + * @return bool Success or failure * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveReshare(array $importer, $data, $xml, int $direction) + private static function receiveReshare(array $importer, SimpleXMLElement $data, string $xml, int $direction): bool { $author = XML::unescape($data->author); $guid = XML::unescape($data->guid); @@ -2411,7 +2429,7 @@ class Diaspora GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA); } - $message_id = self::messageExists($importer["uid"], $guid); + $message_id = self::messageExists($importer['uid'], $guid); if ($message_id) { return true; } @@ -2427,53 +2445,53 @@ class Diaspora $datarray = []; - $datarray["uid"] = $importer["uid"]; - $datarray["contact-id"] = $contact["id"]; - $datarray["network"] = Protocol::DIASPORA; + $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['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['owner-link'] = $datarray['author-link']; + $datarray['owner-id'] = $datarray['author-id']; - $datarray["guid"] = $guid; - $datarray["uri"] = $datarray["thr-parent"] = self::getUriFromGuid($author, $guid); + $datarray['guid'] = $guid; + $datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($author, $guid); $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); - $datarray["verb"] = Activity::POST; - $datarray["gravity"] = GRAVITY_PARENT; + $datarray['verb'] = Activity::POST; + $datarray['gravity'] = GRAVITY_PARENT; - $datarray["protocol"] = Conversation::PARCEL_DIASPORA; - $datarray["source"] = $xml; - $datarray["direction"] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; + $datarray['protocol'] = Conversation::PARCEL_DIASPORA; + $datarray['source'] = $xml; + $datarray['direction'] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; /// @todo Copy tag data from original post $prefix = BBCode::getShareOpeningTag( - $original_item["author-name"], - $original_item["author-link"], - $original_item["author-avatar"], - $original_item["plink"], - $original_item["created"], - $original_item["guid"] + $original_item['author-name'], + $original_item['author-link'], + $original_item['author-avatar'], + $original_item['plink'], + $original_item['created'], + $original_item['guid'] ); if (!empty($original_item['title'])) { $prefix .= '[h3]' . $original_item['title'] . "[/h3]\n"; } - $datarray["body"] = $prefix.$original_item["body"]."[/share]"; + $datarray['body'] = $prefix.$original_item['body'] . '[/share]'; - Tag::storeFromBody($datarray['uri-id'], $datarray["body"]); + Tag::storeFromBody($datarray['uri-id'], $datarray['body']); - $datarray["app"] = $original_item["app"]; + $datarray['app'] = $original_item['app']; - $datarray["plink"] = self::plink($author, $guid); - $datarray["private"] = (($public == "false") ? Item::PRIVATE : Item::PUBLIC); - $datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at; + $datarray['plink'] = self::plink($author, $guid); + $datarray['private'] = (($public == 'false') ? Item::PRIVATE : Item::PUBLIC); + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = $created_at; - $datarray["object-type"] = $original_item["object-type"]; + $datarray['object-type'] = $original_item['object-type']; self::fetchGuid($datarray); @@ -2486,13 +2504,13 @@ class Diaspora self::sendParticipation($contact, $datarray); - $root_message_id = self::messageExists($importer["uid"], $root_guid); + $root_message_id = self::messageExists($importer['uid'], $root_guid); if ($root_message_id) { self::addReshareActivity($datarray, $root_message_id, $guid, $author); } if ($message_id) { - Logger::info("Stored reshare ".$datarray["guid"]." with message id ".$message_id); + Logger::info("Stored reshare " . $datarray['guid'] . " with message id " . $message_id); if ($datarray['uid'] == 0) { Item::distribute($message_id); } @@ -2507,12 +2525,12 @@ class Diaspora * * @param array $importer Array of the importer user * @param array $contact The contact of the item owner - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool success * @throws \Exception */ - private static function itemRetraction(array $importer, array $contact, $data) + private static function itemRetraction(array $importer, array $contact, SimpleXMLElement $data): bool { $author = XML::unescape($data->author); $target_guid = XML::unescape($data->target_guid); @@ -2520,12 +2538,12 @@ class Diaspora $person = FContact::getByURL($author); if (!is_array($person)) { - Logger::notice("unable to find author detail for ".$author); + Logger::notice("unable to find author detail for " . $author); return false; } - if (empty($contact["url"])) { - $contact["url"] = $person["url"]; + if (empty($contact['url'])) { + $contact['url'] = $person['url']; } // Fetch items that are about to be deleted @@ -2540,7 +2558,7 @@ class Diaspora $r = Post::select($fields, $condition); if (!DBA::isResult($r)) { - Logger::notice("Target guid ".$target_guid." was not found on this system for user ".$importer['uid']."."); + Logger::notice("Target guid " . $target_guid . " was not found on this system for user " . $importer['uid'] . "."); return false; } @@ -2554,14 +2572,14 @@ class Diaspora $parent = Post::selectFirst(['author-link'], ['id' => $item['parent']]); // Only delete it if the parent author really fits - if (!Strings::compareLink($parent["author-link"], $contact["url"]) && !Strings::compareLink($item["author-link"], $contact["url"])) { - Logger::info("Thread author ".$parent["author-link"]." and item author ".$item["author-link"]." don't fit to expected contact ".$contact["url"]); + if (!Strings::compareLink($parent['author-link'], $contact['url']) && !Strings::compareLink($item['author-link'], $contact['url'])) { + Logger::info("Thread author " . $parent['author-link'] . " and item author " . $item['author-link'] . " don't fit to expected contact " . $contact['url']); continue; } Item::markForDeletion(['id' => $item['id']]); - Logger::info("Deleted target ".$target_guid." (".$item["id"].") from user ".$item["uid"]." parent: ".$item['parent']); + Logger::info("Deleted target " . $target_guid . " (" . $item['id'] . ") from user " . $item['uid'] . " parent: " . $item['parent']); } DBA::close($r); @@ -2573,18 +2591,18 @@ class Diaspora * * @param array $importer Array of the importer user * @param string $sender The sender of the message - * @param object $data The message object + * @param SimpleXMLElement $data The message object * * @return bool Success * @throws \Exception */ - private static function receiveRetraction(array $importer, $sender, $data) + private static function receiveRetraction(array $importer, string $sender, SimpleXMLElement $data) { $target_type = XML::unescape($data->target_type); - $contact = self::contactByHandle($importer["uid"], $sender); - if (!$contact && (in_array($target_type, ["Contact", "Person"]))) { - Logger::notice("cannot find contact for sender: ".$sender." and user ".$importer["uid"]); + $contact = self::contactByHandle($importer['uid'], $sender); + if (!$contact && (in_array($target_type, ['Contact', 'Person']))) { + Logger::notice("cannot find contact for sender: " . $sender . " and user " . $importer['uid']); return false; } @@ -2592,23 +2610,23 @@ class Diaspora $contact = []; } - Logger::info("Got retraction for ".$target_type.", sender ".$sender." and user ".$importer["uid"]); + Logger::info("Got retraction for " . $target_type . ", sender " . $sender . " and user " . $importer['uid']); switch ($target_type) { - case "Comment": - case "Like": - case "Post": - case "Reshare": - case "StatusMessage": + case 'Comment': + case 'Like': + case 'Post': + case 'Reshare': + case 'StatusMessage': return self::itemRetraction($importer, $contact, $data); - case "PollParticipation": - case "Photo": + case 'PollParticipation': + case 'Photo': // Currently unsupported break; default: - Logger::notice("Unknown target type ".$target_type); + Logger::notice("Unknown target type " . $target_type); return false; } return true; @@ -2624,11 +2642,10 @@ class Diaspora * * @return boolean Is the message wanted? */ - private static function isSolicitedMessage(array $item, string $author, string $body, int $direction) + private static function isSolicitedMessage(array $item, string $author, string $body, int $direction): bool { $contact = Contact::getByURL($author); - if (DBA::exists('contact', ["`nurl` = ? AND `uid` != ? AND `rel` IN (?, ?)", - $contact['nurl'], 0, Contact::FRIEND, Contact::SHARING])) { + if (DBA::exists('contact', ['`nurl` = ? AND `uid` != ? AND `rel` IN (?, ?)', $contact['nurl'], 0, Contact::FRIEND, Contact::SHARING])) { Logger::debug('Author has got followers - accepted', ['uri-id' => $item['uri-id'], 'guid' => $item['guid'], 'url' => $item['uri'], 'author' => $author]); return true; } @@ -2656,6 +2673,8 @@ class Diaspora */ 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; @@ -2675,11 +2694,11 @@ class Diaspora * @param string $xml The original XML of the message * @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH) * - * @return int The message id of the newly created item + * @return int|bool The message id of the newly created item or false on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function receiveStatusMessage(array $importer, SimpleXMLElement $data, $xml, int $direction) + private static function receiveStatusMessage(array $importer, SimpleXMLElement $data, string $xml, int $direction) { $author = XML::unescape($data->author); $guid = XML::unescape($data->guid); @@ -2697,7 +2716,7 @@ class Diaspora GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA); } - $message_id = self::messageExists($importer["uid"], $guid); + $message_id = self::messageExists($importer['uid'], $guid); if ($message_id) { return true; } @@ -2713,8 +2732,8 @@ class Diaspora $datarray = []; - $datarray["guid"] = $guid; - $datarray["uri"] = $datarray["thr-parent"] = self::getUriFromGuid($author, $guid); + $datarray['guid'] = $guid; + $datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($author, $guid); $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); // Attach embedded pictures to the body @@ -2723,14 +2742,14 @@ class Diaspora self::storePhotoAsMedia($datarray['uri-id'], $photo); } - $datarray["object-type"] = Activity\ObjectType::IMAGE; - $datarray["post-type"] = Item::PT_IMAGE; + $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; + $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; + $datarray['object-type'] = Activity\ObjectType::NOTE; + $datarray['post-type'] = Item::PT_NOTE; } /// @todo enable support for polls @@ -2742,54 +2761,54 @@ class Diaspora /// @todo enable support for events - $datarray["uid"] = $importer["uid"]; - $datarray["contact-id"] = $contact["id"]; - $datarray["network"] = Protocol::DIASPORA; + $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['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['owner-link'] = $datarray['author-link']; + $datarray['owner-id'] = $datarray['author-id']; - $datarray["verb"] = Activity::POST; - $datarray["gravity"] = GRAVITY_PARENT; + $datarray['verb'] = Activity::POST; + $datarray['gravity'] = GRAVITY_PARENT; - $datarray["protocol"] = Conversation::PARCEL_DIASPORA; - $datarray["source"] = $xml; - $datarray["direction"] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; + $datarray['protocol'] = Conversation::PARCEL_DIASPORA; + $datarray['source'] = $xml; + $datarray['direction'] = in_array($direction, [self::FETCHED, self::FORCED_FETCH]) ? Conversation::PULL : Conversation::PUSH; if (in_array($direction, [self::FETCHED, self::FORCED_FETCH])) { - $datarray["post-reason"] = Item::PR_FETCHED; - } elseif ($datarray["uid"] == 0) { - $datarray["post-reason"] = Item::PR_GLOBAL; + $datarray['post-reason'] = Item::PR_FETCHED; + } elseif ($datarray['uid'] == 0) { + $datarray['post-reason'] = Item::PR_GLOBAL; } - $datarray["body"] = self::replacePeopleGuid($body, $contact["url"]); - $datarray["raw-body"] = self::replacePeopleGuid($raw_body, $contact["url"]); + $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"]); + Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray['body']); if (!self::isSolicitedMessage($datarray, $author, $body, $direction)) { DBA::delete('item-uri', ['uri' => $datarray['uri']]); return false; } - if ($provider_display_name != "") { - $datarray["app"] = $provider_display_name; + if ($provider_display_name != '') { + $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; + $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"])) { - $datarray["location"] = $address["address"]; + if (isset($address['address'])) { + $datarray['location'] = $address['address']; } - if (isset($address["lat"]) && isset($address["lng"])) { - $datarray["coord"] = $address["lat"]." ".$address["lng"]; + if (isset($address['lat']) && isset($address['lng'])) { + $datarray['coord'] = $address['lat'] . " " . $address['lng']; } self::fetchGuid($datarray); @@ -2804,7 +2823,7 @@ class Diaspora self::sendParticipation($contact, $datarray); if ($message_id) { - Logger::info("Stored item ".$datarray["guid"]." with message id ".$message_id); + Logger::info("Stored item " . $datarray['guid'] . " with message id " . $message_id); if ($datarray['uid'] == 0) { Item::distribute($message_id); } @@ -2826,21 +2845,21 @@ class Diaspora * @return string the handle in the format user@domain.tld * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function myHandle(array $contact) + private static function myHandle(array $contact): string { - if (!empty($contact["addr"])) { - return $contact["addr"]; + if (!empty($contact['addr'])) { + return $contact['addr']; } // Normally we should have a filled "addr" field - but in the past this wasn't the case // So - just in case - we build the the address here. - if ($contact["nickname"] != "") { - $nick = $contact["nickname"]; + if ($contact['nickname'] != '') { + $nick = $contact['nickname']; } else { - $nick = $contact["nick"]; + $nick = $contact['nick']; } - return $nick . "@" . substr(DI::baseUrl(), strpos(DI::baseUrl(), "://") + 3); + return $nick . '@' . substr(DI::baseUrl(), strpos(DI::baseUrl(), '://') + 3); } @@ -2856,7 +2875,7 @@ class Diaspora * @return string The encrypted data * @throws \Exception */ - public static function encodePrivateData($msg, array $user, array $contact, $prvkey, $pubkey) + public static function encodePrivateData(string $msg, array $user, array $contact, string $prvkey, string $pubkey): string { Logger::debug("Message: ".$msg); @@ -2873,16 +2892,18 @@ class Diaspora $ciphertext = self::aesEncrypt($aes_key, $iv, $msg); - $json = json_encode(["iv" => $b_iv, "key" => $b_aes_key]); + $json = json_encode(['iv' => $b_iv, 'key' => $b_aes_key]); - $encrypted_key_bundle = ""; + $encrypted_key_bundle = ''; if (!@openssl_public_encrypt($json, $encrypted_key_bundle, $pubkey)) { return false; } $json_object = json_encode( - ["aes_key" => base64_encode($encrypted_key_bundle), - "encrypted_magic_envelope" => base64_encode($ciphertext)] + [ + 'aes_key' => base64_encode($encrypted_key_bundle), + 'encrypted_magic_envelope' => base64_encode($ciphertext) + ] ); return $json_object; @@ -2897,33 +2918,37 @@ class Diaspora * @return string The envelope * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function buildMagicEnvelope($msg, array $user) + 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"; - $encoding = "base64url"; - $alg = "RSA-SHA256"; - $signable_data = $data.".".Strings::base64UrlEncode($type).".".Strings::base64UrlEncode($encoding).".".Strings::base64UrlEncode($alg); + $type = 'application/xml'; + $encoding = 'base64url'; + $alg = 'RSA-SHA256'; + $signable_data = $data . '.' . Strings::base64UrlEncode($type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($alg); // Fallback if the private key wasn't transmitted in the expected field - if ($user['uprvkey'] == "") { + if ($user['uprvkey'] == '') { $user['uprvkey'] = $user['prvkey']; } - $signature = Crypto::rsaSign($signable_data, $user["uprvkey"]); + $signature = Crypto::rsaSign($signable_data, $user['uprvkey']); $sig = Strings::base64UrlEncode($signature); - $xmldata = ["me:env" => ["me:data" => $data, - "@attributes" => ["type" => $type], - "me:encoding" => $encoding, - "me:alg" => $alg, - "me:sig" => $sig, - "@attributes2" => ["key_id" => $key_id]]]; + $xmldata = [ + 'me:env' => [ + 'me:data' => $data, + '@attributes' => ['type' => $type], + 'me:encoding' => $encoding, + 'me:alg' => $alg, + 'me:sig' => $sig, + '@attributes2' => ['key_id' => $key_id] + ] + ]; - $namespaces = ["me" => "http://salmon-protocol.org/ns/magic-env"]; + $namespaces = ['me' => 'http://salmon-protocol.org/ns/magic-env']; return XML::fromArray($xmldata, $xml, false, $namespaces); } @@ -2941,7 +2966,7 @@ class Diaspora * @return string The message that will be transmitted to other servers * @throws \Exception */ - public static function buildMessage($msg, array $user, array $contact, $prvkey, $pubkey, $public = false) + public static function buildMessage(string $msg, array $user, array $contact, string $prvkey, string $pubkey, bool $public = false): string { // The message is put into an envelope with the sender's signature $envelope = self::buildMagicEnvelope($msg, $user); @@ -2962,15 +2987,15 @@ class Diaspora * * @return string The signature */ - private static function signature($owner, $message) + private static function signature(array $owner, array $message): string { $sigmsg = $message; - unset($sigmsg["author_signature"]); - unset($sigmsg["parent_author_signature"]); + unset($sigmsg['author_signature']); + unset($sigmsg['parent_author_signature']); - $signed_text = implode(";", $sigmsg); + $signed_text = implode(';', $sigmsg); - return base64_encode(Crypto::rsaSign($signed_text, $owner["uprvkey"], "sha256")); + return base64_encode(Crypto::rsaSign($signed_text, $owner['uprvkey'], 'sha256')); } /** @@ -2986,9 +3011,9 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function transmit(array $owner, array $contact, $envelope, $public_batch, $guid = "") + private static function transmit(array $owner, array $contact, string $envelope, bool $public_batch, string $guid = ''): int { - $enabled = intval(DI::config()->get("system", "diaspora_enabled")); + $enabled = intval(DI::config()->get('system', 'diaspora_enabled')); if (!$enabled) { return 200; } @@ -3000,32 +3025,32 @@ class Diaspora if (!empty($contact['addr'])) { $fcontact = FContact::getByURL($contact['addr']); if (!empty($fcontact)) { - $dest_url = ($public_batch ? $fcontact["batch"] : $fcontact["notify"]); + $dest_url = ($public_batch ? $fcontact['batch'] : $fcontact['notify']); } } if (empty($dest_url)) { - $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); + $dest_url = ($public_batch ? $contact['batch'] : $contact['notify']); } if (!$dest_url) { - Logger::notice("no url for contact: ".$contact["id"]." batch mode =".$public_batch); + Logger::notice("no url for contact: " . $contact['id'] . " batch mode =" . $public_batch); return 0; } - Logger::notice("transmit: ".$logid."-".$guid." ".$dest_url); + Logger::notice("transmit: " . $logid . "-" . $guid . " " . $dest_url); - if (!intval(DI::config()->get("system", "diaspora_test"))) { - $content_type = (($public_batch) ? "application/magic-envelope+xml" : "application/json"); + if (!intval(DI::config()->get('system', 'diaspora_test'))) { + $content_type = (($public_batch) ? 'application/magic-envelope+xml' : 'application/json'); - $postResult = DI::httpClient()->post($dest_url . "/", $envelope, ['Content-Type' => $content_type]); + $postResult = DI::httpClient()->post($dest_url . '/', $envelope, ['Content-Type' => $content_type]); $return_code = $postResult->getReturnCode(); } else { - Logger::notice("test_mode"); + Logger::notice('test_mode'); return 200; } - Logger::notice("transmit: ".$logid."-".$guid." to ".$dest_url." returns: ".$return_code); + Logger::notice("transmit: " . $logid . "-" . $guid . " to " . $dest_url . " returns: " . $return_code); return $return_code ? $return_code : -1; } @@ -3039,7 +3064,7 @@ class Diaspora * * @return string The post XML */ - public static function buildPostXml($type, $message) + public static function buildPostXml(string $type, array $message): string { $data = [$type => $message]; @@ -3060,7 +3085,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function buildAndTransmit(array $owner, array $contact, $type, $message, $public_batch = false, $guid = "") + private static function buildAndTransmit(array $owner, array $contact, string $type, array $message, bool $public_batch = false, string $guid = '') { $msg = self::buildPostXml($type, $message); @@ -3103,18 +3128,18 @@ class Diaspora * @return int The result of the transmission * @throws \Exception */ - private static function sendParticipation(array $contact, array $item) + private static function sendParticipation(array $contact, array $item): int { // Don't send notifications for private postings if ($item['private'] == Item::PRIVATE) { - return; + return 0; } - $cachekey = "diaspora:sendParticipation:".$item['guid']; + $cachekey = 'diaspora:sendParticipation:' . $item['guid']; $result = DI::cache()->get($cachekey); if (!is_null($result)) { - return; + return -1; } // Fetch some user id to have a valid handle to transmit the participation. @@ -3132,17 +3157,19 @@ class Diaspora $author = self::myHandle($owner); - $message = ["author" => $author, - "guid" => System::createUUID(), - "parent_type" => "Post", - "parent_guid" => $item["guid"]]; + $message = [ + 'author' => $author, + 'guid' => System::createUUID(), + 'parent_type' => 'Post', + 'parent_guid' => $item['guid'] + ]; - Logger::info("Send participation for ".$item["guid"]." by ".$author); + Logger::info("Send participation for " . $item['guid'] . " by " . $author); // It doesn't matter what we store, we only want to avoid sending repeated notifications for the same item - DI::cache()->set($cachekey, $item["guid"], Duration::QUARTER_HOUR); + DI::cache()->set($cachekey, $item['guid'], Duration::QUARTER_HOUR); - return self::buildAndTransmit($owner, $contact, "participation", $message); + return self::buildAndTransmit($owner, $contact, 'participation', $message); } /** @@ -3156,21 +3183,23 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function sendAccountMigration(array $owner, array $contact, $uid) + public static function sendAccountMigration(array $owner, array $contact, int $uid): int { $old_handle = DI::pConfig()->get($uid, 'system', 'previous_addr'); $profile = self::createProfileData($uid); $signed_text = 'AccountMigration:'.$old_handle.':'.$profile['author']; - $signature = base64_encode(Crypto::rsaSign($signed_text, $owner["uprvkey"], "sha256")); + $signature = base64_encode(Crypto::rsaSign($signed_text, $owner['uprvkey'], 'sha256')); - $message = ["author" => $old_handle, - "profile" => $profile, - "signature" => $signature]; + $message = [ + 'author' => $old_handle, + 'profile' => $profile, + 'signature' => $signature + ]; Logger::info('Send account migration', ['msg' => $message]); - return self::buildAndTransmit($owner, $contact, "account_migration", $message); + return self::buildAndTransmit($owner, $contact, 'account_migration', $message); } /** @@ -3182,7 +3211,7 @@ class Diaspora * @return int The result of the transmission * @throws \Exception */ - public static function sendShare(array $owner, array $contact) + public static function sendShare(array $owner, array $contact): int { /** * @todo support the different possible combinations of "following" and "sharing" @@ -3207,14 +3236,16 @@ class Diaspora } */ - $message = ["author" => self::myHandle($owner), - "recipient" => $contact["addr"], - "following" => "true", - "sharing" => "true"]; + $message = [ + 'author' => self::myHandle($owner), + 'recipient' => $contact['addr'], + 'following' => 'true', + 'sharing' => 'true' + ]; Logger::info('Send share', ['msg' => $message]); - return self::buildAndTransmit($owner, $contact, "contact", $message); + return self::buildAndTransmit($owner, $contact, 'contact', $message); } /** @@ -3226,16 +3257,18 @@ class Diaspora * @return int The result of the transmission * @throws \Exception */ - public static function sendUnshare(array $owner, array $contact) + public static function sendUnshare(array $owner, array $contact): int { - $message = ["author" => self::myHandle($owner), - "recipient" => $contact["addr"], - "following" => "false", - "sharing" => "false"]; + $message = [ + 'author' => self::myHandle($owner), + 'recipient' => $contact['addr'], + 'following' => 'false', + 'sharing' => 'false' + ]; Logger::info('Send unshare', ['msg' => $message]); - return self::buildAndTransmit($owner, $contact, "contact", $message); + return self::buildAndTransmit($owner, $contact, 'contact', $message); } /** @@ -3248,7 +3281,7 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isReshare($body, $complete = true) + public static function isReshare(string $body, bool $complete = true) { $body = trim($body); @@ -3268,8 +3301,8 @@ class Diaspora $item = Post::selectFirst(['contact-id'], $condition); if (DBA::isResult($item)) { $ret = []; - $ret["root_handle"] = self::handleFromContact($item["contact-id"]); - $ret["root_guid"] = $reshared['guid']; + $ret['root_handle'] = self::handleFromContact($item['contact-id']); + $ret['root_guid'] = $reshared['guid']; return $ret; } elseif ($complete) { // We are resharing something that isn't a DFRN or Diaspora post. @@ -3304,7 +3337,7 @@ class Diaspora * @return array with event data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function buildEvent($event_id) + private static function buildEvent(string $event_id): array { $event = DBA::selectFirst('event', [], ['id' => $event_id]); if (!DBA::isResult($event)) { @@ -3327,7 +3360,7 @@ class Diaspora $mask = DateTimeFormat::ATOM; /// @todo - establish "all day" events in Friendica - $eventdata["all_day"] = "false"; + $eventdata['all_day'] = 'false'; $eventdata['timezone'] = 'UTC'; @@ -3348,13 +3381,13 @@ class Diaspora $coord = Map::getCoordinates($event['location']); $location = []; - $location["address"] = html_entity_decode(BBCode::toMarkdown($event['location'])); + $location['address'] = html_entity_decode(BBCode::toMarkdown($event['location'])); if (!empty($coord['lat']) && !empty($coord['lon'])) { - $location["lat"] = $coord['lat']; - $location["lng"] = $coord['lon']; + $location['lat'] = $coord['lat']; + $location['lng'] = $coord['lon']; } else { - $location["lat"] = 0; - $location["lng"] = 0; + $location['lat'] = 0; + $location['lng'] = 0; } $eventdata['location'] = $location; } @@ -3376,7 +3409,7 @@ class Diaspora */ public static function buildStatus(array $item, array $owner) { - $cachekey = "diaspora:buildStatus:".$item['guid']; + $cachekey = 'diaspora:buildStatus:' . $item['guid']; $result = DI::cache()->get($cachekey); if (!is_null($result)) { @@ -3385,27 +3418,29 @@ class Diaspora $myaddr = self::myHandle($owner); - $public = ($item["private"] == Item::PRIVATE ? "false" : "true"); + $public = ($item['private'] == Item::PRIVATE ? 'false' : 'true'); $created = DateTimeFormat::utc($item['received'], DateTimeFormat::ATOM); - $edited = DateTimeFormat::utc($item["edited"] ?? $item["created"], DateTimeFormat::ATOM); + $edited = DateTimeFormat::utc($item['edited'] ?? $item['created'], DateTimeFormat::ATOM); // Detect a share element and do a reshare - if (($item['private'] != Item::PRIVATE) && ($ret = self::isReshare($item["body"]))) { - $message = ["author" => $myaddr, - "guid" => $item["guid"], - "created_at" => $created, - "root_author" => $ret["root_handle"], - "root_guid" => $ret["root_guid"], - "provider_display_name" => $item["app"], - "public" => $public]; + if (($item['private'] != Item::PRIVATE) && ($ret = self::isReshare($item['body']))) { + $message = [ + 'author' => $myaddr, + 'guid' => $item['guid'], + 'created_at' => $created, + 'root_author' => $ret['root_handle'], + 'root_guid' => $ret['root_guid'], + 'provider_display_name' => $item['app'], + 'public' => $public + ]; - $type = "reshare"; + $type = 'reshare'; } else { - $title = $item["title"]; + $title = $item['title']; $body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']); // Fetch the title from an attached link - if there is one - if (empty($item["title"]) && DI::pConfig()->get($owner['uid'], 'system', 'attach_link_title')) { + if (empty($item['title']) && DI::pConfig()->get($owner['uid'], 'system', 'attach_link_title')) { $page_data = BBCode::getAttachmentData($item['body']); if (!empty($page_data['type']) && !empty($page_data['title']) && ($page_data['type'] == 'link')) { $title = $page_data['title']; @@ -3422,7 +3457,7 @@ class Diaspora // Adding the title if (strlen($title)) { - $body = "### ".html_entity_decode($title)."\n\n".$body; + $body = '### ' . html_entity_decode($title) . "\n\n" . $body; } $attachments = Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT, Post\Media::TORRENT, Post\Media::UNKNOWN]); @@ -3435,27 +3470,29 @@ class Diaspora $location = []; - if ($item["location"] != "") - $location["address"] = $item["location"]; + if ($item['location'] != '') + $location['address'] = $item['location']; - if ($item["coord"] != "") { - $coord = explode(" ", $item["coord"]); - $location["lat"] = $coord[0]; - $location["lng"] = $coord[1]; + if ($item['coord'] != '') { + $coord = explode(' ', $item['coord']); + $location['lat'] = $coord[0]; + $location['lng'] = $coord[1]; } - $message = ["author" => $myaddr, - "guid" => $item["guid"], - "created_at" => $created, - "edited_at" => $edited, - "public" => $public, - "text" => $body, - "provider_display_name" => $item["app"], - "location" => $location]; + $message = [ + 'author' => $myaddr, + 'guid' => $item['guid'], + 'created_at' => $created, + 'edited_at' => $edited, + 'public' => $public, + 'text' => $body, + 'provider_display_name' => $item['app'], + 'location' => $location + ]; // Diaspora rejects messages when they contain a location without "lat" or "lng" - if (!isset($location["lat"]) || !isset($location["lng"])) { - unset($message["location"]); + if (!isset($location['lat']) || !isset($location['lng'])) { + unset($message['location']); } if ($item['event-id'] > 0) { @@ -3474,17 +3511,20 @@ class Diaspora } } - $type = "status_message"; + $type = 'status_message'; } - $msg = ["type" => $type, "message" => $message]; + $msg = [ + 'type' => $type, + 'message' => $message + ]; DI::cache()->set($cachekey, $msg, Duration::QUARTER_HOUR); return $msg; } - private static function prependParentAuthorMention($body, $profile_url) + private static function prependParentAuthorMention(string $body, string $profile_url): string { $profile = Contact::getByURL($profile_url, false, ['addr', 'name']); if (!empty($profile['addr']) @@ -3509,11 +3549,11 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function sendStatus(array $item, array $owner, array $contact, $public_batch = false) + public static function sendStatus(array $item, array $owner, array $contact, bool $public_batch = false): int { $status = self::buildStatus($item, $owner); - return self::buildAndTransmit($owner, $contact, $status["type"], $status["message"], $public_batch, $item["guid"]); + return self::buildAndTransmit($owner, $contact, $status['type'], $status['message'], $public_batch, $item['guid']); } /** @@ -3522,30 +3562,32 @@ class Diaspora * @param array $item The item that will be exported * @param array $owner the array of the item owner * - * @return array The data for a "like" + * @return array|bool The data for a "like" or false on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function constructLike(array $item, array $owner) { - $parent = Post::selectFirst(['guid', 'uri', 'thr-parent'], ['uri' => $item["thr-parent"]]); + $parent = Post::selectFirst(['guid', 'uri', 'thr-parent'], ['uri' => $item['thr-parent']]); if (!DBA::isResult($parent)) { return false; } - $target_type = ($parent["uri"] === $parent["thr-parent"] ? "Post" : "Comment"); + $target_type = ($parent['uri'] === $parent['thr-parent'] ? 'Post' : 'Comment'); $positive = null; if ($item['verb'] === Activity::LIKE) { - $positive = "true"; + $positive = 'true'; } elseif ($item['verb'] === Activity::DISLIKE) { - $positive = "false"; + $positive = 'false'; } - return(["author" => self::myHandle($owner), - "guid" => $item["guid"], - "parent_guid" => $parent["guid"], - "parent_type" => $target_type, - "positive" => $positive, - "author_signature" => ""]); + return [ + 'author' => self::myHandle($owner), + 'guid' => $item['guid'], + 'parent_guid' => $parent['guid'], + 'parent_type' => $target_type, + 'positive' => $positive, + 'author_signature' => '' + ]; } /** @@ -3554,7 +3596,7 @@ class Diaspora * @param array $item The item that will be exported * @param array $owner the array of the item owner * - * @return array The data for an "EventParticipation" + * @return array|bool The data for an "EventParticipation" or false on error * @throws \Exception */ private static function constructAttend(array $item, array $owner) @@ -3579,11 +3621,13 @@ class Diaspora return false; } - return(["author" => self::myHandle($owner), - "guid" => $item["guid"], - "parent_guid" => $parent["guid"], - "status" => $attend_answer, - "author_signature" => ""]); + return [ + 'author' => self::myHandle($owner), + 'guid' => $item['guid'], + 'parent_guid' => $parent['guid'], + 'status' => $attend_answer, + 'author_signature' => '' + ]; } /** @@ -3597,7 +3641,7 @@ class Diaspora */ private static function constructComment(array $item, array $owner) { - $cachekey = "diaspora:constructComment:".$item['guid']; + $cachekey = 'diaspora:constructComment:' . $item['guid']; $result = DI::cache()->get($cachekey); if (!is_null($result)) { @@ -3631,17 +3675,17 @@ class Diaspora } $text = html_entity_decode(BBCode::toMarkdown($body)); - $created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM); - $edited = DateTimeFormat::utc($item["edited"], DateTimeFormat::ATOM); + $created = DateTimeFormat::utc($item['created'], DateTimeFormat::ATOM); + $edited = DateTimeFormat::utc($item['edited'], DateTimeFormat::ATOM); $comment = [ - "author" => self::myHandle($owner), - "guid" => $item["guid"], - "created_at" => $created, - "edited_at" => $edited, - "parent_guid" => $toplevel_item["guid"], - "text" => $text, - "author_signature" => "" + 'author' => self::myHandle($owner), + 'guid' => $item['guid'], + 'created_at' => $created, + 'edited_at' => $edited, + 'parent_guid' => $toplevel_item['guid'], + 'text' => $text, + 'author_signature' => '' ]; // Send the thread parent guid only if it is a threaded comment @@ -3651,7 +3695,7 @@ class Diaspora DI::cache()->set($cachekey, $comment, Duration::QUARTER_HOUR); - return($comment); + return $comment; } /** @@ -3666,26 +3710,26 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function sendFollowup(array $item, array $owner, array $contact, $public_batch = false) + public static function sendFollowup(array $item, array $owner, array $contact, bool $public_batch = false): int { if (in_array($item['verb'], [Activity::ATTEND, Activity::ATTENDNO, Activity::ATTENDMAYBE])) { $message = self::constructAttend($item, $owner); - $type = "event_participation"; - } elseif (in_array($item["verb"], [Activity::LIKE, Activity::DISLIKE])) { + $type = 'event_participation'; + } elseif (in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE])) { $message = self::constructLike($item, $owner); - $type = "like"; - } elseif (!in_array($item["verb"], [Activity::FOLLOW, Activity::TAG])) { + $type = 'like'; + } elseif (!in_array($item['verb'], [Activity::FOLLOW, Activity::TAG])) { $message = self::constructComment($item, $owner); - $type = "comment"; + $type = 'comment'; } if (empty($message)) { - return false; + return -1; } - $message["author_signature"] = self::signature($owner, $message); + $message['author_signature'] = self::signature($owner, $message); - return self::buildAndTransmit($owner, $contact, $type, $message, $public_batch, $item["guid"]); + return self::buildAndTransmit($owner, $contact, $type, $message, $public_batch, $item['guid']); } /** @@ -3699,43 +3743,43 @@ class Diaspora * @return int The result of the transmission * @throws \Exception */ - public static function sendRelay(array $item, array $owner, array $contact, $public_batch = false) + public static function sendRelay(array $item, array $owner, array $contact, bool $public_batch = false): int { - if ($item["deleted"]) { + if ($item['deleted']) { return self::sendRetraction($item, $owner, $contact, $public_batch, true); - } elseif (in_array($item["verb"], [Activity::LIKE, Activity::DISLIKE])) { - $type = "like"; + } elseif (in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE])) { + $type = 'like'; } else { - $type = "comment"; + $type = 'comment'; } - Logger::info("Got relayable data ".$type." for item ".$item["guid"]." (".$item["id"].")"); + Logger::info("Got relayable data " . $type . " for item " . $item['guid'] . " (" . $item['id'] . ")"); $msg = json_decode($item['signed_text'], true); $message = []; if (is_array($msg)) { foreach ($msg as $field => $data) { - if (!$item["deleted"]) { - if ($field == "diaspora_handle") { - $field = "author"; + if (!$item['deleted']) { + if ($field == 'diaspora_handle') { + $field = 'author'; } - if ($field == "target_type") { - $field = "parent_type"; + if ($field == 'target_type') { + $field = 'parent_type'; } } $message[$field] = $data; } } else { - Logger::info("Signature text for item ".$item["guid"]." (".$item["id"].") couldn't be extracted: ".$item['signed_text']); + Logger::info("Signature text for item " . $item["guid"] . " (" . $item["id"] . ") couldn't be extracted: " . $item['signed_text']); } - $message["parent_author_signature"] = self::signature($owner, $message); + $message['parent_author_signature'] = self::signature($owner, $message); Logger::info('Relayed data', ['msg' => $message]); - return self::buildAndTransmit($owner, $contact, $type, $message, $public_batch, $item["guid"]); + return self::buildAndTransmit($owner, $contact, $type, $message, $public_batch, $item['guid']); } /** @@ -3750,27 +3794,29 @@ class Diaspora * @return int The result of the transmission * @throws \Exception */ - public static function sendRetraction(array $item, array $owner, array $contact, $public_batch = false, $relay = false) + public static function sendRetraction(array $item, array $owner, array $contact, bool $public_batch = false, bool $relay = false): int { - $itemaddr = self::handleFromContact($item["contact-id"], $item["author-id"]); + $itemaddr = self::handleFromContact($item['contact-id'], $item['author-id']); - $msg_type = "retraction"; + $msg_type = 'retraction'; if ($item['gravity'] == GRAVITY_PARENT) { - $target_type = "Post"; - } elseif (in_array($item["verb"], [Activity::LIKE, Activity::DISLIKE])) { - $target_type = "Like"; + $target_type = 'Post'; + } elseif (in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE])) { + $target_type = 'Like'; } else { - $target_type = "Comment"; + $target_type = 'Comment'; } - $message = ["author" => $itemaddr, - "target_guid" => $item['guid'], - "target_type" => $target_type]; + $message = [ + 'author' => $itemaddr, + 'target_guid' => $item['guid'], + 'target_type' => $target_type + ]; Logger::info('Got message', ['msg' => $message]); - return self::buildAndTransmit($owner, $contact, $msg_type, $message, $public_batch, $item["guid"]); + return self::buildAndTransmit($owner, $contact, $msg_type, $message, $public_batch, $item['guid']); } /** @@ -3784,44 +3830,44 @@ class Diaspora * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function sendMail(array $item, array $owner, array $contact) + public static function sendMail(array $item, array $owner, array $contact): int { $myaddr = self::myHandle($owner); - $cnv = DBA::selectFirst('conv', [], ['id' => $item["convid"], 'uid' => $item["uid"]]); + $cnv = DBA::selectFirst('conv', [], ['id' => $item['convid'], 'uid' => $item['uid']]); if (!DBA::isResult($cnv)) { Logger::notice("conversation not found."); - return; + return -1; } - $body = BBCode::toMarkdown($item["body"]); - $created = DateTimeFormat::utc($item["created"], DateTimeFormat::ATOM); + $body = BBCode::toMarkdown($item['body']); + $created = DateTimeFormat::utc($item['created'], DateTimeFormat::ATOM); $msg = [ - "author" => $myaddr, - "guid" => $item["guid"], - "conversation_guid" => $cnv["guid"], - "text" => $body, - "created_at" => $created, + 'author' => $myaddr, + 'guid' => $item['guid'], + 'conversation_guid' => $cnv['guid'], + 'text' => $body, + 'created_at' => $created, ]; - if ($item["reply"]) { + if ($item['reply']) { $message = $msg; - $type = "message"; + $type = 'message'; } else { $message = [ - "author" => $cnv["creator"], - "guid" => $cnv["guid"], - "subject" => $cnv["subject"], - "created_at" => DateTimeFormat::utc($cnv['created'], DateTimeFormat::ATOM), - "participants" => $cnv["recips"], - "message" => $msg + 'author' => $cnv['creator'], + 'guid' => $cnv['guid'], + 'subject' => $cnv['subject'], + 'created_at' => DateTimeFormat::utc($cnv['created'], DateTimeFormat::ATOM), + 'participants' => $cnv['recips'], + 'message' => $msg ]; - $type = "conversation"; + $type = 'conversation'; } - return self::buildAndTransmit($owner, $contact, $type, $message, false, $item["guid"]); + return self::buildAndTransmit($owner, $contact, $type, $message, false, $item['guid']); } /** @@ -3831,7 +3877,8 @@ class Diaspora * * @return array The array with "first" and "last" */ - public static function splitName($name) { + public static function splitName(string $name): array + { $name = trim($name); // Is the name longer than 64 characters? Then cut the rest of it. @@ -3888,14 +3935,14 @@ class Diaspora * @return array The profile data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function createProfileData($uid) + private static function createProfileData(int $uid): array { $profile = DBA::selectFirst('owner-view', ['uid', 'addr', 'name', 'location', 'net-publish', 'dob', 'about', 'pub_keywords'], ['uid' => $uid]); if (!DBA::isResult($profile)) { return []; } - $handle = $profile["addr"]; + $handle = $profile['addr']; $split_name = self::splitName($profile['name']); $first = $split_name['first']; @@ -3940,18 +3987,20 @@ class Diaspora $tags = trim($tags); } - return ["author" => $handle, - "first_name" => $first, - "last_name" => $last, - "image_url" => $large, - "image_url_medium" => $medium, - "image_url_small" => $small, - "birthday" => $dob, - "bio" => $about, - "location" => $location, - "searchable" => $searchable, - "nsfw" => "false", - "tag_string" => $tags]; + return [ + 'author' => $handle, + 'first_name' => $first, + 'last_name' => $last, + 'image_url' => $large, + 'image_url_medium' => $medium, + 'image_url_small' => $small, + 'birthday' => $dob, + 'bio' => $about, + 'location' => $location, + 'searchable' => $searchable, + 'nsfw' => 'false', + 'tag_string' => $tags + ]; } /** @@ -3962,7 +4011,7 @@ class Diaspora * @return void * @throws \Exception */ - public static function sendProfile($uid, $recips = false) + public static function sendProfile(int $uid, bool $recips = false) { if (!$uid) { return; @@ -3985,8 +4034,8 @@ class Diaspora // @ToDo Split this into single worker jobs foreach ($recips as $recip) { - Logger::info("Send updated profile data for user ".$uid." to contact ".$recip["id"]); - self::buildAndTransmit($owner, $recip, "profile", $message); + Logger::info("Send updated profile data for user " . $uid . " to contact " . $recip['id']); + self::buildAndTransmit($owner, $recip, 'profile', $message); } } @@ -3996,10 +4045,10 @@ class Diaspora * @param integer $uid The user of that comment * @param array $item Item array * - * @return array Signed content + * @return array|bool Signed content or false on error * @throws \Exception */ - public static function createLikeSignature($uid, array $item) + public static function createLikeSignature(int $uid, array $item) { $owner = User::getOwnerDataById($uid); if (empty($owner)) { @@ -4007,7 +4056,7 @@ class Diaspora return false; } - if (!in_array($item["verb"], [Activity::LIKE, Activity::DISLIKE])) { + if (!in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE])) { return false; } @@ -4016,7 +4065,7 @@ class Diaspora return false; } - $message["author_signature"] = self::signature($owner, $message); + $message['author_signature'] = self::signature($owner, $message); return $message; } @@ -4026,7 +4075,7 @@ class Diaspora * * @param array $item Item array * - * @return array Signed content + * @return array|bool Signed content or false on error * @throws \Exception */ public static function createCommentSignature(array $item) @@ -4064,12 +4113,12 @@ class Diaspora return false; } - $message["author_signature"] = self::signature($owner, $message); + $message['author_signature'] = self::signature($owner, $message); return $message; } - public static function performReshare(int $UriId, int $uid) + public static function performReshare(int $UriId, int $uid): int { $fields = ['uri-id', 'body', 'title', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink']; $item = Post::selectFirst($fields, ['uri-id' => $UriId, 'uid' => [$uid, 0], 'private' => [Item::PUBLIC, Item::UNLISTED]]); diff --git a/src/Protocol/Email.php b/src/Protocol/Email.php index db22b76973..7584518449 100644 --- a/src/Protocol/Email.php +++ b/src/Protocol/Email.php @@ -38,10 +38,10 @@ class Email * @param string $mailbox The mailbox name * @param string $username The username * @param string $password The password - * @return Connection|resource + * @return Connection|resource|bool * @throws \Exception */ - public static function connect($mailbox, $username, $password) + public static function connect(string $mailbox, string $username, string $password) { if (!function_exists('imap_open')) { return false; @@ -68,7 +68,7 @@ class Email * @return array * @throws \Exception */ - public static function poll($mbox, $email_addr): array + public static function poll($mbox, string $email_addr): array { if (!$mbox || !$email_addr) { return []; @@ -101,10 +101,12 @@ class Email } /** + * Returns mailbox name + * * @param array $mailacct mail account * @return string */ - public static function constructMailboxName($mailacct) + public static function constructMailboxName(array $mailacct): string { $ret = '{' . $mailacct['server'] . ((intval($mailacct['port'])) ? ':' . $mailacct['port'] : ''); $ret .= (($mailacct['ssltype']) ? '/' . $mailacct['ssltype'] . '/novalidate-cert' : ''); @@ -117,7 +119,7 @@ class Email * @param integer $uid user id * @return mixed */ - public static function messageMeta($mbox, $uid) + public static function messageMeta($mbox, int $uid) { $ret = (($mbox && $uid) ? @imap_fetch_overview($mbox, $uid, FT_UID) : [[]]); // POSSIBLE CLEANUP --> array(array()) is probably redundant now return (count($ret)) ? $ret : []; @@ -127,10 +129,11 @@ class Email * @param Connection|resource $mbox mailbox * @param integer $uid user id * @param string $reply reply + * @param array $item Item * @return array * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getMessage($mbox, $uid, $reply, $item): array + public static function getMessage($mbox, int $uid, string $reply, array $item): array { $ret = $item; @@ -218,7 +221,7 @@ class Email * @param string $subtype sub type * @return string */ - private static function messageGetPart($mbox, $uid, $p, $partno, $subtype) + private static function messageGetPart($mbox, int $uid, $p, int $partno, string $subtype): string { // $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple global $htmlmsg,$plainmsg,$charset,$attachments; @@ -296,11 +299,13 @@ class Email } /** + * Returns encoded header + * * @param string $in_str in string * @param string $charset character set * @return string */ - public static function encodeHeader($in_str, $charset) + public static function encodeHeader(string $in_str, string $charset): string { $out_str = $in_str; $need_to_convert = false; @@ -360,21 +365,20 @@ class Email * @param string $subject subject * @param string $headers headers * @param array $item item - * - * @return void + * @return bool Status from mail() * * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException * @todo This could be changed to use the Emailer class */ - public static function send($addr, $subject, $headers, $item) + public static function send(string $addr, string $subject, string $headers, array$item) { //$headers .= 'MIME-Version: 1.0' . "\n"; //$headers .= 'Content-Type: text/html; charset=UTF-8' . "\n"; //$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\n"; //$headers .= 'Content-Transfer-Encoding: 8bit' . "\n\n"; - $part = uniqid("", true); + $part = uniqid('', true); $html = Item::prepareBody($item); @@ -398,52 +402,70 @@ class Email //$message = '' . $html . ''; //$message = html2plain($html); Logger::notice('notifier: email delivery to ' . $addr); - mail($addr, $subject, $body, $headers); + return mail($addr, $subject, $body, $headers); } /** - * @param string $iri string - * @return string + * Convert item URI to message id + * + * @param string $itemUri Item URI + * @return string Message id */ - public static function iri2msgid($iri) + public static function iri2msgid(string $itemUri): string { - if (!strpos($iri, "@")) { - $msgid = preg_replace("/urn:(\S+):(\S+)\.(\S+):(\d+):(\S+)/i", "urn!$1!$4!$5@$2.$3", $iri); - } else { - $msgid = $iri; + $msgid = $itemUri; + + if (!strpos($itemUri, '@')) { + $msgid = preg_replace("/urn:(\S+):(\S+)\.(\S+):(\d+):(\S+)/i", "urn!$1!$4!$5@$2.$3", $itemUri); } return $msgid; } /** - * @param string $msgid msgid - * @return string + * Converts message id to item URI + * + * @param string $msgid Message id + * @return string Item URI */ - public static function msgid2iri($msgid) + public static function msgid2iri(string $msgid): string { - if (strpos($msgid, "@")) { - $iri = preg_replace("/urn!(\S+)!(\d+)!(\S+)@(\S+)\.(\S+)/i", "urn:$1:$4.$5:$2:$3", $msgid); - } else { - $iri = $msgid; + $itemUri = $msgid; + + if (strpos($msgid, '@')) { + $itemUri = preg_replace("/urn!(\S+)!(\d+)!(\S+)@(\S+)\.(\S+)/i", "urn:$1:$4.$5:$2:$3", $msgid); } - return $iri; + return $itemUri; } - private static function saveReplace($pattern, $replace, $text) + /** + * Invokes preg_replace() but does return full text from parameter if it + * returned an empty message. + * + * @param string $pattern Pattern to match + * @param string $replace String to replace with + * @param string $text String to check + * @return string Replaced string + */ + private static function saveReplace(string $pattern, string $replace, string $text): string { - $save = $text; + $return = preg_replace($pattern, $replace, $text); - $text = preg_replace($pattern, $replace, $text); - - if ($text == '') { - $text = $save; + if ($return == '') { + $return = $text; } - return $text; + + return $return; } - private static function unifyAttributionLine($message) + /** + * Unifies attribution line(s) + * + * @param string $message Unfiltered message + * @return string Message with unified attribution line(s) + */ + private static function unifyAttributionLine(string $message): string { $quotestr = ['quote', 'spoiler']; foreach ($quotestr as $quote) { @@ -520,7 +542,13 @@ class Email return $message; } - private static function removeGPG($message) + /** + * Removes GPG part from message + * + * @param string $message Unfiltered message + * @return string Message with GPG part + */ + private static function removeGPG(string $message): string { $pattern = '/(.*)\s*-----BEGIN PGP SIGNED MESSAGE-----\s*[\r\n].*Hash:.*?[\r\n](.*)'. '[\r\n]\s*-----BEGIN PGP SIGNATURE-----\s*[\r\n].*'. @@ -537,7 +565,13 @@ class Email return $cleaned; } - private static function removeSig($message) + /** + * Removes signature from message + * + * @param string $message Unfiltered message + * @return string Message with no signature + */ + private static function removeSig(string $message): string { $sigpos = strrpos($message, "\n-- \n"); $quotepos = strrpos($message, "[/quote]"); @@ -569,7 +603,13 @@ class Email return ['body' => $cleaned, 'sig' => $sig]; } - private static function removeLinebreak($message) + /** + * Removes lines breaks from message + * + * @param string $message Unfiltered message + * @return string Message with no line breaks + */ + private static function removeLinebreak(string $message): string { $arrbody = explode("\n", trim($message)); @@ -622,7 +662,7 @@ class Email return implode("\n", $lines); } - private static function convertQuote($body, $reply) + private static function convertQuote(strng $body, string $reply): string { // Convert Quotes $arrbody = explode("\n", trim($body)); @@ -682,14 +722,14 @@ class Email return $body; } - private static function removeToFu($message) + private static function removeToFu(string $message): string { $message = trim($message); do { $oldmessage = $message; $message = preg_replace('=\[/quote\][\s](.*?)\[quote\]=i', '$1', $message); - $message = str_replace("[/quote][quote]", "", $message); + $message = str_replace('[/quote][quote]', '', $message); } while ($message != $oldmessage); $quotes = []; @@ -724,8 +764,9 @@ class Email $start = $pos + 7; } - if (strtolower(substr($message, -8)) != '[/quote]') + if (strtolower(substr($message, -8)) != '[/quote]') { return($message); + } krsort($quotes); @@ -739,7 +780,7 @@ class Email } if ($quotestart != 0) { - $message = trim(substr($message, 0, $quotestart))."\n[spoiler]".substr($message, $quotestart+7, -8).'[/spoiler]'; + $message = trim(substr($message, 0, $quotestart))."\n[spoiler]".substr($message, $quotestart+7, -8) . '[/spoiler]'; } return $message; diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index cde81394d3..6601a2e8c3 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -22,6 +22,7 @@ namespace Friendica\Protocol; use DOMDocument; +use DOMElement; use DOMXPath; use Friendica\Content\PageInfo; use Friendica\Content\Text\BBCode; @@ -59,14 +60,14 @@ class Feed * @return array Returns the header and the first item in dry run mode * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function import($xml, array $importer = [], array $contact = []) + public static function import(string $xml, array $importer = [], array $contact = []): array { $dryRun = empty($importer) && empty($contact); if ($dryRun) { Logger::info("Test Atom/RSS feed"); } else { - Logger::info("Import Atom/RSS feed '" . $contact["name"] . "' (Contact " . $contact["id"] . ") for user " . $importer["uid"]); + Logger::info('Import Atom/RSS feed "' . $contact['name'] . '" (Contact ' . $contact['id'] . ') for user ' . $importer['uid']); } $xml = trim($xml); @@ -88,11 +89,11 @@ class Feed @$doc->loadXML($xml); $xpath = new DOMXPath($doc); $xpath->registerNamespace('atom', ActivityNamespace::ATOM1); - $xpath->registerNamespace('dc', "http://purl.org/dc/elements/1.1/"); - $xpath->registerNamespace('content', "http://purl.org/rss/1.0/modules/content/"); - $xpath->registerNamespace('rdf', "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); - $xpath->registerNamespace('rss', "http://purl.org/rss/1.0/"); - $xpath->registerNamespace('media', "http://search.yahoo.com/mrss/"); + $xpath->registerNamespace('dc', 'http://purl.org/dc/elements/1.1/'); + $xpath->registerNamespace('content', 'http://purl.org/rss/1.0/modules/content/'); + $xpath->registerNamespace('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); + $xpath->registerNamespace('rss', 'http://purl.org/rss/1.0/'); + $xpath->registerNamespace('media', 'http://search.yahoo.com/mrss/'); $xpath->registerNamespace('poco', ActivityNamespace::POCO); $author = []; @@ -100,11 +101,11 @@ class Feed // Is it RDF? if ($xpath->query('/rdf:RDF/rss:channel')->length > 0) { - $author["author-link"] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:link/text()'); - $author["author-name"] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:title/text()'); + $author['author-link'] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:link/text()'); + $author['author-name'] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:title/text()'); - if (empty($author["author-name"])) { - $author["author-name"] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:description/text()'); + if (empty($author['author-name'])) { + $author['author-name'] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:description/text()'); } $entries = $xpath->query('/rdf:RDF/rss:item'); } @@ -114,150 +115,150 @@ class Feed $alternate = XML::getFirstAttributes($xpath, "atom:link[@rel='alternate']"); if (is_object($alternate)) { foreach ($alternate as $attribute) { - if ($attribute->name == "href") { - $author["author-link"] = $attribute->textContent; + if ($attribute->name == 'href') { + $author['author-link'] = $attribute->textContent; } } } - if (empty($author["author-link"])) { + if (empty($author['author-link'])) { $self = XML::getFirstAttributes($xpath, "atom:link[@rel='self']"); if (is_object($self)) { foreach ($self as $attribute) { - if ($attribute->name == "href") { - $author["author-link"] = $attribute->textContent; + if ($attribute->name == 'href') { + $author['author-link'] = $attribute->textContent; } } } } - if (empty($author["author-link"])) { - $author["author-link"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:id/text()'); + if (empty($author['author-link'])) { + $author['author-link'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:id/text()'); } - $author["author-avatar"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:logo/text()'); + $author['author-avatar'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:logo/text()'); - $author["author-name"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:title/text()'); + $author['author-name'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:title/text()'); - if (empty($author["author-name"])) { - $author["author-name"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:subtitle/text()'); + if (empty($author['author-name'])) { + $author['author-name'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:subtitle/text()'); } - if (empty($author["author-name"])) { - $author["author-name"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:author/atom:name/text()'); + if (empty($author['author-name'])) { + $author['author-name'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:author/atom:name/text()'); } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:displayName/text()'); - if ($value != "") { - $author["author-name"] = $value; + if ($value != '') { + $author['author-name'] = $value; } if ($dryRun) { - $author["author-id"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:author/atom:id/text()'); + $author['author-id'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:author/atom:id/text()'); // See https://tools.ietf.org/html/rfc4287#section-3.2.2 $value = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()'); - if ($value != "") { - $author["author-link"] = $value; + if ($value != '') { + $author['author-link'] = $value; } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:preferredUsername/text()'); - if ($value != "") { - $author["author-nick"] = $value; + if ($value != '') { + $author['author-nick'] = $value; } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:address/poco:formatted/text()'); - if ($value != "") { - $author["author-location"] = $value; + if ($value != '') { + $author['author-location'] = $value; } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:note/text()'); - if ($value != "") { - $author["author-about"] = $value; + if ($value != '') { + $author['author-about'] = $value; } $avatar = XML::getFirstAttributes($xpath, "atom:author/atom:link[@rel='avatar']"); if (is_object($avatar)) { foreach ($avatar as $attribute) { - if ($attribute->name == "href") { - $author["author-avatar"] = $attribute->textContent; + if ($attribute->name == 'href') { + $author['author-avatar'] = $attribute->textContent; } } } } - $author["edited"] = $author["created"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:updated/text()'); + $author['edited'] = $author['created'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:updated/text()'); - $author["app"] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:generator/text()'); + $author['app'] = XML::getFirstNodeValue($xpath, '/atom:feed/atom:generator/text()'); $entries = $xpath->query('/atom:feed/atom:entry'); } // Is it RSS? if ($xpath->query('/rss/channel')->length > 0) { - $author["author-link"] = XML::getFirstNodeValue($xpath, '/rss/channel/link/text()'); + $author['author-link'] = XML::getFirstNodeValue($xpath, '/rss/channel/link/text()'); - $author["author-name"] = XML::getFirstNodeValue($xpath, '/rss/channel/title/text()'); + $author['author-name'] = XML::getFirstNodeValue($xpath, '/rss/channel/title/text()'); - if (empty($author["author-name"])) { - $author["author-name"] = XML::getFirstNodeValue($xpath, '/rss/channel/copyright/text()'); + if (empty($author['author-name'])) { + $author['author-name'] = XML::getFirstNodeValue($xpath, '/rss/channel/copyright/text()'); } - if (empty($author["author-name"])) { - $author["author-name"] = XML::getFirstNodeValue($xpath, '/rss/channel/description/text()'); + if (empty($author['author-name'])) { + $author['author-name'] = XML::getFirstNodeValue($xpath, '/rss/channel/description/text()'); } - $author["author-avatar"] = XML::getFirstNodeValue($xpath, '/rss/channel/image/url/text()'); + $author['author-avatar'] = XML::getFirstNodeValue($xpath, '/rss/channel/image/url/text()'); - if (empty($author["author-avatar"])) { - $avatar = XML::getFirstAttributes($xpath, "/rss/channel/itunes:image"); + if (empty($author['author-avatar'])) { + $avatar = XML::getFirstAttributes($xpath, '/rss/channel/itunes:image'); if (is_object($avatar)) { foreach ($avatar as $attribute) { - if ($attribute->name == "href") { - $author["author-avatar"] = $attribute->textContent; + if ($attribute->name == 'href') { + $author['author-avatar'] = $attribute->textContent; } } } } - $author["author-about"] = HTML::toBBCode(XML::getFirstNodeValue($xpath, '/rss/channel/description/text()'), $basepath); + $author['author-about'] = HTML::toBBCode(XML::getFirstNodeValue($xpath, '/rss/channel/description/text()'), $basepath); - if (empty($author["author-about"])) { - $author["author-about"] = XML::getFirstNodeValue($xpath, '/rss/channel/itunes:summary/text()'); + if (empty($author['author-about'])) { + $author['author-about'] = XML::getFirstNodeValue($xpath, '/rss/channel/itunes:summary/text()'); } - $author["edited"] = $author["created"] = XML::getFirstNodeValue($xpath, '/rss/channel/pubDate/text()'); + $author['edited'] = $author['created'] = XML::getFirstNodeValue($xpath, '/rss/channel/pubDate/text()'); - $author["app"] = XML::getFirstNodeValue($xpath, '/rss/channel/generator/text()'); + $author['app'] = XML::getFirstNodeValue($xpath, '/rss/channel/generator/text()'); $entries = $xpath->query('/rss/channel/item'); } if (!$dryRun) { - $author["author-link"] = $contact["url"]; + $author['author-link'] = $contact['url']; - if (empty($author["author-name"])) { - $author["author-name"] = $contact["name"]; + if (empty($author['author-name'])) { + $author['author-name'] = $contact['name']; } - $author["author-avatar"] = $contact["thumb"]; + $author['author-avatar'] = $contact['thumb']; - $author["owner-link"] = $contact["url"]; - $author["owner-name"] = $contact["name"]; - $author["owner-avatar"] = $contact["thumb"]; + $author['owner-link'] = $contact['url']; + $author['owner-name'] = $contact['name']; + $author['owner-avatar'] = $contact['thumb']; } $header = []; - $header["uid"] = $importer["uid"] ?? 0; - $header["network"] = Protocol::FEED; - $header["wall"] = 0; - $header["origin"] = 0; - $header["gravity"] = GRAVITY_PARENT; - $header["private"] = Item::PUBLIC; - $header["verb"] = Activity::POST; - $header["object-type"] = Activity\ObjectType::NOTE; - $header["post-type"] = Item::PT_ARTICLE; + $header['uid'] = $importer['uid'] ?? 0; + $header['network'] = Protocol::FEED; + $header['wall'] = 0; + $header['origin'] = 0; + $header['gravity'] = GRAVITY_PARENT; + $header['private'] = Item::PUBLIC; + $header['verb'] = Activity::POST; + $header['object-type'] = Activity\ObjectType::NOTE; + $header['post-type'] = Item::PT_ARTICLE; - $header["contact-id"] = $contact["id"] ?? 0; + $header['contact-id'] = $contact['id'] ?? 0; if (!is_object($entries)) { Logger::info("There are no entries in this feed."); @@ -284,64 +285,64 @@ class Feed $alternate = XML::getFirstAttributes($xpath, "atom:link[@rel='alternate']", $entry); if (!is_object($alternate)) { - $alternate = XML::getFirstAttributes($xpath, "atom:link", $entry); + $alternate = XML::getFirstAttributes($xpath, 'atom:link', $entry); } if (is_object($alternate)) { foreach ($alternate as $attribute) { - if ($attribute->name == "href") { - $item["plink"] = $attribute->textContent; + if ($attribute->name == 'href') { + $item['plink'] = $attribute->textContent; } } } - if (empty($item["plink"])) { - $item["plink"] = XML::getFirstNodeValue($xpath, 'link/text()', $entry); + if (empty($item['plink'])) { + $item['plink'] = XML::getFirstNodeValue($xpath, 'link/text()', $entry); } - if (empty($item["plink"])) { - $item["plink"] = XML::getFirstNodeValue($xpath, 'rss:link/text()', $entry); + if (empty($item['plink'])) { + $item['plink'] = XML::getFirstNodeValue($xpath, 'rss:link/text()', $entry); } // Add the base path if missing - $item["plink"] = Network::addBasePath($item["plink"], $basepath); + $item['plink'] = Network::addBasePath($item['plink'], $basepath); - $item["uri"] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry); + $item['uri'] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry); $guid = XML::getFirstNodeValue($xpath, 'guid/text()', $entry); if (!empty($guid)) { - $item["uri"] = $guid; + $item['uri'] = $guid; // Don't use the GUID value directly but instead use it as a basis for the GUID - $item["guid"] = Item::guidFromUri($guid, parse_url($guid, PHP_URL_HOST) ?? parse_url($item["plink"], PHP_URL_HOST)); + $item['guid'] = Item::guidFromUri($guid, parse_url($guid, PHP_URL_HOST) ?? parse_url($item['plink'], PHP_URL_HOST)); } - if (empty($item["uri"])) { - $item["uri"] = $item["plink"]; + if (empty($item['uri'])) { + $item['uri'] = $item['plink']; } - $orig_plink = $item["plink"]; + $orig_plink = $item['plink']; try { - $item["plink"] = DI::httpClient()->finalUrl($item["plink"]); + $item['plink'] = DI::httpClient()->finalUrl($item['plink']); } catch (TransferException $exception) { - Logger::notice('Item URL couldn\'t get expanded', ['url' => $item["plink"], 'exception' => $exception]); + Logger::notice('Item URL couldn\'t get expanded', ['url' => $item['plink'], 'exception' => $exception]); } - $item["title"] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); + $item['title'] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); - if (empty($item["title"])) { - $item["title"] = XML::getFirstNodeValue($xpath, 'title/text()', $entry); + if (empty($item['title'])) { + $item['title'] = XML::getFirstNodeValue($xpath, 'title/text()', $entry); } - if (empty($item["title"])) { - $item["title"] = XML::getFirstNodeValue($xpath, 'rss:title/text()', $entry); + if (empty($item['title'])) { + $item['title'] = XML::getFirstNodeValue($xpath, 'rss:title/text()', $entry); } - if (empty($item["title"])) { - $item["title"] = XML::getFirstNodeValue($xpath, 'itunes:title/text()', $entry); + if (empty($item['title'])) { + $item['title'] = XML::getFirstNodeValue($xpath, 'itunes:title/text()', $entry); } - $item["title"] = html_entity_decode($item["title"], ENT_QUOTES, 'UTF-8'); + $item['title'] = html_entity_decode($item['title'], ENT_QUOTES, 'UTF-8'); $published = XML::getFirstNodeValue($xpath, 'atom:published/text()', $entry); @@ -363,22 +364,22 @@ class Feed $published = $updated; } - if ($published != "") { - $item["created"] = $published; + if ($published != '') { + $item['created'] = $published; } - if ($updated != "") { - $item["edited"] = $updated; + if ($updated != '') { + $item['edited'] = $updated; } if (!$dryRun) { $condition = ["`uid` = ? AND `uri` = ? AND `network` IN (?, ?)", - $importer["uid"], $item["uri"], Protocol::FEED, Protocol::DFRN]; + $importer['uid'], $item['uri'], Protocol::FEED, Protocol::DFRN]; $previous = Post::selectFirst(['id', 'created'], $condition); if (DBA::isResult($previous)) { // Use the creation date when the post had been stored. It can happen this date changes in the feed. $creation_dates[] = $previous['created']; - Logger::info("Item with uri " . $item["uri"] . " for user " . $importer["uid"] . " already existed under id " . $previous["id"]); + Logger::info('Item with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . ' already existed under id ' . $previous['id']); continue; } $creation_dates[] = DateTimeFormat::utc($item['created']); @@ -394,14 +395,14 @@ class Feed $creator = XML::getFirstNodeValue($xpath, 'dc:creator/text()', $entry); } - if ($creator != "") { - $item["author-name"] = $creator; + if ($creator != '') { + $item['author-name'] = $creator; } $creator = XML::getFirstNodeValue($xpath, 'dc:creator/text()', $entry); - if ($creator != "") { - $item["author-name"] = $creator; + if ($creator != '') { + $item['author-name'] = $creator; } /// @TODO ? @@ -412,16 +413,16 @@ class Feed $enclosures = $xpath->query("enclosure|atom:link[@rel='enclosure']", $entry); foreach ($enclosures as $enclosure) { - $href = ""; + $href = ''; $length = null; $type = null; foreach ($enclosure->attributes as $attribute) { - if (in_array($attribute->name, ["url", "href"])) { + if (in_array($attribute->name, ['url', 'href'])) { $href = $attribute->textContent; - } elseif ($attribute->name == "length") { + } elseif ($attribute->name == 'length') { $length = (int)$attribute->textContent; - } elseif ($attribute->name == "type") { + } elseif ($attribute->name == 'type') { $type = $attribute->textContent; } } @@ -441,7 +442,7 @@ class Feed } $taglist = []; - $categories = $xpath->query("category", $entry); + $categories = $xpath->query('category', $entry); foreach ($categories as $category) { $taglist[] = $category->nodeValue; } @@ -469,17 +470,17 @@ class Feed // remove the content of the title if it is identically to the body // This helps with auto generated titles e.g. from tumblr - if (self::titleIsBody($item["title"], $body)) { - $item["title"] = ""; + if (self::titleIsBody($item['title'], $body)) { + $item['title'] = ''; } - $item["body"] = HTML::toBBCode($body, $basepath); + $item['body'] = HTML::toBBCode($body, $basepath); // Remove tracking pixels - $item["body"] = preg_replace("/\[img=1x1\]([^\[\]]*)\[\/img\]/Usi", '', $item["body"]); + $item['body'] = preg_replace("/\[img=1x1\]([^\[\]]*)\[\/img\]/Usi", '', $item['body']); - if (($item["body"] == '') && ($item["title"] != '')) { - $item["body"] = $item["title"]; - $item["title"] = ''; + if (($item['body'] == '') && ($item['title'] != '')) { + $item['body'] = $item['title']; + $item['title'] = ''; } if ($dryRun) { @@ -495,36 +496,36 @@ class Feed } $preview = ''; - if (!empty($contact["fetch_further_information"]) && ($contact["fetch_further_information"] < 3)) { + if (!empty($contact['fetch_further_information']) && ($contact['fetch_further_information'] < 3)) { // Handle enclosures and treat them as preview picture foreach ($attachments as $attachment) { - if ($attachment["mimetype"] == "image/jpeg") { - $preview = $attachment["url"]; + if ($attachment['mimetype'] == 'image/jpeg') { + $preview = $attachment['url']; } } // Remove a possible link to the item itself - $item["body"] = str_replace($item["plink"], '', $item["body"]); - $item["body"] = trim(preg_replace('/\[url\=\](\w+.*?)\[\/url\]/i', '', $item["body"])); + $item['body'] = str_replace($item['plink'], '', $item['body']); + $item['body'] = trim(preg_replace('/\[url\=\](\w+.*?)\[\/url\]/i', '', $item['body'])); // Replace the content when the title is longer than the body - $replace = (strlen($item["title"]) > strlen($item["body"])); + $replace = (strlen($item['title']) > strlen($item['body'])); // Replace it, when there is an image in the body - if (strstr($item["body"], '[/img]')) { + if (strstr($item['body'], '[/img]')) { $replace = true; } // Replace it, when there is a link in the body - if (strstr($item["body"], '[/url]')) { + if (strstr($item['body'], '[/url]')) { $replace = true; } - $saved_body = $item["body"]; - $saved_title = $item["title"]; + $saved_body = $item['body']; + $saved_title = $item['title']; if ($replace) { - $item["body"] = trim($item["title"]); + $item['body'] = trim($item['title']); } $data = ParseUrl::getSiteinfoCached($item['plink']); @@ -539,13 +540,13 @@ class Feed } } - $data = PageInfo::queryUrl($item["plink"], false, $preview, ($contact["fetch_further_information"] == 2), $contact["ffi_keyword_denylist"] ?? ''); + $data = PageInfo::queryUrl($item['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_denylist'] ?? ''); if (!empty($data)) { // Take the data that was provided by the feed if the query is empty if (($data['type'] == 'link') && empty($data['title']) && empty($data['text'])) { $data['title'] = $saved_title; - $item["body"] = $saved_body; + $item['body'] = $saved_body; } $data_text = strip_tags(trim($data['text'] ?? '')); @@ -556,10 +557,10 @@ 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"] ?? '') : []; - $item["object-type"] = Activity\ObjectType::BOOKMARK; + $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'] ?? '') : []; + $item['object-type'] = Activity\ObjectType::BOOKMARK; $attachments = []; foreach (['audio', 'video'] as $elementname) { @@ -587,21 +588,21 @@ class Feed } } else { if (!empty($summary)) { - $item["body"] = '[abstract]' . HTML::toBBCode($summary, $basepath) . "[/abstract]\n" . $item["body"]; + $item['body'] = '[abstract]' . HTML::toBBCode($summary, $basepath) . "[/abstract]\n" . $item['body']; } - if (!empty($contact["fetch_further_information"]) && ($contact["fetch_further_information"] == 3)) { + if (!empty($contact['fetch_further_information']) && ($contact['fetch_further_information'] == 3)) { if (empty($taglist)) { - $taglist = PageInfo::getTagsFromUrl($item["plink"], $preview, $contact["ffi_keyword_denylist"] ?? ''); + $taglist = PageInfo::getTagsFromUrl($item['plink'], $preview, $contact['ffi_keyword_denylist'] ?? ''); } - $item["body"] .= "\n" . self::tagToString($taglist); + $item['body'] .= "\n" . self::tagToString($taglist); } else { $taglist = []; } // Add the link to the original feed entry if not present in feed - if (($item['plink'] != '') && !strstr($item["body"], $item['plink']) && !in_array($item['plink'], array_column($attachments, 'url'))) { - $item["body"] .= "[hr][url]" . $item['plink'] . "[/url]"; + if (($item['plink'] != '') && !strstr($item['body'], $item['plink']) && !in_array($item['plink'], array_column($attachments, 'url'))) { + $item['body'] .= '[hr][url]' . $item['plink'] . '[/url]'; } } @@ -617,7 +618,7 @@ class Feed // Additionally we have to avoid conflicts with identical URI between imported feeds and these items. if ($notify) { $item['guid'] = Item::guidFromUri($orig_plink, DI::baseUrl()->getHostname()); - $item['uri'] = Item::newURI($item['uid'], $item['guid']); + $item['uri'] = Item::newURI($item['guid']); unset($item['thr-parent']); unset($item['parent-uri']); @@ -626,7 +627,7 @@ class Feed } $condition = ['uid' => $item['uid'], 'uri' => $item['uri']]; - if (!Post::exists($condition) && !Post\Delayed::exists($item["uri"], $item['uid'])) { + if (!Post::exists($condition) && !Post\Delayed::exists($item['uri'], $item['uid'])) { if (!$notify) { Post\Delayed::publish($item, $notify, $taglist, $attachments); } else { @@ -634,7 +635,7 @@ class Feed 'taglist' => $taglist, 'attachments' => $attachments]; } } else { - Logger::info('Post already created or exists in the delayed posts queue', ['uid' => $item['uid'], 'uri' => $item["uri"]]); + Logger::info('Post already created or exists in the delayed posts queue', ['uid' => $item['uid'], 'uri' => $item['uri']]); } } @@ -677,13 +678,13 @@ class Feed self::adjustPollFrequency($contact, $creation_dates); } - return ["header" => $author, "items" => $items]; + return ['header' => $author, 'items' => $items]; } /** * Automatically adjust the poll frequency according to the post frequency * - * @param array $contact + * @param array $contact Contact array * @param array $creation_dates * @return void */ @@ -803,7 +804,7 @@ class Feed * @param array $contact * @return int Poll interval in minutes */ - public static function getPollInterval(array $contact) + public static function getPollInterval(array $contact): int { if (in_array($contact['network'], [Protocol::MAIL, Protocol::FEED])) { $ratings = [0, 3, 7, 8, 9, 10]; @@ -852,39 +853,39 @@ class Feed * @param array $tags * @return string tag string */ - private static function tagToString(array $tags) + private static function tagToString(array $tags): string { $tagstr = ''; foreach ($tags as $tag) { - if ($tagstr != "") { - $tagstr .= ", "; + if ($tagstr != '') { + $tagstr .= ', '; } - $tagstr .= "#[url=" . DI::baseUrl() . "/search?tag=" . urlencode($tag) . "]" . $tag . "[/url]"; + $tagstr .= '#[url=' . DI::baseUrl() . '/search?tag=' . urlencode($tag) . ']' . $tag . '[/url]'; } return $tagstr; } - private static function titleIsBody($title, $body) + private static function titleIsBody(string $title, string $body): bool { $title = strip_tags($title); $title = trim($title); $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8'); - $title = str_replace(["\n", "\r", "\t", " "], ["", "", "", ""], $title); + $title = str_replace(["\n", "\r", "\t", " "], ['', '', '', ''], $title); $body = strip_tags($body); $body = trim($body); $body = html_entity_decode($body, ENT_QUOTES, 'UTF-8'); - $body = str_replace(["\n", "\r", "\t", " "], ["", "", "", ""], $body); + $body = str_replace(["\n", "\r", "\t", " "], ['', '', '', ''], $body); if (strlen($title) < strlen($body)) { $body = substr($body, 0, strlen($title)); } - if (($title != $body) && (substr($title, -3) == "...")) { - $pos = strrpos($title, "..."); + if (($title != $body) && (substr($title, -3) == '...')) { + $pos = strrpos($title, '...'); if ($pos > 0) { $title = substr($title, 0, $pos); $body = substr($body, 0, $pos); @@ -914,7 +915,7 @@ class Feed * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function atom($owner_nick, $last_update, $max_items = 300, $filter = 'activity', $nocache = false) + public static function atom(string $owner_nick, string $last_update, int $max_items = 300, string $filter = 'activity', bool $nocache = false) { $stamp = microtime(true); @@ -923,7 +924,7 @@ class Feed return; } - $cachekey = "feed:feed:" . $owner_nick . ":" . $filter . ":" . $last_update; + $cachekey = 'feed:feed:' . $owner_nick . ':' . $filter . ':' . $last_update; // Display events in the users's timezone if (strlen($owner['timezone'])) { @@ -942,11 +943,11 @@ class Feed } $check_date = empty($last_update) ? '' : DateTimeFormat::utc($last_update); - $authorid = Contact::getIdForURL($owner["url"]); + $authorid = Contact::getIdForURL($owner['url']); $condition = ["`uid` = ? AND `received` > ? AND NOT `deleted` AND `gravity` IN (?, ?) AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?, ?, ?)", - $owner["uid"], $check_date, GRAVITY_PARENT, GRAVITY_COMMENT, + $owner['uid'], $check_date, GRAVITY_PARENT, GRAVITY_COMMENT, Item::PRIVATE, Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA]; @@ -957,7 +958,7 @@ class Feed if ($owner['account-type'] != User::ACCOUNT_TYPE_COMMUNITY) { $condition[0] .= " AND `contact-id` = ? AND `author-id` = ?"; - $condition[] = $owner["id"]; + $condition[] = $owner['id']; $condition[] = $authorid; } @@ -1002,16 +1003,16 @@ class Feed * @param array $owner Contact data of the poster * @param string $filter The related feed filter (activity, posts or comments) * - * @return object header root element + * @return DOMElement Header root element * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function addHeader(DOMDocument $doc, array $owner, $filter) + private static function addHeader(DOMDocument $doc, array $owner, string $filter): DOMElement { $root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed'); $doc->appendChild($root); $title = ''; - $selfUri = '/feed/' . $owner["nick"] . '/'; + $selfUri = '/feed/' . $owner['nick'] . '/'; switch ($filter) { case 'activity': $title = DI::l10n()->t('%s\'s timeline', $owner['name']); @@ -1026,24 +1027,24 @@ class Feed break; } - $attributes = ["uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION . "-" . DB_UPDATE_VERSION]; - XML::addElement($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); - XML::addElement($doc, $root, "id", DI::baseUrl() . "/profile/" . $owner["nick"]); - XML::addElement($doc, $root, "title", $title); - XML::addElement($doc, $root, "subtitle", sprintf("Updates from %s on %s", $owner["name"], DI::config()->get('config', 'sitename'))); - XML::addElement($doc, $root, "logo", User::getAvatarUrl($owner, Proxy::SIZE_SMALL)); - XML::addElement($doc, $root, "updated", DateTimeFormat::utcNow(DateTimeFormat::ATOM)); + $attributes = ['uri' => 'https://friendi.ca', 'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION]; + XML::addElement($doc, $root, 'generator', FRIENDICA_PLATFORM, $attributes); + XML::addElement($doc, $root, 'id', DI::baseUrl() . '/profile/' . $owner['nick']); + XML::addElement($doc, $root, 'title', $title); + XML::addElement($doc, $root, 'subtitle', sprintf("Updates from %s on %s", $owner['name'], DI::config()->get('config', 'sitename'))); + XML::addElement($doc, $root, 'logo', User::getAvatarUrl($owner, Proxy::SIZE_SMALL)); + XML::addElement($doc, $root, 'updated', DateTimeFormat::utcNow(DateTimeFormat::ATOM)); $author = self::addAuthor($doc, $owner); $root->appendChild($author); - $attributes = ["href" => $owner["url"], "rel" => "alternate", "type" => "text/html"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => $owner['url'], 'rel' => 'alternate', 'type' => 'text/html']; + XML::addElement($doc, $root, 'link', '', $attributes); - OStatus::hublinks($doc, $root, $owner["nick"]); + OStatus::addHubLink($doc, $root, $owner['nick']); - $attributes = ["href" => DI::baseUrl() . $selfUri, "rel" => "self", "type" => "application/atom+xml"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => DI::baseUrl() . $selfUri, 'rel' => 'self', 'type' => 'application/atom+xml']; + XML::addElement($doc, $root, 'link', '', $attributes); return $root; } @@ -1053,16 +1054,15 @@ class Feed * * @param DOMDocument $doc XML document * @param array $owner Contact data of the poster - * - * @return \DOMElement author element + * @return DOMElement author element * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function addAuthor(DOMDocument $doc, array $owner) + private static function addAuthor(DOMDocument $doc, array $owner): DOMElement { - $author = $doc->createElement("author"); - XML::addElement($doc, $author, "uri", $owner["url"]); - XML::addElement($doc, $author, "name", $owner["nick"]); - XML::addElement($doc, $author, "email", $owner["addr"]); + $author = $doc->createElement('author'); + XML::addElement($doc, $author, 'uri', $owner['url']); + XML::addElement($doc, $author, 'name', $owner['nick']); + XML::addElement($doc, $author, 'email', $owner['addr']); return $author; } @@ -1074,15 +1074,14 @@ class Feed * @param array $item Data of the item that is to be posted * @param array $owner Contact data of the poster * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? - * - * @return \DOMElement Entry element + * @return DOMElement Entry element * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function noteEntry(DOMDocument $doc, array $item, array $owner) + private static function noteEntry(DOMDocument $doc, array $item, array $owner): DOMElement { - if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { - Logger::info('Feed entry author does not match feed owner', ['owner' => $owner["url"], 'author' => $item["author-link"]]); + if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) { + Logger::info('Feed entry author does not match feed owner', ['owner' => $owner['url'], 'author' => $item['author-link']]); } $entry = OStatus::entryHeader($doc, $owner, $item, false); @@ -1104,31 +1103,30 @@ class Feed * @param string $title Title for the post * @param string $verb The activity verb * @param bool $complete Add the "status_net" element? - * @param bool $feed_mode Behave like a regular feed for users if true * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function entryContent(DOMDocument $doc, \DOMElement $entry, array $item, $title, $verb = "", $complete = true) + private static function entryContent(DOMDocument $doc, DOMElement $entry, array $item, $title, string $verb = '', bool $complete = true) { - if ($verb == "") { + if ($verb == '') { $verb = OStatus::constructVerb($item); } - XML::addElement($doc, $entry, "id", $item["uri"]); - XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8')); + XML::addElement($doc, $entry, 'id', $item['uri']); + XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8')); $body = OStatus::formatPicturePost($item['body'], $item['uri-id']); $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::ACTIVITYPUB); - XML::addElement($doc, $entry, "content", $body, ["type" => "html"]); + XML::addElement($doc, $entry, 'content', $body, ['type' => 'html']); - XML::addElement($doc, $entry, "link", "", ["rel" => "alternate", "type" => "text/html", - "href" => DI::baseUrl()."/display/".$item["guid"]] + XML::addElement($doc, $entry, 'link', '', ['rel' => 'alternate', 'type' => 'text/html', + 'href' => DI::baseUrl() . '/display/' . $item['guid']] ); - XML::addElement($doc, $entry, "published", DateTimeFormat::utc($item["created"]."+00:00", DateTimeFormat::ATOM)); - XML::addElement($doc, $entry, "updated", DateTimeFormat::utc($item["edited"]."+00:00", DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'published', DateTimeFormat::utc($item['created'] . '+00:00', DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'updated', DateTimeFormat::utc($item['edited'] . '+00:00', DateTimeFormat::ATOM)); } /** @@ -1197,28 +1195,28 @@ class Feed * @param array $item * @return string title */ - private static function getTitle(array $item) + private static function getTitle(array $item): string { if ($item['title'] != '') { return BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::ACTIVITYPUB); } // Fetch information about the post - $siteinfo = BBCode::getAttachedData($item["body"]); - if (isset($siteinfo["title"])) { - return $siteinfo["title"]; + $siteinfo = BBCode::getAttachedData($item['body']); + if (isset($siteinfo['title'])) { + return $siteinfo['title']; } // If no bookmark is found then take the first line // Remove the share element before fetching the first line - $title = trim(preg_replace("/\[share.*?\](.*?)\[\/share\]/ism","\n$1\n",$item['body'])); + $title = trim(preg_replace("/\[share.*?\](.*?)\[\/share\]/ism", "\n$1\n", $item['body'])); $title = BBCode::toPlaintext($title)."\n"; $pos = strpos($title, "\n"); - $trailer = ""; + $trailer = ''; if (($pos == 0) || ($pos > 100)) { $pos = 100; - $trailer = "..."; + $trailer = '...'; } return substr($title, 0, $pos) . $trailer; diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index fe8f060aa3..36dbb06c84 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -22,6 +22,7 @@ namespace Friendica\Protocol; use DOMDocument; +use DOMElement; use DOMXPath; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; @@ -67,24 +68,24 @@ class OStatus * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function fetchAuthor(DOMXPath $xpath, $context, array $importer, array &$contact = null, $onlyfetch) + private static function fetchAuthor(DOMXPath $xpath, $context, array $importer, array &$contact = null, bool $onlyfetch): array { $author = []; - $author["author-link"] = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context); - $author["author-name"] = XML::getFirstNodeValue($xpath, 'atom:author/atom:name/text()', $context); + $author['author-link'] = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context); + $author['author-name'] = XML::getFirstNodeValue($xpath, 'atom:author/atom:name/text()', $context); $addr = XML::getFirstNodeValue($xpath, 'atom:author/atom:email/text()', $context); - $aliaslink = $author["author-link"]; + $aliaslink = $author['author-link']; $alternate_item = $xpath->query("atom:author/atom:link[@rel='alternate']", $context)->item(0); if (is_object($alternate_item)) { foreach ($alternate_item->attributes as $attributes) { - if (($attributes->name == "href") && ($attributes->textContent != "")) { - $author["author-link"] = $attributes->textContent; + if (($attributes->name == 'href') && ($attributes->textContent != '')) { + $author['author-link'] = $attributes->textContent; } } } - $author["author-id"] = Contact::getIdForURL($author["author-link"]); + $author['author-id'] = Contact::getIdForURL($author['author-link']); $author['contact-id'] = ($contact['id'] ?? 0) ?: $author['author-id']; @@ -94,34 +95,45 @@ class OStatus This here would be better, but we would get problems with contacts from the statusnet addon This is kept here as a reminder for the future - $cid = Contact::getIdForURL($author["author-link"], $importer["uid"]); + $cid = Contact::getIdForURL($author['author-link'], $importer['uid']); if ($cid) { $contact = DBA::selectFirst('contact', [], ['id' => $cid]); } */ if ($aliaslink != '') { - $condition = ["`uid` = ? AND `alias` = ? AND `network` != ? AND `rel` IN (?, ?)", - $importer["uid"], $aliaslink, Protocol::STATUSNET, - Contact::SHARING, Contact::FRIEND]; - $contact = DBA::selectFirst('contact', [], $condition); + $contact = DBA::selectFirst('contact', [], [ + "`uid` = ? AND `alias` = ? AND `network` != ? AND `rel` IN (?, ?)", + $importer['uid'], + $aliaslink, Protocol::STATUSNET, + Contact::SHARING, Contact::FRIEND, + ]); } - if (!DBA::isResult($contact) && $author["author-link"] != '') { - if ($aliaslink == "") { - $aliaslink = $author["author-link"]; + if (!DBA::isResult($contact) && $author['author-link'] != '') { + if ($aliaslink == '') { + $aliaslink = $author['author-link']; } - $condition = ["`uid` = ? AND `nurl` IN (?, ?) AND `network` != ? AND `rel` IN (?, ?)", - $importer["uid"], Strings::normaliseLink($author["author-link"]), Strings::normaliseLink($aliaslink), - Protocol::STATUSNET, Contact::SHARING, Contact::FRIEND]; - $contact = DBA::selectFirst('contact', [], $condition); + $contact = DBA::selectFirst('contact', [], [ + "`uid` = ? AND `nurl` IN (?, ?) AND `network` != ? AND `rel` IN (?, ?)", + $importer['uid'], + Strings::normaliseLink($author['author-link']), + Strings::normaliseLink($aliaslink), + Protocol::STATUSNET, + Contact::SHARING, + Contact::FRIEND, + ]); } if (!DBA::isResult($contact) && ($addr != '')) { - $condition = ["`uid` = ? AND `addr` = ? AND `network` != ? AND `rel` IN (?, ?)", - $importer["uid"], $addr, Protocol::STATUSNET, - Contact::SHARING, Contact::FRIEND]; - $contact = DBA::selectFirst('contact', [], $condition); + $contact = DBA::selectFirst('contact', [], [ + "`uid` = ? AND `addr` = ? AND `network` != ? AND `rel` IN (?, ?)", + $importer['uid'], + $addr, + Protocol::STATUSNET, + Contact::SHARING, + Contact::FRIEND, + ]); } if (DBA::isResult($contact)) { @@ -130,40 +142,40 @@ class OStatus } elseif (!empty(APContact::getByURL($contact['url'], false))) { ActivityPub\Receiver::switchContact($contact['id'], $importer['uid'], $contact['url']); } - $author["contact-id"] = $contact["id"]; + $author['contact-id'] = $contact['id']; } $avatarlist = []; $avatars = $xpath->query("atom:author/atom:link[@rel='avatar']", $context); foreach ($avatars as $avatar) { - $href = ""; + $href = ''; $width = 0; foreach ($avatar->attributes as $attributes) { - if ($attributes->name == "href") { + if ($attributes->name == 'href') { $href = $attributes->textContent; } - if ($attributes->name == "width") { + if ($attributes->name == 'width') { $width = $attributes->textContent; } } - if ($href != "") { + if ($href != '') { $avatarlist[$width] = $href; } } if (count($avatarlist) > 0) { krsort($avatarlist); - $author["author-avatar"] = Probe::fixAvatar(current($avatarlist), $author["author-link"]); + $author['author-avatar'] = Probe::fixAvatar(current($avatarlist), $author['author-link']); } $displayname = XML::getFirstNodeValue($xpath, 'atom:author/poco:displayName/text()', $context); - if ($displayname != "") { - $author["author-name"] = $displayname; + if ($displayname != '') { + $author['author-name'] = $displayname; } - $author["owner-id"] = $author["author-id"]; + $author['owner-id'] = $author['author-id']; // Only update the contacts if it is an OStatus contact - if (DBA::isResult($contact) && ($contact['id'] > 0) && !$onlyfetch && ($contact["network"] == Protocol::OSTATUS)) { + if (DBA::isResult($contact) && ($contact['id'] > 0) && !$onlyfetch && ($contact['network'] == Protocol::OSTATUS)) { // Update contact data $current = $contact; @@ -179,41 +191,41 @@ class OStatus // if ($value != "") // $contact["poll"] = $value; - $contact['url'] = $author["author-link"]; + $contact['url'] = $author['author-link']; $contact['nurl'] = Strings::normaliseLink($contact['url']); $value = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context); - if ($value != "") { - $contact["alias"] = $value; + if ($value != '') { + $contact['alias'] = $value; } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:displayName/text()', $context); - if ($value != "") { - $contact["name"] = $value; + if ($value != '') { + $contact['name'] = $value; } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:preferredUsername/text()', $context); - if ($value != "") { - $contact["nick"] = $value; + if ($value != '') { + $contact['nick'] = $value; } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:note/text()', $context); - if ($value != "") { - $contact["about"] = HTML::toBBCode($value); + if ($value != '') { + $contact['about'] = HTML::toBBCode($value); } $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:address/poco:formatted/text()', $context); - if ($value != "") { - $contact["location"] = $value; + if ($value != '') { + $contact['location'] = $value; } $contact['name-date'] = DateTimeFormat::utcNow(); - Contact::update($contact, ['id' => $contact["id"]], $current); + Contact::update($contact, ['id' => $contact['id']], $current); - if (!empty($author["author-avatar"]) && ($author["author-avatar"] != $current['avatar'])) { - Logger::info("Update profile picture for contact ".$contact["id"]); - Contact::updateAvatar($contact["id"], $author["author-avatar"]); + if (!empty($author['author-avatar']) && ($author['author-avatar'] != $current['avatar'])) { + Logger::info('Update profile picture for contact ' . $contact['id']); + Contact::updateAvatar($contact['id'], $author['author-avatar']); } // Ensure that we are having this contact (with uid=0) @@ -224,20 +236,26 @@ class OStatus $old_contact = DBA::selectFirst('contact', $fields, ['id' => $cid]); // Update it with the current values - $fields = ['url' => $author["author-link"], 'name' => $contact["name"], - 'nurl' => Strings::normaliseLink($author["author-link"]), - 'nick' => $contact["nick"], 'alias' => $contact["alias"], - 'about' => $contact["about"], 'location' => $contact["location"], - 'success_update' => DateTimeFormat::utcNow(), 'last-update' => DateTimeFormat::utcNow()]; + $fields = [ + 'url' => $author['author-link'], + 'name' => $contact['name'], + 'nurl' => Strings::normaliseLink($author['author-link']), + 'nick' => $contact['nick'], + 'alias' => $contact['alias'], + 'about' => $contact['about'], + 'location' => $contact['location'], + 'success_update' => DateTimeFormat::utcNow(), + 'last-update' => DateTimeFormat::utcNow(), + ]; Contact::update($fields, ['id' => $cid], $old_contact); // Update the avatar - if (!empty($author["author-avatar"])) { - Contact::updateAvatar($cid, $author["author-avatar"]); + if (!empty($author['author-avatar'])) { + Contact::updateAvatar($cid, $author['author-avatar']); } } - } elseif (empty($contact["network"]) || ($contact["network"] != Protocol::DFRN)) { + } elseif (empty($contact['network']) || ($contact['network'] != Protocol::DFRN)) { $contact = []; } @@ -254,10 +272,10 @@ class OStatus * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function salmonAuthor($xml, array $importer) + public static function salmonAuthor(string $xml, array $importer): array { - if ($xml == "") { - return; + if (empty($xml)) { + return []; } $doc = new DOMDocument(); @@ -273,7 +291,7 @@ class OStatus $xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS); $xpath->registerNamespace('statusnet', ActivityNamespace::STATUSNET); - $contact = ["id" => 0]; + $contact = ['id' => 0]; // Fetch the first author $authordata = $xpath->query('//author')->item(0); @@ -285,10 +303,9 @@ class OStatus * Read attributes from element * * @param object $element Element object - * * @return array attributes */ - private static function readAttributes($element) + private static function readAttributes($element): array { $attribute = []; @@ -324,12 +341,12 @@ class OStatus * @param string $hub Called by reference, returns the fetched hub data * @param boolean $stored Is the post fresh imported or from the database? * @param boolean $initialize Is it the leading post so that data has to be initialized? - * + * @param integer $direction Direction, default UNKNOWN(0) * @return boolean Could the XML be processed? * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function process($xml, array $importer, array &$contact = null, &$hub, $stored = false, $initialize = true, $direction = Conversation::UNKNOWN) + private static function process(string $xml, array $importer, array &$contact = null, string &$hub, bool $stored = false, bool $initialize = true, int $direction = Conversation::UNKNOWN) { if ($initialize) { self::$itemlist = []; @@ -338,9 +355,10 @@ class OStatus Logger::info('Import OStatus message for user ' . $importer['uid']); - if ($xml == "") { + if (empty($xml)) { return false; } + $doc = new DOMDocument(); @$doc->loadXML($xml); @@ -354,26 +372,26 @@ class OStatus $xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS); $xpath->registerNamespace('statusnet', ActivityNamespace::STATUSNET); - $hub = ""; + $hub = ''; $hub_items = $xpath->query("/atom:feed/atom:link[@rel='hub']")->item(0); if (is_object($hub_items)) { $hub_attributes = $hub_items->attributes; if (is_object($hub_attributes)) { foreach ($hub_attributes as $hub_attribute) { - if ($hub_attribute->name == "href") { + if ($hub_attribute->name == 'href') { $hub = $hub_attribute->textContent; - Logger::info("Found hub ".$hub); + Logger::info('Found hub ', ['hub' => $hub]); } } } } $header = []; - $header["uid"] = $importer["uid"]; - $header["network"] = Protocol::OSTATUS; - $header["wall"] = 0; - $header["origin"] = 0; - $header["gravity"] = GRAVITY_COMMENT; + $header['uid'] = $importer['uid']; + $header['network'] = Protocol::OSTATUS; + $header['wall'] = 0; + $header['origin'] = 0; + $header['gravity'] = GRAVITY_COMMENT; if (!is_object($doc->firstChild) || empty($doc->firstChild->tagName)) { return false; @@ -381,7 +399,7 @@ class OStatus $first_child = $doc->firstChild->tagName; - if ($first_child == "feed") { + if ($first_child == 'feed') { $entries = $xpath->query('/atom:feed/atom:entry'); } else { $entries = $xpath->query('/atom:entry'); @@ -395,9 +413,9 @@ class OStatus $doc2->formatOutput = true; $xml2 = $doc2->saveXML(); - $header["protocol"] = Conversation::PARCEL_SALMON; - $header["source"] = $xml2; - $header["direction"] = $direction; + $header['protocol'] = Conversation::PARCEL_SALMON; + $header['source'] = $xml2; + $header['direction'] = $direction; } elseif (!$initialize) { return false; } @@ -427,67 +445,67 @@ class OStatus $item = array_merge($header, $author); - $item["uri"] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry); + $item['uri'] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry); $item['uri-id'] = ItemURI::insert(['uri' => $item['uri']]); - $item["verb"] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $entry); + $item['verb'] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $entry); // Delete a message - if (in_array($item["verb"], ['qvitter-delete-notice', Activity::DELETE, 'delete'])) { + if (in_array($item['verb'], ['qvitter-delete-notice', Activity::DELETE, 'delete'])) { self::deleteNotice($item); continue; } - if (in_array($item["verb"], [Activity::O_UNFAVOURITE, Activity::UNFAVORITE])) { + if (in_array($item['verb'], [Activity::O_UNFAVOURITE, Activity::UNFAVORITE])) { // Ignore "Unfavorite" message - Logger::info("Ignore unfavorite message ", ['item' => $item]); + Logger::info('Ignore unfavorite message ', ['item' => $item]); continue; } // Deletions come with the same uri, so we check for duplicates after processing deletions - if (Post::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]])) { - Logger::info('Post with URI '.$item["uri"].' already existed for user '.$importer["uid"].'.'); + if (Post::exists(['uid' => $importer['uid'], 'uri' => $item['uri']])) { + Logger::info('Post with URI ' . $item['uri'] . ' already existed for user ' . $importer['uid'] . '.'); continue; } else { - Logger::info('Processing post with URI '.$item["uri"].' for user '.$importer["uid"].'.'); + Logger::info('Processing post with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . '.'); } - if ($item["verb"] == Activity::JOIN) { + if ($item['verb'] == Activity::JOIN) { // ignore "Join" messages - Logger::info("Ignore join message ", ['item' => $item]); + Logger::info('Ignore join message ', ['item' => $item]); continue; } - if ($item["verb"] == "http://mastodon.social/schema/1.0/block") { + if ($item['verb'] == 'http://mastodon.social/schema/1.0/block') { // ignore mastodon "block" messages - Logger::info("Ignore block message ", ['item' => $item]); + Logger::info('Ignore block message ', ['item' => $item]); continue; } - if ($item["verb"] == Activity::FOLLOW) { + if ($item['verb'] == Activity::FOLLOW) { Contact::addRelationship($importer, $contact, $item); continue; } - if ($item["verb"] == Activity::O_UNFOLLOW) { + if ($item['verb'] == Activity::O_UNFOLLOW) { $dummy = null; Contact::removeFollower($contact); continue; } - if ($item["verb"] == Activity::FAVORITE) { - $orig_uri = $xpath->query("activity:object/atom:id", $entry)->item(0)->nodeValue; - Logger::notice("Favorite", ['uri' => $orig_uri, 'item' => $item]); + if ($item['verb'] == Activity::FAVORITE) { + $orig_uri = $xpath->query('activity:object/atom:id', $entry)->item(0)->nodeValue; + Logger::notice('Favorite', ['uri' => $orig_uri, 'item' => $item]); - $item["verb"] = Activity::LIKE; - $item["thr-parent"] = $orig_uri; - $item["gravity"] = GRAVITY_ACTIVITY; - $item["object-type"] = Activity\ObjectType::NOTE; + $item['verb'] = Activity::LIKE; + $item['thr-parent'] = $orig_uri; + $item['gravity'] = GRAVITY_ACTIVITY; + $item['object-type'] = Activity\ObjectType::NOTE; } // http://activitystrea.ms/schema/1.0/rsvp-yes - if (!in_array($item["verb"], [Activity::POST, Activity::LIKE, Activity::SHARE])) { - Logger::info("Unhandled verb", ['verb' => $item["verb"], 'item' => $item]); + if (!in_array($item['verb'], [Activity::POST, Activity::LIKE, Activity::SHARE])) { + Logger::info('Unhandled verb', ['verb' => $item['verb'], 'item' => $item]); } self::processPost($xpath, $entry, $item, $importer); @@ -503,10 +521,10 @@ class OStatus $valid = !$uid || DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_NONE; if ($valid) { - Logger::info("Item with uri ".self::$itemlist[0]['uri']." will be imported due to the system settings."); + Logger::info('Item with URI ' . self::$itemlist[0]['uri'] . ' will be imported due to the system settings.'); } } else { - Logger::info("Item with uri ".self::$itemlist[0]['uri']." belongs to a contact (".self::$itemlist[0]['contact-id']."). It will be imported."); + Logger::info('Item with URI ' . self::$itemlist[0]['uri'] . ' belongs to a contact (' . self::$itemlist[0]['contact-id'] . '). It will be imported.'); } if ($valid && DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_LIKE) { @@ -519,7 +537,7 @@ class OStatus } } if ($valid) { - Logger::info("Item with uri ".self::$itemlist[0]['uri']." will be imported since the thread contains posts or shares."); + Logger::info('Item with URI ' . self::$itemlist[0]['uri'] . ' will be imported since the thread contains posts or shares.'); } } } else { @@ -536,20 +554,20 @@ class OStatus } } foreach (self::$itemlist as $item) { - $found = Post::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]]); + $found = Post::exists(['uid' => $importer['uid'], 'uri' => $item['uri']]); if ($found) { - Logger::notice("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already exists."); + Logger::notice('Item with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . ' already exists.'); } elseif ($item['contact-id'] < 0) { - Logger::notice("Item with uri ".$item["uri"]." is from a blocked contact."); + Logger::notice('Item with URI ' . $item['uri'] . ' is from a blocked contact.'); } else { $ret = Item::insert($item); - Logger::info("Item with uri ".$item["uri"]." for user ".$importer["uid"].' stored. Return value: '.$ret); + Logger::info('Item with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . ' stored. Return value: ' . $ret); } } } self::$itemlist = []; } - Logger::info('Processing done for post with URI '.$item["uri"].' for user '.$importer["uid"].'.'); + Logger::info('Processing done for post with URI ' . $item['uri'] . ' for user '.$importer['uid'] . '.'); } return true; } @@ -565,13 +583,13 @@ class OStatus { $condition = ['uid' => $item['uid'], 'author-id' => $item['author-id'], 'uri' => $item['uri']]; if (!Post::exists($condition)) { - Logger::notice('Item from '.$item['author-link'].' with uri '.$item['uri'].' for user '.$item['uid']." wasn't found. We don't delete it."); + Logger::notice('Item from ' . $item['author-link'] . ' with uri ' . $item['uri'] . ' for user ' . $item['uid'] . " wasn't found. We don't delete it."); return; } Item::markForDeletion($condition); - Logger::notice('Deleted item with uri '.$item['uri'].' for user '.$item['uid']); + Logger::notice('Deleted item with URI ' . $item['uri'] . ' for user ' . $item['uid']); } /** @@ -587,40 +605,40 @@ class OStatus */ private static function processPost(DOMXPath $xpath, $entry, array &$item, array $importer) { - $item["body"] = HTML::toBBCode(XML::getFirstNodeValue($xpath, 'atom:content/text()', $entry)); - $item["object-type"] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $entry); - if (($item["object-type"] == Activity\ObjectType::BOOKMARK) || ($item["object-type"] == Activity\ObjectType::EVENT)) { - $item["title"] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); - $item["body"] = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $entry); - } elseif ($item["object-type"] == Activity\ObjectType::QUESTION) { - $item["title"] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); + $item['body'] = HTML::toBBCode(XML::getFirstNodeValue($xpath, 'atom:content/text()', $entry)); + $item['object-type'] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $entry); + if (($item['object-type'] == Activity\ObjectType::BOOKMARK) || ($item['object-type'] == Activity\ObjectType::EVENT)) { + $item['title'] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); + $item['body'] = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $entry); + } elseif ($item['object-type'] == Activity\ObjectType::QUESTION) { + $item['title'] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); } - $item["created"] = XML::getFirstNodeValue($xpath, 'atom:published/text()', $entry); - $item["edited"] = XML::getFirstNodeValue($xpath, 'atom:updated/text()', $entry); + $item['created'] = XML::getFirstNodeValue($xpath, 'atom:published/text()', $entry); + $item['edited'] = XML::getFirstNodeValue($xpath, 'atom:updated/text()', $entry); $item['conversation-uri'] = XML::getFirstNodeValue($xpath, 'ostatus:conversation/text()', $entry); $conv = $xpath->query('ostatus:conversation', $entry); if (is_object($conv->item(0))) { foreach ($conv->item(0)->attributes as $attributes) { - if ($attributes->name == "ref") { + if ($attributes->name == 'ref') { $item['conversation-uri'] = $attributes->textContent; } - if ($attributes->name == "href") { + if ($attributes->name == 'href') { $item['conversation-href'] = $attributes->textContent; } } } - $related = ""; + $related = ''; $inreplyto = $xpath->query('thr:in-reply-to', $entry); if (is_object($inreplyto->item(0))) { foreach ($inreplyto->item(0)->attributes as $attributes) { - if ($attributes->name == "ref") { - $item["thr-parent"] = $attributes->textContent; + if ($attributes->name == 'ref') { + $item['thr-parent'] = $attributes->textContent; } - if ($attributes->name == "href") { + if ($attributes->name == 'href') { $related = $attributes->textContent; } } @@ -628,7 +646,7 @@ class OStatus $georsspoint = $xpath->query('georss:point', $entry); if (!empty($georsspoint) && ($georsspoint->length > 0)) { - $item["coord"] = $georsspoint->item(0)->nodeValue; + $item['coord'] = $georsspoint->item(0)->nodeValue; } $categories = $xpath->query('atom:category', $entry); @@ -653,33 +671,33 @@ class OStatus $add_body = $link_data['add_body']; } - $repeat_of = ""; + $repeat_of = ''; $notice_info = $xpath->query('statusnet:notice_info', $entry); if ($notice_info && ($notice_info->length > 0)) { foreach ($notice_info->item(0)->attributes as $attributes) { - if ($attributes->name == "source") { - $item["app"] = strip_tags($attributes->textContent); + if ($attributes->name == 'source') { + $item['app'] = strip_tags($attributes->textContent); } - if ($attributes->name == "repeat_of") { + if ($attributes->name == 'repeat_of') { $repeat_of = $attributes->textContent; } } } // Is it a repeated post? - if (($repeat_of != "") || ($item["verb"] == Activity::SHARE)) { + if (($repeat_of != '') || ($item['verb'] == Activity::SHARE)) { $link_data = self::processRepeatedItem($xpath, $entry, $item, $importer); if (!empty($link_data['add_body'])) { $add_body .= $link_data['add_body']; } } - $item["body"] .= $add_body; + $item['body'] .= $add_body; Tag::storeFromBody($item['uri-id'], $item['body']); // Mastodon Content Warning - if (($item["verb"] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $entry)) { + if (($item['verb'] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $entry)) { $clear_text = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $entry); if (!empty($clear_text)) { $item['content-warning'] = HTML::toBBCode($clear_text); @@ -690,21 +708,21 @@ class OStatus self::fetchSelf($self, $item); } - if (!empty($item["conversation-href"])) { + if (!empty($item['conversation-href'])) { self::fetchConversation($item['conversation-href'], $item['conversation-uri']); } - if (isset($item["thr-parent"])) { - if (!Post::exists(['uid' => $importer["uid"], 'uri' => $item['thr-parent']])) { + if (isset($item['thr-parent'])) { + if (!Post::exists(['uid' => $importer['uid'], 'uri' => $item['thr-parent']])) { if ($related != '') { - self::fetchRelated($related, $item["thr-parent"], $importer); + self::fetchRelated($related, $item['thr-parent'], $importer); } } else { - Logger::info('Reply with URI '.$item["uri"].' already existed for user '.$importer["uid"].'.'); + Logger::info('Reply with URI ' . $item['uri'] . ' already existed for user ' . $importer['uid'] . '.'); } } else { - $item["thr-parent"] = $item["uri"]; - $item["gravity"] = GRAVITY_PARENT; + $item['thr-parent'] = $item['uri']; + $item['gravity'] = GRAVITY_PARENT; } if (($item['author-link'] != '') && !empty($item['protocol'])) { @@ -722,7 +740,7 @@ class OStatus * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function fetchConversation($conversation, $conversation_uri) + private static function fetchConversation(string $conversation, string $conversation_uri) { // Ensure that we only store a conversation once in a process if (isset(self::$conv_list[$conversation])) { @@ -786,7 +804,7 @@ class OStatus * @return void * @throws \Exception */ - private static function storeConversation($xml, $conversation = '', $conversation_uri = '') + private static function storeConversation(string $xml, string $conversation = '', string $conversation_uri = '') { $doc = new DOMDocument(); @$doc->loadXML($xml); @@ -814,7 +832,7 @@ class OStatus $inreplyto = $xpath->query('thr:in-reply-to', $entry); if (is_object($inreplyto->item(0))) { foreach ($inreplyto->item(0)->attributes as $attributes) { - if ($attributes->name == "ref") { + if ($attributes->name == 'ref') { $conv_data['reply-to-uri'] = $attributes->textContent; } } @@ -825,10 +843,10 @@ class OStatus $conv = $xpath->query('ostatus:conversation', $entry); if (is_object($conv->item(0))) { foreach ($conv->item(0)->attributes as $attributes) { - if ($attributes->name == "ref") { + if ($attributes->name == 'ref') { $conv_data['conversation-uri'] = $attributes->textContent; } - if ($attributes->name == "href") { + if ($attributes->name == 'href') { $conv_data['conversation-href'] = $attributes->textContent; } } @@ -865,7 +883,7 @@ class OStatus * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function fetchSelf($self, array &$item) + private static function fetchSelf(string $self, array &$item) { $condition = ['item-uri' => $self, 'protocol' => [Conversation::PARCEL_DFRN, Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LOCAL_DFRN, @@ -888,9 +906,9 @@ class OStatus $doc->formatOutput = true; $xml = $doc->saveXML(); - $item["protocol"] = Conversation::PARCEL_SALMON; - $item["source"] = $xml; - $item["direction"] = Conversation::PULL; + $item['protocol'] = Conversation::PARCEL_SALMON; + $item['source'] = $xml; + $item['direction'] = Conversation::PULL; Logger::info('Conversation '.$item['uri'].' is now fetched.'); } @@ -905,11 +923,18 @@ class OStatus * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function fetchRelated($related, $related_uri, $importer) + private static function fetchRelated(string $related, string $related_uri, array $importer) { - $condition = ['item-uri' => $related_uri, 'protocol' => [Conversation::PARCEL_DFRN, - Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LOCAL_DFRN, - Conversation::PARCEL_DIRECT, Conversation::PARCEL_SALMON]]; + $condition = [ + 'item-uri' => $related_uri, + 'protocol' => [ + Conversation::PARCEL_DFRN, + Conversation::PARCEL_DIASPORA_DFRN, + Conversation::PARCEL_LOCAL_DFRN, + Conversation::PARCEL_DIRECT, + Conversation::PARCEL_SALMON, + ], + ]; $conversation = DBA::selectFirst('conversation', ['source', 'protocol'], $condition); if (DBA::isResult($conversation)) { $stored = true; @@ -994,7 +1019,7 @@ class OStatus $conversation = DBA::selectFirst('conversation', ['source'], $condition); if (DBA::isResult($conversation)) { $stored = true; - Logger::info('Got cached XML from conversation for URI '.$related_uri); + Logger::info('Got cached XML from conversation for URI ' . $related_uri); $xml = $conversation['source']; } } @@ -1002,7 +1027,7 @@ class OStatus if ($xml != '') { self::process($xml, $importer, $contact, $hub, $stored, false, Conversation::PULL); } else { - Logger::info("XML couldn't be fetched for URI: ".$related_uri." - href: ".$related); + Logger::info('XML could not be fetched for URI: ' . $related_uri . ' - href: ' . $related); } return; } @@ -1019,7 +1044,7 @@ class OStatus * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function processRepeatedItem(DOMXPath $xpath, $entry, array &$item, array $importer) + private static function processRepeatedItem(DOMXPath $xpath, $entry, array &$item, array $importer): array { $activityobject = $xpath->query('activity:object', $entry)->item(0); @@ -1031,7 +1056,7 @@ class OStatus $orig_uri = XML::getFirstNodeValue($xpath, 'atom:id/text()', $activityobject); - $links = $xpath->query("atom:link", $activityobject); + $links = $xpath->query('atom:link', $activityobject); if ($links) { $link_data = self::processLinks($links, $item); } @@ -1042,22 +1067,22 @@ class OStatus $orig_author = self::fetchAuthor($xpath, $activityobject, $importer, $dummy, false); - $item["author-name"] = $orig_author["author-name"]; - $item["author-link"] = $orig_author["author-link"]; - $item["author-id"] = $orig_author["author-id"]; + $item['author-name'] = $orig_author['author-name']; + $item['author-link'] = $orig_author['author-link']; + $item['author-id'] = $orig_author['author-id']; - $item["body"] = HTML::toBBCode($orig_body); - $item["created"] = $orig_created; - $item["edited"] = $orig_edited; + $item['body'] = HTML::toBBCode($orig_body); + $item['created'] = $orig_created; + $item['edited'] = $orig_edited; - $item["uri"] = $orig_uri; + $item['uri'] = $orig_uri; - $item["verb"] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $activityobject); + $item['verb'] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $activityobject); - $item["object-type"] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $activityobject); + $item['object-type'] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $activityobject); // Mastodon Content Warning - if (($item["verb"] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $activityobject)) { + if (($item['verb'] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $activityobject)) { $clear_text = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $activityobject); if (!empty($clear_text)) { $item['content-warning'] = HTML::toBBCode($clear_text); @@ -1067,8 +1092,8 @@ class OStatus $inreplyto = $xpath->query('thr:in-reply-to', $activityobject); if (is_object($inreplyto->item(0))) { foreach ($inreplyto->item(0)->attributes as $attributes) { - if ($attributes->name == "ref") { - $item["thr-parent"] = $attributes->textContent; + if ($attributes->name == 'ref') { + $item['thr-parent'] = $attributes->textContent; } } } @@ -1081,10 +1106,9 @@ class OStatus * * @param object $links The xml data that contain links * @param array $item The item array - * * @return array with data from the links */ - private static function processLinks($links, array &$item) + private static function processLinks($links, array &$item): array { $link_data = ['add_body' => '', 'self' => '']; @@ -1093,24 +1117,26 @@ class OStatus if (!empty($attribute['rel']) && !empty($attribute['href'])) { switch ($attribute['rel']) { - case "alternate": - $item["plink"] = $attribute['href']; - if (($item["object-type"] == Activity\ObjectType::QUESTION) - || ($item["object-type"] == Activity\ObjectType::EVENT) + case 'alternate': + $item['plink'] = $attribute['href']; + if (($item['object-type'] == Activity\ObjectType::QUESTION) + || ($item['object-type'] == Activity\ObjectType::EVENT) ) { Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::UNKNOWN, 'url' => $attribute['href'], 'mimetype' => $attribute['type'] ?? null, 'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]); } break; - case "ostatus:conversation": + + case 'ostatus:conversation': $link_data['conversation'] = $attribute['href']; $item['conversation-href'] = $link_data['conversation']; if (!isset($item['conversation-uri'])) { $item['conversation-uri'] = $item['conversation-href']; } break; - case "enclosure": + + case 'enclosure': $filetype = strtolower(substr($attribute['type'], 0, strpos($attribute['type'], '/'))); if ($filetype == 'image') { $link_data['add_body'] .= "\n[img]".$attribute['href'].'[/img]'; @@ -1120,10 +1146,11 @@ class OStatus 'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]); } break; - case "related": - if ($item["object-type"] != Activity\ObjectType::BOOKMARK) { - if (!isset($item["thr-parent"])) { - $item["thr-parent"] = $attribute['href']; + + case 'related': + if ($item['object-type'] != Activity\ObjectType::BOOKMARK) { + if (!isset($item['thr-parent'])) { + $item['thr-parent'] = $attribute['href']; } $link_data['related'] = $attribute['href']; } else { @@ -1132,12 +1159,16 @@ class OStatus 'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]); } break; - case "self": - if (empty($item["plink"])) { - $item["plink"] = $attribute['href']; + + case 'self': + if (empty($item['plink'])) { + $item['plink'] = $attribute['href']; } $link_data['self'] = $attribute['href']; break; + + default: + Logger::warning('Unsupported rel=' . $attribute['rel'] . ', href=' . $attribute['href'] . ', object-type=' . $attribute['object-type']); } } } @@ -1148,31 +1179,31 @@ class OStatus * Create an url out of an uri * * @param string $href URI in the format "parameter1:parameter1:..." - * * @return string URL in the format http(s)://.... */ - private static function convertHref($href) + private static function convertHref(string $href): string { - $elements = explode(":", $href); + $elements = explode(':', $href); - if ((count($elements) <= 2) || ($elements[0] != "tag")) { + if ((count($elements) <= 2) || ($elements[0] != 'tag')) { return $href; } - $server = explode(",", $elements[1]); - $conversation = explode("=", $elements[2]); + $server = explode(',', $elements[1]); + $conversation = explode('=', $elements[2]); - if ((count($elements) == 4) && ($elements[2] == "post")) { - return "http://".$server[0]."/notice/".$elements[3]; + if ((count($elements) == 4) && ($elements[2] == 'post')) { + return 'http://' . $server[0] . '/notice/' . $elements[3]; } - if ((count($conversation) != 2) || ($conversation[1] =="")) { + if ((count($conversation) != 2) || ($conversation[1] == '')) { return $href; } - if ($elements[3] == "objectType=thread") { - return "http://".$server[0]."/conversation/".$conversation[1]; + + if ($elements[3] == 'objectType=thread') { + return 'http://' . $server[0] . '/conversation/' . $conversation[1]; } else { - return "http://".$server[0]."/notice/".$conversation[1]; + return 'http://' . $server[0] . '/notice/' . $conversation[1]; } } @@ -1180,35 +1211,35 @@ class OStatus * Cleans the body of a post if it contains picture links * * @param string $body The body - * + * @param integer $uriId * @return string The cleaned body * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function formatPicturePost($body, $uriid) + public static function formatPicturePost(string $body, int $uriid): string { $siteinfo = BBCode::getAttachedData($body); - if (($siteinfo["type"] == "photo") && (!empty($siteinfo["preview"]) || !empty($siteinfo["image"]))) { - if (isset($siteinfo["preview"])) { - $preview = $siteinfo["preview"]; + if (($siteinfo['type'] == 'photo') && (!empty($siteinfo['preview']) || !empty($siteinfo['image']))) { + if (isset($siteinfo['preview'])) { + $preview = $siteinfo['preview']; } else { - $preview = $siteinfo["image"]; + $preview = $siteinfo['image']; } // Is it a remote picture? Then make a smaller preview here $preview = Post\Link::getByLink($uriid, $preview, Proxy::SIZE_SMALL); // Is it a local picture? Then make it smaller here - $preview = str_replace(["-0.jpg", "-0.png"], ["-2.jpg", "-2.png"], $preview); - $preview = str_replace(["-1.jpg", "-1.png"], ["-2.jpg", "-2.png"], $preview); + $preview = str_replace(['-0.jpg', '-0.png'], ['-2.jpg', '-2.png'], $preview); + $preview = str_replace(['-1.jpg', '-1.png'], ['-2.jpg', '-2.png'], $preview); - if (isset($siteinfo["url"])) { - $url = $siteinfo["url"]; + if (isset($siteinfo['url'])) { + $url = $siteinfo['url']; } else { - $url = $siteinfo["image"]; + $url = $siteinfo['image']; } - $body = trim($siteinfo["text"])." [url]".$url."[/url]\n[img]".$preview."[/img]"; + $body = trim($siteinfo['text']) . ' [url]' . $url . "[/url]\n[img]" . $preview . '[/img]'; } return $body; @@ -1221,54 +1252,63 @@ class OStatus * @param array $owner Contact data of the poster * @param string $filter The related feed filter (activity, posts or comments) * - * @return object header root element + * @return DOMElement Header root element * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function addHeader(DOMDocument $doc, array $owner, $filter) + private static function addHeader(DOMDocument $doc, array $owner, string $filter): DOMElement { $root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed'); $doc->appendChild($root); - $root->setAttribute("xmlns:thr", ActivityNamespace::THREAD); - $root->setAttribute("xmlns:georss", ActivityNamespace::GEORSS); - $root->setAttribute("xmlns:activity", ActivityNamespace::ACTIVITY); - $root->setAttribute("xmlns:media", ActivityNamespace::MEDIA); - $root->setAttribute("xmlns:poco", ActivityNamespace::POCO); - $root->setAttribute("xmlns:ostatus", ActivityNamespace::OSTATUS); - $root->setAttribute("xmlns:statusnet", ActivityNamespace::STATUSNET); - $root->setAttribute("xmlns:mastodon", ActivityNamespace::MASTODON); + $root->setAttribute('xmlns:thr', ActivityNamespace::THREAD); + $root->setAttribute('xmlns:georss', ActivityNamespace::GEORSS); + $root->setAttribute('xmlns:activity', ActivityNamespace::ACTIVITY); + $root->setAttribute('xmlns:media', ActivityNamespace::MEDIA); + $root->setAttribute('xmlns:poco', ActivityNamespace::POCO); + $root->setAttribute('xmlns:ostatus', ActivityNamespace::OSTATUS); + $root->setAttribute('xmlns:statusnet', ActivityNamespace::STATUSNET); + $root->setAttribute('xmlns:mastodon', ActivityNamespace::MASTODON); $title = ''; - $selfUri = '/feed/' . $owner["nick"] . '/'; + $selfUri = '/feed/' . $owner['nick'] . '/'; switch ($filter) { case 'activity': $title = DI::l10n()->t('%s\'s timeline', $owner['name']); $selfUri .= $filter; break; + case 'posts': $title = DI::l10n()->t('%s\'s posts', $owner['name']); break; + case 'comments': $title = DI::l10n()->t('%s\'s comments', $owner['name']); $selfUri .= $filter; break; } - $selfUri = "/dfrn_poll/" . $owner["nick"]; + $selfUri = '/dfrn_poll/' . $owner['nick']; - $attributes = ["uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION . "-" . DB_UPDATE_VERSION]; - XML::addElement($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); - XML::addElement($doc, $root, "id", DI::baseUrl() . "/profile/" . $owner["nick"]); - XML::addElement($doc, $root, "title", $title); - XML::addElement($doc, $root, "subtitle", sprintf("Updates from %s on %s", $owner["name"], DI::config()->get('config', 'sitename'))); - XML::addElement($doc, $root, "logo", User::getAvatarUrl($owner, Proxy::SIZE_SMALL)); - XML::addElement($doc, $root, "updated", DateTimeFormat::utcNow(DateTimeFormat::ATOM)); + $attributes = [ + 'uri' => 'https://friendi.ca', + 'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION, + ]; + XML::addElement($doc, $root, 'generator', FRIENDICA_PLATFORM, $attributes); + XML::addElement($doc, $root, 'id', DI::baseUrl() . '/profile/' . $owner['nick']); + XML::addElement($doc, $root, 'title', $title); + XML::addElement($doc, $root, 'subtitle', sprintf("Updates from %s on %s", $owner['name'], DI::config()->get('config', 'sitename'))); + XML::addElement($doc, $root, 'logo', User::getAvatarUrl($owner, Proxy::SIZE_SMALL)); + XML::addElement($doc, $root, 'updated', DateTimeFormat::utcNow(DateTimeFormat::ATOM)); $author = self::addAuthor($doc, $owner, true); $root->appendChild($author); - $attributes = ["href" => $owner["url"], "rel" => "alternate", "type" => "text/html"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = [ + 'href' => $owner['url'], + 'rel' => 'alternate', + 'type' => 'text/html', + ]; + XML::addElement($doc, $root, 'link', '', $attributes); /// @TODO We have to find out what this is /// $attributes = array("href" => DI::baseUrl()."/sup", @@ -1276,25 +1316,30 @@ class OStatus /// "type" => "application/json"); /// XML::addElement($doc, $root, "link", "", $attributes); - self::hublinks($doc, $root, $owner["nick"]); + self::addHubLink($doc, $root, $owner['nick']); - $attributes = ["href" => DI::baseUrl() . "/salmon/" . $owner["nick"], "rel" => "salmon"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => DI::baseUrl() . '/salmon/' . $owner['nick'], 'rel' => 'salmon']; + XML::addElement($doc, $root, 'link', '', $attributes); - $attributes = ["href" => DI::baseUrl() . "/salmon/" . $owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-replies"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => DI::baseUrl() . '/salmon/' . $owner['nick'], 'rel' => 'http://salmon-protocol.org/ns/salmon-replies']; + XML::addElement($doc, $root, 'link', '', $attributes); - $attributes = ["href" => DI::baseUrl() . "/salmon/" . $owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-mention"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => DI::baseUrl() . '/salmon/' . $owner['nick'], 'rel' => 'http://salmon-protocol.org/ns/salmon-mention']; + XML::addElement($doc, $root, 'link', '', $attributes); - $attributes = ["href" => DI::baseUrl() . $selfUri, "rel" => "self", "type" => "application/atom+xml"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => DI::baseUrl() . $selfUri, 'rel' => 'self', 'type' => 'application/atom+xml']; + XML::addElement($doc, $root, 'link', '', $attributes); if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { - $condition = ['uid' => $owner['uid'], 'self' => false, 'pending' => false, - 'archive' => false, 'hidden' => false, 'blocked' => false]; - $members = DBA::count('contact', $condition); - XML::addElement($doc, $root, "statusnet:group_info", "", ["member_count" => $members]); + $members = DBA::count('contact', [ + 'uid' => $owner['uid'], + 'self' => false, + 'pending' => false, + 'archive' => false, + 'hidden' => false, + 'blocked' => false, + ]); + XML::addElement($doc, $root, 'statusnet:group_info', '', ['member_count' => $members]); } return $root; @@ -1304,65 +1349,73 @@ class OStatus * Add the link to the push hubs to the XML document * * @param DOMDocument $doc XML document - * @param object $root XML root element where the hub links are added - * @param object $nick nick + * @param DOMElement $root XML root element where the hub links are added + * @param string $nick Nickname * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function hublinks(DOMDocument $doc, $root, $nick) + public static function addHubLink(DOMDocument $doc, DOMElement $root, string $nick) { - $h = DI::baseUrl() . '/pubsubhubbub/'.$nick; - XML::addElement($doc, $root, "link", "", ["href" => $h, "rel" => "hub"]); + $h = DI::baseUrl() . '/pubsubhubbub/' . $nick; + XML::addElement($doc, $root, 'link', '', ['href' => $h, 'rel' => 'hub']); } /** * Adds attachment data to the XML document * * @param DOMDocument $doc XML document - * @param object $root XML root element where the hub links are added + * @param DOMElement $root XML root element where the hub links are added * @param array $item Data of the item that is to be posted * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getAttachment(DOMDocument $doc, $root, $item) + public static function getAttachment(DOMDocument $doc, DOMElement $root, array $item) { - $siteinfo = BBCode::getAttachedData($item["body"]); + $siteinfo = BBCode::getAttachedData($item['body']); - switch ($siteinfo["type"]) { + switch ($siteinfo['type']) { case 'photo': - if (!empty($siteinfo["image"])) { - $imgdata = Images::getInfoFromURLCached($siteinfo["image"]); + if (!empty($siteinfo['image'])) { + $imgdata = Images::getInfoFromURLCached($siteinfo['image']); if ($imgdata) { - $attributes = ["rel" => "enclosure", - "href" => $siteinfo["image"], - "type" => $imgdata["mime"], - "length" => intval($imgdata["size"])]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = [ + 'rel' => 'enclosure', + 'href' => $siteinfo['image'], + 'type' => $imgdata['mime'], + 'length' => intval($imgdata['size']), + ]; + XML::addElement($doc, $root, 'link', '', $attributes); } } break; + case 'video': - $attributes = ["rel" => "enclosure", - "href" => $siteinfo["url"], - "type" => "text/html; charset=UTF-8", - "length" => "0", - "title" => ($siteinfo["title"] ?? '') ?: $siteinfo["url"], + $attributes = [ + 'rel' => 'enclosure', + 'href' => $siteinfo['url'], + 'type' => 'text/html; charset=UTF-8', + 'length' => '0', + 'title' => ($siteinfo['title'] ?? '') ?: $siteinfo['url'], ]; - XML::addElement($doc, $root, "link", "", $attributes); + XML::addElement($doc, $root, 'link', '', $attributes); break; + default: + Logger::warning('Unsupported type', ['type' => $siteinfo['type'], 'url' => $siteinfo['url'] ?? '']); break; } - if (!DI::config()->get('system', 'ostatus_not_attach_preview') && ($siteinfo["type"] != "photo") && isset($siteinfo["image"])) { - $imgdata = Images::getInfoFromURLCached($siteinfo["image"]); + if (!DI::config()->get('system', 'ostatus_not_attach_preview') && ($siteinfo['type'] != 'photo') && isset($siteinfo['image'])) { + $imgdata = Images::getInfoFromURLCached($siteinfo['image']); if ($imgdata) { - $attributes = ["rel" => "enclosure", - "href" => $siteinfo["image"], - "type" => $imgdata["mime"], - "length" => intval($imgdata["size"])]; + $attributes = [ + 'rel' => 'enclosure', + 'href' => $siteinfo['image'], + 'type' => $imgdata['mime'], + 'length' => intval($imgdata['size']), + ]; - XML::addElement($doc, $root, "link", "", $attributes); + XML::addElement($doc, $root, 'link', '', $attributes); } } @@ -1388,75 +1441,80 @@ class OStatus * @param DOMDocument $doc XML document * @param array $owner Contact data of the poster * @param bool $show_profile Whether to show profile - * - * @return \DOMElement author element + * @return DOMElement Author element * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function addAuthor(DOMDocument $doc, array $owner, $show_profile = true) + private static function addAuthor(DOMDocument $doc, array $owner, bool $show_profile = true): DOMElement { $profile = DBA::selectFirst('profile', ['homepage', 'publish'], ['uid' => $owner['uid']]); - $author = $doc->createElement("author"); - XML::addElement($doc, $author, "id", $owner["url"]); + $author = $doc->createElement('author'); + XML::addElement($doc, $author, 'id', $owner['url']); if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { - XML::addElement($doc, $author, "activity:object-type", Activity\ObjectType::GROUP); + XML::addElement($doc, $author, 'activity:object-type', Activity\ObjectType::GROUP); } else { - XML::addElement($doc, $author, "activity:object-type", Activity\ObjectType::PERSON); + XML::addElement($doc, $author, 'activity:object-type', Activity\ObjectType::PERSON); } - XML::addElement($doc, $author, "uri", $owner["url"]); - XML::addElement($doc, $author, "name", $owner["nick"]); - XML::addElement($doc, $author, "email", $owner["addr"]); + XML::addElement($doc, $author, 'uri', $owner['url']); + XML::addElement($doc, $author, 'name', $owner['nick']); + XML::addElement($doc, $author, 'email', $owner['addr']); if ($show_profile) { - XML::addElement($doc, $author, "summary", BBCode::convertForUriId($owner['uri-id'], $owner["about"], BBCode::OSTATUS)); + XML::addElement($doc, $author, 'summary', BBCode::convertForUriId($owner['uri-id'], $owner['about'], BBCode::OSTATUS)); } - $attributes = ["rel" => "alternate", "type" => "text/html", "href" => $owner["url"]]; - XML::addElement($doc, $author, "link", "", $attributes); - $attributes = [ - "rel" => "avatar", - "type" => "image/jpeg", // To-Do? - "media:width" => Proxy::PIXEL_SMALL, - "media:height" => Proxy::PIXEL_SMALL, - "href" => User::getAvatarUrl($owner, Proxy::SIZE_SMALL)]; - XML::addElement($doc, $author, "link", "", $attributes); + 'rel' => 'alternate', + 'type' => 'text/html', + 'href' => $owner['url'], + ]; + XML::addElement($doc, $author, 'link', '', $attributes); - if (isset($owner["thumb"])) { + $attributes = [ + 'rel' => 'avatar', + 'type' => 'image/jpeg', // To-Do? + 'media:width' => Proxy::PIXEL_SMALL, + 'media:height' => Proxy::PIXEL_SMALL, + 'href' => User::getAvatarUrl($owner, Proxy::SIZE_SMALL), + ]; + XML::addElement($doc, $author, 'link', '', $attributes); + + if (isset($owner['thumb'])) { $attributes = [ - "rel" => "avatar", - "type" => "image/jpeg", // To-Do? - "media:width" => Proxy::PIXEL_THUMB, - "media:height" => Proxy::PIXEL_THUMB, - "href" => User::getAvatarUrl($owner, Proxy::SIZE_THUMB)]; - XML::addElement($doc, $author, "link", "", $attributes); + 'rel' => 'avatar', + 'type' => 'image/jpeg', // To-Do? + 'media:width' => Proxy::PIXEL_THUMB, + 'media:height' => Proxy::PIXEL_THUMB, + 'href' => User::getAvatarUrl($owner, Proxy::SIZE_THUMB), + ]; + XML::addElement($doc, $author, 'link', '', $attributes); } - XML::addElement($doc, $author, "poco:preferredUsername", $owner["nick"]); - XML::addElement($doc, $author, "poco:displayName", $owner["name"]); + XML::addElement($doc, $author, 'poco:preferredUsername', $owner['nick']); + XML::addElement($doc, $author, 'poco:displayName', $owner['name']); if ($show_profile) { - XML::addElement($doc, $author, "poco:note", BBCode::convertForUriId($owner['uri-id'], $owner["about"], BBCode::OSTATUS)); + XML::addElement($doc, $author, 'poco:note', BBCode::convertForUriId($owner['uri-id'], $owner['about'], BBCode::OSTATUS)); - if (trim($owner["location"]) != "") { - $element = $doc->createElement("poco:address"); - XML::addElement($doc, $element, "poco:formatted", $owner["location"]); + if (trim($owner['location']) != '') { + $element = $doc->createElement('poco:address'); + XML::addElement($doc, $element, 'poco:formatted', $owner['location']); $author->appendChild($element); } } if (DBA::isResult($profile) && !$show_profile) { - if (trim($profile["homepage"]) != "") { - $urls = $doc->createElement("poco:urls"); - XML::addElement($doc, $urls, "poco:type", "homepage"); - XML::addElement($doc, $urls, "poco:value", $profile["homepage"]); - XML::addElement($doc, $urls, "poco:primary", "true"); + if (trim($profile['homepage']) != '') { + $urls = $doc->createElement('poco:urls'); + XML::addElement($doc, $urls, 'poco:type', 'homepage'); + XML::addElement($doc, $urls, 'poco:value', $profile['homepage']); + XML::addElement($doc, $urls, 'poco:primary', 'true'); $author->appendChild($urls); } - XML::addElement($doc, $author, "followers", "", ["url" => DI::baseUrl() . "/profile/" . $owner["nick"] . "/contacts/followers"]); - XML::addElement($doc, $author, "statusnet:profile_info", "", ["local_id" => $owner["uid"]]); + XML::addElement($doc, $author, 'followers', '', ['url' => DI::baseUrl() . '/profile/' . $owner['nick'] . '/contacts/followers']); + XML::addElement($doc, $author, 'statusnet:profile_info', '', ['local_id' => $owner['uid']]); - if ($profile["publish"]) { - XML::addElement($doc, $author, "mastodon:scope", "public"); + if ($profile['publish']) { + XML::addElement($doc, $author, 'mastodon:scope', 'public'); } } @@ -1473,10 +1531,9 @@ class OStatus * Returns the given activity if present - otherwise returns the "post" activity * * @param array $item Data of the item that is to be posted - * * @return string activity */ - public static function constructVerb(array $item) + public static function constructVerb(array $item): string { if (!empty($item['verb'])) { return $item['verb']; @@ -1489,10 +1546,9 @@ class OStatus * Returns the given object type if present - otherwise returns the "note" object type * * @param array $item Data of the item that is to be posted - * * @return string Object type */ - private static function constructObjecttype(array $item) + private static function constructObjecttype(array $item): string { if (!empty($item['object-type']) && in_array($item['object-type'], [Activity\ObjectType::NOTE, Activity\ObjectType::COMMENT])) { return $item['object-type']; @@ -1509,15 +1565,15 @@ class OStatus * @param array $owner Contact data of the poster * @param bool $toplevel optional default false * - * @return \DOMElement Entry element + * @return DOMElement Entry element * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function entry(DOMDocument $doc, array $item, array $owner, $toplevel = false) + private static function entry(DOMDocument $doc, array $item, array $owner, bool $toplevel = false): DOMElement { - if ($item["verb"] == Activity::LIKE) { + if ($item['verb'] == Activity::LIKE) { return self::likeEntry($doc, $item, $owner, $toplevel); - } elseif (in_array($item["verb"], [Activity::FOLLOW, Activity::O_UNFOLLOW])) { + } elseif (in_array($item['verb'], [Activity::FOLLOW, Activity::O_UNFOLLOW])) { return self::followEntry($doc, $item, $owner, $toplevel); } else { return self::noteEntry($doc, $item, $owner, $toplevel); @@ -1531,29 +1587,28 @@ class OStatus * @param array $item Data of the item that is to be posted * @param array $owner Contact data of the poster * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? - * - * @return \DOMElement Entry element with "like" + * @return DOMElement Entry element with "like" * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function likeEntry(DOMDocument $doc, array $item, array $owner, $toplevel) + private static function likeEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement { - if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { - Logger::info("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting."); + if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) { + Logger::info('OStatus entry is from author ' . $owner['url'] . ' - not from ' . $item['author-link'] . '. Quitting.'); } $entry = self::entryHeader($doc, $owner, $item, $toplevel); - $verb = ActivityNamespace::ACTIVITY_SCHEMA . "favorite"; - self::entryContent($doc, $entry, $item, $owner, "Favorite", $verb, false); + $verb = ActivityNamespace::ACTIVITY_SCHEMA . 'favorite'; + self::entryContent($doc, $entry, $item, $owner, 'Favorite', $verb, false); - $parent = Post::selectFirst([], ['uri' => $item["thr-parent"], 'uid' => $item["uid"]]); + $parent = Post::selectFirst([], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]); if (DBA::isResult($parent)) { - $as_object = $doc->createElement("activity:object"); + $as_object = $doc->createElement('activity:object'); - XML::addElement($doc, $as_object, "activity:object-type", self::constructObjecttype($parent)); + XML::addElement($doc, $as_object, 'activity:object-type', self::constructObjecttype($parent)); - self::entryContent($doc, $as_object, $parent, $owner, "New entry"); + self::entryContent($doc, $as_object, $parent, $owner, 'New entry'); $entry->appendChild($as_object); } @@ -1569,39 +1624,42 @@ class OStatus * @param DOMDocument $doc XML document * @param array $owner Contact data of the poster * @param array $contact Contact data of the target - * - * @return object author element + * @return DOMElement author element */ - private static function addPersonObject(DOMDocument $doc, array $owner, array $contact) + private static function addPersonObject(DOMDocument $doc, array $owner, array $contact): DOMElement { - $object = $doc->createElement("activity:object"); - XML::addElement($doc, $object, "activity:object-type", Activity\ObjectType::PERSON); + $object = $doc->createElement('activity:object'); + XML::addElement($doc, $object, 'activity:object-type', Activity\ObjectType::PERSON); if ($contact['network'] == Protocol::PHANTOM) { - XML::addElement($doc, $object, "id", $contact['url']); + XML::addElement($doc, $object, 'id', $contact['url']); return $object; } - XML::addElement($doc, $object, "id", $contact["alias"]); - XML::addElement($doc, $object, "title", $contact["nick"]); + XML::addElement($doc, $object, 'id', $contact['alias']); + XML::addElement($doc, $object, 'title', $contact['nick']); - $attributes = ["rel" => "alternate", "type" => "text/html", "href" => $contact["url"]]; - XML::addElement($doc, $object, "link", "", $attributes); + XML::addElement($doc, $object, 'link', '', [ + 'rel' => 'alternate', + 'type' => 'text/html', + 'href' => $contact['url'], + ]); $attributes = [ - "rel" => "avatar", - "type" => "image/jpeg", // To-Do? - "media:width" => 300, - "media:height" => 300, - "href" => $contact["photo"]]; - XML::addElement($doc, $object, "link", "", $attributes); + 'rel' => 'avatar', + 'type' => 'image/jpeg', // To-Do? + 'media:width' => 300, + 'media:height' => 300, + 'href' => $contact['photo'], + ]; + XML::addElement($doc, $object, 'link', '', $attributes); - XML::addElement($doc, $object, "poco:preferredUsername", $contact["nick"]); - XML::addElement($doc, $object, "poco:displayName", $contact["name"]); + XML::addElement($doc, $object, 'poco:preferredUsername', $contact['nick']); + XML::addElement($doc, $object, 'poco:displayName', $contact['name']); - if (trim($contact["location"]) != "") { - $element = $doc->createElement("poco:address"); - XML::addElement($doc, $element, "poco:formatted", $contact["location"]); + if (trim($contact['location']) != '') { + $element = $doc->createElement('poco:address'); + XML::addElement($doc, $element, 'poco:formatted', $contact['location']); $object->appendChild($element); } @@ -1615,16 +1673,15 @@ class OStatus * @param array $item Data of the follow/unfollow message * @param array $owner Contact data of the poster * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? - * - * @return \DOMElement Entry element + * @return DOMElement Entry element * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function followEntry(DOMDocument $doc, array $item, array $owner, $toplevel) + private static function followEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement { - $item["id"] = $item['parent'] = 0; - $item["created"] = $item["edited"] = date("c"); - $item["private"] = Item::PRIVATE; + $item['id'] = $item['parent'] = 0; + $item['created'] = $item['edited'] = date('c'); + $item['private'] = Item::PRIVATE; $contact = Contact::getByURL($item['follow']); $item['follow'] = $contact['url']; @@ -1635,7 +1692,7 @@ class OStatus $contact['alias'] = $contact['url']; } - $condition = ['uid' => $owner['uid'], 'nurl' => Strings::normaliseLink($contact["url"])]; + $condition = ['uid' => $owner['uid'], 'nurl' => Strings::normaliseLink($contact['url'])]; $user_contact = DBA::selectFirst('contact', ['id'], $condition); if (DBA::isResult($user_contact)) { @@ -1647,19 +1704,19 @@ class OStatus if ($item['verb'] == Activity::FOLLOW) { $message = DI::l10n()->t('%s is now following %s.'); $title = DI::l10n()->t('following'); - $action = "subscription"; + $action = 'subscription'; } else { $message = DI::l10n()->t('%s stopped following %s.'); $title = DI::l10n()->t('stopped following'); - $action = "unfollow"; + $action = 'unfollow'; } - $item["uri"] = $item['parent-uri'] = $item['thr-parent'] + $item['uri'] = $item['parent-uri'] = $item['thr-parent'] = 'tag:' . DI::baseUrl()->getHostname(). ','.date('Y-m-d').':'.$action.':'.$owner['uid']. ':person:'.$connect_id.':'.$item['created']; - $item["body"] = sprintf($message, $owner["nick"], $contact["nick"]); + $item['body'] = sprintf($message, $owner['nick'], $contact['nick']); $entry = self::entryHeader($doc, $owner, $item, $toplevel); @@ -1680,30 +1737,29 @@ class OStatus * @param array $item Data of the item that is to be posted * @param array $owner Contact data of the poster * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? - * - * @return \DOMElement Entry element + * @return DOMElement Entry element * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function noteEntry(DOMDocument $doc, array $item, array $owner, $toplevel) + private static function noteEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement { - if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { - Logger::info("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting."); + if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) { + Logger::info('OStatus entry is from author ' . $owner['url'] . ' - not from ' . $item['author-link'] . '. Quitting.'); } if (!$toplevel) { if (!empty($item['title'])) { $title = BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::OSTATUS); } else { - $title = sprintf("New note by %s", $owner["nick"]); + $title = sprintf('New note by %s', $owner['nick']); } } else { - $title = sprintf("New comment by %s", $owner["nick"]); + $title = sprintf('New comment by %s', $owner['nick']); } $entry = self::entryHeader($doc, $owner, $item, $toplevel); - XML::addElement($doc, $entry, "activity:object-type", Activity\ObjectType::NOTE); + XML::addElement($doc, $entry, 'activity:object-type', Activity\ObjectType::NOTE); self::entryContent($doc, $entry, $item, $owner, $title, '', true); @@ -1719,15 +1775,14 @@ class OStatus * @param array $owner Contact data of the poster * @param array $item * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? - * - * @return \DOMElement The entry element where the elements are added + * @return DOMElement The entry element where the elements are added * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function entryHeader(DOMDocument $doc, array $owner, array $item, $toplevel) + public static function entryHeader(DOMDocument $doc, array $owner, array $item, bool $toplevel): DOMElement { if (!$toplevel) { - $entry = $doc->createElement("entry"); + $entry = $doc->createElement('entry'); if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { $contact = Contact::getByURL($item['author-link']) ?: $owner; @@ -1736,16 +1791,16 @@ class OStatus $entry->appendChild($author); } } else { - $entry = $doc->createElementNS(ActivityNamespace::ATOM1, "entry"); + $entry = $doc->createElementNS(ActivityNamespace::ATOM1, 'entry'); - $entry->setAttribute("xmlns:thr", ActivityNamespace::THREAD); - $entry->setAttribute("xmlns:georss", ActivityNamespace::GEORSS); - $entry->setAttribute("xmlns:activity", ActivityNamespace::ACTIVITY); - $entry->setAttribute("xmlns:media", ActivityNamespace::MEDIA); - $entry->setAttribute("xmlns:poco", ActivityNamespace::POCO); - $entry->setAttribute("xmlns:ostatus", ActivityNamespace::OSTATUS); - $entry->setAttribute("xmlns:statusnet", ActivityNamespace::STATUSNET); - $entry->setAttribute("xmlns:mastodon", ActivityNamespace::MASTODON); + $entry->setAttribute('xmlns:thr', ActivityNamespace::THREAD); + $entry->setAttribute('xmlns:georss', ActivityNamespace::GEORSS); + $entry->setAttribute('xmlns:activity', ActivityNamespace::ACTIVITY); + $entry->setAttribute('xmlns:media', ActivityNamespace::MEDIA); + $entry->setAttribute('xmlns:poco', ActivityNamespace::POCO); + $entry->setAttribute('xmlns:ostatus', ActivityNamespace::OSTATUS); + $entry->setAttribute('xmlns:statusnet', ActivityNamespace::STATUSNET); + $entry->setAttribute('xmlns:mastodon', ActivityNamespace::MASTODON); $author = self::addAuthor($doc, $owner); $entry->appendChild($author); @@ -1758,7 +1813,7 @@ class OStatus * Adds elements to the XML document * * @param DOMDocument $doc XML document - * @param \DOMElement $entry Entry element where the content is added + * @param DOMElement $entry Entry element where the content is added * @param array $item Data of the item that is to be posted * @param array $owner Contact data of the poster * @param string $title Title for the post @@ -1767,38 +1822,40 @@ class OStatus * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function entryContent(DOMDocument $doc, \DOMElement $entry, array $item, array $owner, $title, $verb = "", $complete = true) + private static function entryContent(DOMDocument $doc, DOMElement $entry, array $item, array $owner, string $title, string $verb = '', bool $complete = true) { - if ($verb == "") { + if ($verb == '') { $verb = self::constructVerb($item); } - XML::addElement($doc, $entry, "id", $item["uri"]); - XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8')); + XML::addElement($doc, $entry, 'id', $item['uri']); + XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8')); $body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']); $body = self::formatPicturePost($body, $item['uri-id']); if (!empty($item['title'])) { - $body = "[b]".$item['title']."[/b]\n\n".$body; + $body = '[b]' . $item['title'] . "[/b]\n\n" . $body; } $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::OSTATUS); - XML::addElement($doc, $entry, "content", $body, ["type" => "html"]); + XML::addElement($doc, $entry, 'content', $body, ['type' => 'html']); - XML::addElement($doc, $entry, "link", "", ["rel" => "alternate", "type" => "text/html", - "href" => DI::baseUrl()."/display/".$item["guid"]] - ); + XML::addElement($doc, $entry, 'link', '', [ + 'rel' => 'alternate', + 'type' => 'text/html', + 'href' => DI::baseUrl() . '/display/' . $item['guid'], + ]); - if ($complete && ($item["id"] > 0)) { - XML::addElement($doc, $entry, "status_net", "", ["notice_id" => $item["id"]]); + if ($complete && ($item['id'] > 0)) { + XML::addElement($doc, $entry, 'status_net', '', ['notice_id' => $item['id']]); } - XML::addElement($doc, $entry, "activity:verb", $verb); + XML::addElement($doc, $entry, 'activity:verb', $verb); - XML::addElement($doc, $entry, "published", DateTimeFormat::utc($item["created"]."+00:00", DateTimeFormat::ATOM)); - XML::addElement($doc, $entry, "updated", DateTimeFormat::utc($item["edited"]."+00:00", DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'published', DateTimeFormat::utc($item['created'] . '+00:00', DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'updated', DateTimeFormat::utc($item['edited'] . '+00:00', DateTimeFormat::ATOM)); } /** @@ -1812,7 +1869,7 @@ class OStatus * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function entryFooter(DOMDocument $doc, $entry, array $item, array $owner, $complete = true) + private static function entryFooter(DOMDocument $doc, $entry, array $item, array $owner, bool $complete = true) { $mentioned = []; @@ -1861,14 +1918,15 @@ class OStatus } } - XML::addElement($doc, $entry, "link", "", ["rel" => "ostatus:conversation", "href" => $conversation_href]); + XML::addElement($doc, $entry, 'link', '', ['rel' => 'ostatus:conversation', 'href' => $conversation_href]); $attributes = [ - "href" => $conversation_href, - "local_id" => $item['parent'], - "ref" => $conversation_uri]; + 'href' => $conversation_href, + 'local_id' => $item['parent'], + 'ref' => $conversation_uri, + ]; - XML::addElement($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes); + XML::addElement($doc, $entry, 'ostatus:conversation', $conversation_uri, $attributes); } // uri-id isn't present for follow entry pseudo-items @@ -1880,72 +1938,70 @@ class OStatus // Make sure that mentions are accepted (GNU Social has problems with mixing HTTP and HTTPS) $newmentions = []; foreach ($mentioned as $mention) { - $newmentions[str_replace("http://", "https://", $mention)] = str_replace("http://", "https://", $mention); - $newmentions[str_replace("https://", "http://", $mention)] = str_replace("https://", "http://", $mention); + $newmentions[str_replace('http://', 'https://', $mention)] = str_replace('http://', 'https://', $mention); + $newmentions[str_replace('https://', 'http://', $mention)] = str_replace('https://', 'http://', $mention); } $mentioned = $newmentions; foreach ($mentioned as $mention) { $contact = Contact::getByURL($mention, false, ['contact-type']); if (!empty($contact) && ($contact['contact-type'] == Contact::TYPE_COMMUNITY)) { - XML::addElement($doc, $entry, "link", "", - [ - "rel" => "mentioned", - "ostatus:object-type" => Activity\ObjectType::GROUP, - "href" => $mention] - ); + XML::addElement($doc, $entry, 'link', '', [ + 'rel' => 'mentioned', + 'ostatus:object-type' => Activity\ObjectType::GROUP, + 'href' => $mention, + ]); } else { - XML::addElement($doc, $entry, "link", "", - [ - "rel" => "mentioned", - "ostatus:object-type" => Activity\ObjectType::PERSON, - "href" => $mention] - ); + XML::addElement($doc, $entry, 'link', '', [ + 'rel' => 'mentioned', + 'ostatus:object-type' => Activity\ObjectType::PERSON, + 'href' => $mention, + ]); } } if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { - XML::addElement($doc, $entry, "link", "", [ - "rel" => "mentioned", - "ostatus:object-type" => "http://activitystrea.ms/schema/1.0/group", - "href" => $owner['url'] + XML::addElement($doc, $entry, 'link', '', [ + 'rel' => 'mentioned', + 'ostatus:object-type' => 'http://activitystrea.ms/schema/1.0/group', + 'href' => $owner['url'] ]); } if ($item['private'] != Item::PRIVATE) { - XML::addElement($doc, $entry, "link", "", ["rel" => "ostatus:attention", - "href" => "http://activityschema.org/collection/public"]); - XML::addElement($doc, $entry, "link", "", ["rel" => "mentioned", - "ostatus:object-type" => "http://activitystrea.ms/schema/1.0/collection", - "href" => "http://activityschema.org/collection/public"]); - XML::addElement($doc, $entry, "mastodon:scope", "public"); + XML::addElement($doc, $entry, 'link', '', ['rel' => 'ostatus:attention', + 'href' => 'http://activityschema.org/collection/public']); + XML::addElement($doc, $entry, 'link', '', ['rel' => 'mentioned', + 'ostatus:object-type' => 'http://activitystrea.ms/schema/1.0/collection', + 'href' => 'http://activityschema.org/collection/public']); + XML::addElement($doc, $entry, 'mastodon:scope', 'public'); } foreach ($tags as $tag) { if ($tag['type'] == Tag::HASHTAG) { - XML::addElement($doc, $entry, "category", "", ["term" => $tag['name']]); + XML::addElement($doc, $entry, 'category', '', ['term' => $tag['name']]); } } self::getAttachment($doc, $entry, $item); - if ($complete && ($item["id"] > 0)) { - $app = $item["app"]; - if ($app == "") { - $app = "web"; + if ($complete && ($item['id'] > 0)) { + $app = $item['app']; + if ($app == '') { + $app = 'web'; } - $attributes = ["local_id" => $item["id"], "source" => $app]; + $attributes = ['local_id' => $item['id'], 'source' => $app]; - if (isset($parent["id"])) { - $attributes["repeat_of"] = $parent["id"]; + if (isset($parent['id'])) { + $attributes['repeat_of'] = $parent['id']; } - if ($item["coord"] != "") { - XML::addElement($doc, $entry, "georss:point", $item["coord"]); + if ($item['coord'] != '') { + XML::addElement($doc, $entry, 'georss:point', $item['coord']); } - XML::addElement($doc, $entry, "statusnet:notice_info", "", $attributes); + XML::addElement($doc, $entry, 'statusnet:notice_info', '', $attributes); } } @@ -1961,25 +2017,24 @@ class OStatus * cache or it is empty * * @param string $owner_nick Nickname of the feed owner - * @param string $last_update Date of the last update + * @param string $last_update Date of the last update (in "Y-m-d H:i:s" format) * @param integer $max_items Number of maximum items to fetch * @param string $filter Feed items filter (activity, posts or comments) * @param boolean $nocache Wether to bypass caching - * - * @return string XML feed + * @return string XML feed or empty string on error * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function feed($owner_nick, &$last_update, $max_items = 300, $filter = 'activity', $nocache = false) + public static function feed(string $owner_nick, string &$last_update, int $max_items = 300, string $filter = 'activity', bool $nocache = false): string { $stamp = microtime(true); $owner = User::getOwnerDataByNick($owner_nick); if (!$owner) { - return; + return ''; } - $cachekey = "ostatus:feed:" . $owner_nick . ":" . $filter . ":" . $last_update; + $cachekey = 'ostatus:feed:' . $owner_nick . ':' . $filter . ':' . $last_update; $previous_created = $last_update; @@ -1998,11 +2053,16 @@ class OStatus } $check_date = DateTimeFormat::utc($last_update); - $authorid = Contact::getIdForURL($owner["url"]); + $authorid = Contact::getIdForURL($owner['url']); - $condition = ["`uid` = ? AND `received` > ? AND NOT `deleted` - AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?)", - $owner["uid"], $check_date, Item::PRIVATE, Protocol::OSTATUS, Protocol::DFRN]; + $condition = [ + "`uid` = ? AND `received` > ? AND NOT `deleted` AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?)", + $owner['uid'], + $check_date, + Item::PRIVATE, + Protocol::OSTATUS, + Protocol::DFRN, + ]; if ($filter === 'comments') { $condition[0] .= " AND `object-type` = ? "; @@ -2011,7 +2071,7 @@ class OStatus if ($owner['contact-type'] != Contact::TYPE_COMMUNITY) { $condition[0] .= " AND `contact-id` = ? AND `author-id` = ?"; - $condition[] = $owner["id"]; + $condition[] = $owner['id']; $condition[] = $authorid; } @@ -2035,7 +2095,7 @@ class OStatus $item['body'] .= '🍼'; } - if (in_array($item["verb"], [Activity::FOLLOW, Activity::O_UNFOLLOW, Activity::LIKE])) { + if (in_array($item['verb'], [Activity::FOLLOW, Activity::O_UNFOLLOW, Activity::LIKE])) { continue; } @@ -2067,7 +2127,7 @@ class OStatus * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function salmon(array $item, array $owner) + public static function salmon(array $item, array $owner): string { $doc = new DOMDocument('1.0', 'utf-8'); $doc->formatOutput = true; @@ -2091,7 +2151,7 @@ class OStatus * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function isSupportedByContactUrl($url) + public static function isSupportedByContactUrl(string $url): bool { $probe = Probe::uri($url, Protocol::OSTATUS); return $probe['network'] == Protocol::OSTATUS; diff --git a/src/Protocol/Relay.php b/src/Protocol/Relay.php index 8679bbec5b..7414c29315 100644 --- a/src/Protocol/Relay.php +++ b/src/Protocol/Relay.php @@ -55,7 +55,7 @@ class Relay * @param string $url * @return boolean "true" is the post is wanted by the system */ - public static function isSolicitedPost(array $tags, string $body, int $authorid, string $url, string $network = '') + public static function isSolicitedPost(array $tags, string $body, int $authorid, string $url, string $network = ''): bool { $config = DI::config(); @@ -139,6 +139,7 @@ class Relay * * @param array $gserver Global server record * @param array $fields Optional network specific fields + * @return void * @throws \Exception */ public static function updateContact(array $gserver, array $fields = []) @@ -198,6 +199,7 @@ class Relay * The relay contact is a technical contact entry that exists once per server. * * @param array $contact of the relay contact + * @return void */ public static function markForArchival(array $contact) { @@ -229,15 +231,14 @@ class Relay * @param integer $item_id id of the item that is sent * @param array $contacts Previously fetched contacts * @param array $networks Networks of the relay servers - * * @return array of relay servers * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getDirectRelayList(int $item_id) + public static function getDirectRelayList(int $item_id): array { $serverlist = []; - if (!DI::config()->get("system", "relay_directly", false)) { + if (!DI::config()->get('system', 'relay_directly', false)) { return []; } @@ -302,10 +303,10 @@ class Relay * Return a list of relay servers * * @param array $fields Field list - * @return array + * @return array List of relay servers * @throws Exception */ - public static function getList($fields = []):array + 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]); @@ -316,7 +317,7 @@ class Relay * * @param array $gserver Global server record * @param array $fields Fieldlist - * @return array with the contact + * @return array|bool Array with the contact or false on error * @throws \Exception */ private static function getContact(array $gserver, array $fields = ['batch', 'id', 'url', 'name', 'network', 'protocol', 'archive', 'blocked']) @@ -344,6 +345,8 @@ class Relay /** * Resubscribe to all relay servers + * + * @return void */ public static function reSubscribe() { diff --git a/src/Protocol/Salmon.php b/src/Protocol/Salmon.php index 9724f82df7..7a4e8cc94e 100644 --- a/src/Protocol/Salmon.php +++ b/src/Protocol/Salmon.php @@ -40,10 +40,10 @@ class Salmon /** * @param string $uri Uniform Resource Identifier * @param string $keyhash encoded key - * @return mixed + * @return string Key or empty string on any errors * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getKey($uri, $keyhash) + public static function getKey(string $uri, string $keyhash): string { $ret = []; @@ -83,13 +83,13 @@ class Salmon Logger::notice('Key located', ['ret' => $ret]); if (count($ret) == 1) { - // We only found one one key so we don't care if the hash matches. - // If it's the wrong key we'll find out soon enough because - // message verification will fail. This also covers some older - // software which don't supply a keyhash. As long as they only - // have one key we'll be right. - - return $ret[0]; + /* We only found one one key so we don't care if the hash matches. + * If it's the wrong key we'll find out soon enough because + * message verification will fail. This also covers some older + * software which don't supply a keyhash. As long as they only + * have one key we'll be right. + */ + return (string) $ret[0]; } else { foreach ($ret as $a) { $hash = Strings::base64UrlEncode(hash('sha256', $a)); @@ -109,18 +109,18 @@ class Salmon * @return integer * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function slapper($owner, $url, $slap) + public static function slapper(array $owner, string $url, string $slap): int { // does contact have a salmon endpoint? if (!strlen($url)) { - return; + return -1; } if (!$owner['sprvkey']) { Logger::notice(sprintf("user '%s' (%d) does not have a salmon private key. Send failed.", $owner['name'], $owner['uid'])); - return; + return -1; } Logger::info('slapper called for '.$url.'. Data: ' . $slap); @@ -229,7 +229,7 @@ class Salmon * @return string * @throws \Exception */ - public static function salmonKey($pubkey) + public static function salmonKey(string $pubkey): string { Crypto::pemToMe($pubkey, $modulus, $exponent); return 'RSA' . '.' . Strings::base64UrlEncode($modulus, true) . '.' . Strings::base64UrlEncode($exponent, true); diff --git a/src/Render/FriendicaSmarty.php b/src/Render/FriendicaSmarty.php index 50dda5eba1..c6dcef429b 100644 --- a/src/Render/FriendicaSmarty.php +++ b/src/Render/FriendicaSmarty.php @@ -39,12 +39,12 @@ class FriendicaSmarty extends Smarty // setTemplateDir can be set to an array, which Smarty will parse in order. // The order is thus very important here - $template_dirs = ['theme' => "view/theme/$theme/" . self::SMARTY3_TEMPLATE_FOLDER . "/"]; + $template_dirs = ['theme' => "view/theme/$theme/" . self::SMARTY3_TEMPLATE_FOLDER . '/']; if (!empty($theme_info['extends'])) { - $template_dirs = $template_dirs + ['extends' => "view/theme/" . $theme_info["extends"] . "/" . self::SMARTY3_TEMPLATE_FOLDER . "/"]; + $template_dirs = $template_dirs + ['extends' => 'view/theme/' . $theme_info['extends'] . '/' . self::SMARTY3_TEMPLATE_FOLDER . '/']; } - $template_dirs = $template_dirs + ['base' => "view/" . self::SMARTY3_TEMPLATE_FOLDER . "/"]; + $template_dirs = $template_dirs + ['base' => 'view/' . self::SMARTY3_TEMPLATE_FOLDER . '/']; $this->setTemplateDir($template_dirs); $this->setCompileDir('view/smarty3/compiled/'); diff --git a/src/Render/FriendicaSmartyEngine.php b/src/Render/FriendicaSmartyEngine.php index 6fc8f44806..c64fd29e52 100644 --- a/src/Render/FriendicaSmartyEngine.php +++ b/src/Render/FriendicaSmartyEngine.php @@ -48,6 +48,19 @@ final class FriendicaSmartyEngine extends TemplateEngine $this->theme_info = $theme_info; $this->smarty = new FriendicaSmarty($this->theme, $this->theme_info); + /* + * Enable sub-directory splitting for reducing directory descriptor + * size. The default behavior is to put all compiled/cached files into + * one single directory. Under Linux and EXT4 (and maybe other FS) this + * will increase the descriptor's size (which contains information + * about entries inside the described directory. If the descriptor is + * getting to big, the system will slow down as it has to read the + * whole directory descriptor all over again (unless you have tons of + * RAM available + have enabled caching inode tables (aka. + * "descriptors"). Still it won't hurt you. + */ + $this->smarty->setUseSubDirs(true); + if (!is_writable(DI::basePath() . '/view/smarty3')) { $admin_message = DI::l10n()->t('The folder view/smarty3/ must be writable by webserver.'); DI::logger()->critical($admin_message); @@ -69,7 +82,7 @@ final class FriendicaSmartyEngine extends TemplateEngine /** * @inheritDoc */ - public function replaceMacros(string $template, array $vars) + public function replaceMacros(string $template, array $vars): string { if (!Strings::startsWith($template, self::FILE_PREFIX)) { $template = self::STRING_PREFIX . $template; diff --git a/src/Render/TemplateEngine.php b/src/Render/TemplateEngine.php index 6bfbe31971..e160192d36 100644 --- a/src/Render/TemplateEngine.php +++ b/src/Render/TemplateEngine.php @@ -45,6 +45,7 @@ abstract class TemplateEngine * parameter or displays them directly if it's null. * * @param array|null $errors + * @return void */ abstract public function testInstall(array &$errors = null); @@ -53,9 +54,9 @@ abstract class TemplateEngine * * @param string $template * @param array $vars - * @return string + * @return string Template output with replaced macros */ - abstract public function replaceMacros(string $template, array $vars); + abstract public function replaceMacros(string $template, array $vars): string; /** * Returns the template string from a file path and an optional sub-directory from the project root diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index 709267c79f..9f45516f7d 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -64,6 +64,8 @@ class Authentication private $session; /** @var IManagePersonalConfigValues */ private $pConfig; + /** @var string */ + private $remoteAddress; /** * Sets the X-Account-Management-Status header @@ -80,27 +82,29 @@ class Authentication /** * Authentication constructor. * - * @param IManageConfigValues $config - * @param App\Mode $mode - * @param App\BaseURL $baseUrl - * @param L10n $l10n - * @param Database $dba - * @param LoggerInterface $logger - * @param User\Cookie $cookie - * @param IHandleSessions $session - * @param IManagePersonalConfigValues $pConfig + * @param IManageConfigValues $config + * @param App\Mode $mode + * @param App\BaseURL $baseUrl + * @param L10n $l10n + * @param Database $dba + * @param LoggerInterface $logger + * @param User\Cookie $cookie + * @param IHandleSessions $session + * @param IManagePersonalConfigValues $pConfig + * @param App\Request $request */ - public function __construct(IManageConfigValues $config, App\Mode $mode, App\BaseURL $baseUrl, L10n $l10n, Database $dba, LoggerInterface $logger, User\Cookie $cookie, IHandleSessions $session, IManagePersonalConfigValues $pConfig) + public function __construct(IManageConfigValues $config, App\Mode $mode, App\BaseURL $baseUrl, L10n $l10n, Database $dba, LoggerInterface $logger, User\Cookie $cookie, IHandleSessions $session, IManagePersonalConfigValues $pConfig, App\Request $request) { - $this->config = $config; - $this->mode = $mode; - $this->baseUrl = $baseUrl; - $this->l10n = $l10n; - $this->dba = $dba; - $this->logger = $logger; - $this->cookie = $cookie; - $this->session = $session; - $this->pConfig = $pConfig; + $this->config = $config; + $this->mode = $mode; + $this->baseUrl = $baseUrl; + $this->l10n = $l10n; + $this->dba = $dba; + $this->logger = $logger; + $this->cookie = $cookie; + $this->session = $session; + $this->pConfig = $pConfig; + $this->remoteAddress = $request->getRemoteAddress(); } /** @@ -140,7 +144,7 @@ class Authentication // Renew the cookie $this->cookie->send(); - // Do the authentification if not done by now + // Do the authentication if not done by now if (!$this->session->get('authenticated')) { $this->setForUser($a, $user); @@ -163,10 +167,11 @@ class Authentication // already logged in user returning $check = $this->config->get('system', 'paranoia'); // extra paranoia - if the IP changed, log them out - if ($check && ($this->session->get('addr') != $_SERVER['REMOTE_ADDR'])) { + if ($check && ($this->session->get('addr') != $this->remoteAddress)) { $this->logger->notice('Session address changed. Paranoid setting in effect, blocking session. ', [ - 'addr' => $this->session->get('addr'), - 'remote_addr' => $_SERVER['REMOTE_ADDR']] + 'addr' => $this->session->get('addr'), + 'remote_addr' => $this->remoteAddress + ] ); $this->session->clear(); $this->baseUrl->redirect(); @@ -258,13 +263,17 @@ class Authentication ['uid' => User::getIdFromPasswordAuthentication($username, $password)] ); } catch (Exception $e) { - $this->logger->warning('authenticate: failed login attempt', ['action' => 'login', 'username' => $username, 'ip' => $_SERVER['REMOTE_ADDR']]); + $this->logger->warning('authenticate: failed login attempt', ['action' => 'login', 'username' => $username, 'ip' => $this->remoteAddress]); notice($this->l10n->t('Login failed. Please check your credentials.')); $this->baseUrl->redirect(); } if (!$remember) { + $trusted = $this->cookie->get('2fa_cookie_hash') ?? null; $this->cookie->clear(); + if ($trusted) { + $this->cookie->set('2fa_cookie_hash', $trusted); + } } // if we haven't failed up this point, log them in. @@ -295,8 +304,13 @@ class Authentication * @param bool $interactive * @param bool $login_refresh * + * @throws HTTPException\FoundException + * @throws HTTPException\MovedPermanentlyException + * @throws HTTPException\TemporaryRedirectException + * @throws HTTPException\ForbiddenException + * @throws HTTPException\InternalServerErrorException In case of Friendica specific exceptions - * @throws Exception In case of general Exceptions (like SQL Grammar exceptions) + * */ public function setForUser(App $a, array $user_record, bool $login_initial = false, bool $interactive = false, bool $login_refresh = false) { @@ -308,7 +322,7 @@ class Authentication 'page_flags' => $user_record['page-flags'], 'my_url' => $this->baseUrl->get() . '/profile/' . $user_record['nickname'], 'my_address' => $user_record['nickname'] . '@' . substr($this->baseUrl->get(), strpos($this->baseUrl->get(), '://') + 3), - 'addr' => ($_SERVER['REMOTE_ADDR'] ?? '') ?: '0.0.0.0' + 'addr' => $this->remoteAddress, ]); Session::setVisitorsContacts(); @@ -402,11 +416,11 @@ class Authentication } // Case 1b: Check for trusted browser - if ($this->cookie->get('trusted')) { + if ($this->cookie->get('2fa_cookie_hash')) { // Retrieve a trusted_browser model based on cookie hash $trustedBrowserRepository = new TrustedBrowser($this->dba, $this->logger); try { - $trustedBrowser = $trustedBrowserRepository->selectOneByHash($this->cookie->get('trusted')); + $trustedBrowser = $trustedBrowserRepository->selectOneByHash($this->cookie->get('2fa_cookie_hash')); // Verify record ownership if ($trustedBrowser->uid === $uid) { // Update last_used date @@ -415,10 +429,13 @@ class Authentication // Save it to the database $trustedBrowserRepository->save($trustedBrowser); - // Set 2fa session key and return - $this->session->set('2fa', true); + // Only use this entry, if its really trusted, otherwise just update the record and proceed + if ($trustedBrowser->trusted) { + // Set 2fa session key and return + $this->session->set('2fa', true); - return; + return; + } } else { // Invalid trusted cookie value, removing it $this->cookie->unset('trusted'); diff --git a/src/Security/TwoFactor/Exception/TrustedBrowserNotFoundException.php b/src/Security/TwoFactor/Exception/TrustedBrowserNotFoundException.php new file mode 100644 index 0000000000..9262aff5b6 --- /dev/null +++ b/src/Security/TwoFactor/Exception/TrustedBrowserNotFoundException.php @@ -0,0 +1,32 @@ +. + * + */ + +namespace Friendica\Security\TwoFactor\Exception; + +use Exception; + +class TrustedBrowserNotFoundException extends \RuntimeException +{ + public function __construct(string $message = '', Exception $previous = null) + { + parent::__construct($message, 404, $previous); + } +} diff --git a/src/Security/TwoFactor/Exception/TrustedBrowserPersistenceException.php b/src/Security/TwoFactor/Exception/TrustedBrowserPersistenceException.php new file mode 100644 index 0000000000..6d303ea410 --- /dev/null +++ b/src/Security/TwoFactor/Exception/TrustedBrowserPersistenceException.php @@ -0,0 +1,32 @@ +. + * + */ + +namespace Friendica\Security\TwoFactor\Exception; + +use Throwable; + +class TrustedBrowserPersistenceException extends \RuntimeException +{ + public function __construct(string $message = "", Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } +} diff --git a/src/Security/TwoFactor/Factory/TrustedBrowser.php b/src/Security/TwoFactor/Factory/TrustedBrowser.php index 61ec154fcc..13e5925006 100644 --- a/src/Security/TwoFactor/Factory/TrustedBrowser.php +++ b/src/Security/TwoFactor/Factory/TrustedBrowser.php @@ -27,7 +27,12 @@ use Friendica\Util\Strings; class TrustedBrowser extends BaseFactory { - public function createForUserWithUserAgent($uid, $userAgent): \Friendica\Security\TwoFactor\Model\TrustedBrowser + /** + * Creates a new Trusted Browser based on the current user environment + * + * @throws \Exception In case something really unexpected happens + */ + public function createForUserWithUserAgent(int $uid, string $userAgent, bool $trusted): \Friendica\Security\TwoFactor\Model\TrustedBrowser { $trustedHash = Strings::getRandomHex(); @@ -35,6 +40,7 @@ class TrustedBrowser extends BaseFactory $trustedHash, $uid, $userAgent, + $trusted, DateTimeFormat::utcNow() ); } @@ -45,6 +51,7 @@ class TrustedBrowser extends BaseFactory $row['cookie_hash'], $row['uid'], $row['user_agent'], + $row['trusted'], $row['created'], $row['last_used'] ); diff --git a/src/Security/TwoFactor/Model/TrustedBrowser.php b/src/Security/TwoFactor/Model/TrustedBrowser.php index d0a654d5f2..7d2bfca30a 100644 --- a/src/Security/TwoFactor/Model/TrustedBrowser.php +++ b/src/Security/TwoFactor/Model/TrustedBrowser.php @@ -31,6 +31,7 @@ use Friendica\Util\DateTimeFormat; * @property-read $cookie_hash * @property-read $uid * @property-read $user_agent + * @property-read $trusted * @property-read $created * @property-read $last_used * @package Friendica\Model\TwoFactor @@ -40,6 +41,7 @@ class TrustedBrowser extends BaseEntity protected $cookie_hash; protected $uid; protected $user_agent; + protected $trusted; protected $created; protected $last_used; @@ -51,18 +53,26 @@ class TrustedBrowser extends BaseEntity * @param string $cookie_hash * @param int $uid * @param string $user_agent + * @param bool $trusted * @param string $created * @param string|null $last_used */ - public function __construct(string $cookie_hash, int $uid, string $user_agent, string $created, string $last_used = null) + public function __construct(string $cookie_hash, int $uid, string $user_agent, bool $trusted, string $created, string $last_used = null) { $this->cookie_hash = $cookie_hash; - $this->uid = $uid; - $this->user_agent = $user_agent; - $this->created = $created; - $this->last_used = $last_used; + $this->uid = $uid; + $this->user_agent = $user_agent; + $this->trusted = $trusted; + $this->created = $created; + $this->last_used = $last_used; } + /** + * Records if the trusted browser was used + * + * @return void + * @throws \Exception unexpected DateTime exception happened + */ public function recordUse() { $this->last_used = DateTimeFormat::utcNow(); diff --git a/src/Security/TwoFactor/Repository/TrustedBrowser.php b/src/Security/TwoFactor/Repository/TrustedBrowser.php index 2a62fa7007..42dd2b18bb 100644 --- a/src/Security/TwoFactor/Repository/TrustedBrowser.php +++ b/src/Security/TwoFactor/Repository/TrustedBrowser.php @@ -21,10 +21,10 @@ namespace Friendica\Security\TwoFactor\Repository; -use Friendica\Security\TwoFactor\Model; -use Friendica\Security\TwoFactor\Collection\TrustedBrowsers; +use Friendica\Security\TwoFactor; use Friendica\Database\Database; -use Friendica\Network\HTTPException\NotFoundException; +use Friendica\Security\TwoFactor\Exception\TrustedBrowserNotFoundException; +use Friendica\Security\TwoFactor\Exception\TrustedBrowserPersistenceException; use Psr\Log\LoggerInterface; class TrustedBrowser @@ -35,83 +35,122 @@ class TrustedBrowser /** @var LoggerInterface */ protected $logger; - /** @var \Friendica\Security\TwoFactor\Factory\TrustedBrowser */ + /** @var TwoFactor\Factory\TrustedBrowser */ protected $factory; protected static $table_name = '2fa_trusted_browser'; - public function __construct(Database $database, LoggerInterface $logger, \Friendica\Security\TwoFactor\Factory\TrustedBrowser $factory = null) + public function __construct(Database $database, LoggerInterface $logger, TwoFactor\Factory\TrustedBrowser $factory = null) { - $this->db = $database; - $this->logger = $logger; - $this->factory = $factory ?? new \Friendica\Security\TwoFactor\Factory\TrustedBrowser($logger); + $this->db = $database; + $this->logger = $logger; + $this->factory = $factory ?? new TwoFactor\Factory\TrustedBrowser($logger); } /** * @param string $cookie_hash - * @return Model\TrustedBrowser|null - * @throws \Exception + * + * @return TwoFactor\Model\TrustedBrowser|null + * + * @throws TrustedBrowserPersistenceException + * @throws TrustedBrowserNotFoundException */ - public function selectOneByHash(string $cookie_hash): Model\TrustedBrowser + public function selectOneByHash(string $cookie_hash): TwoFactor\Model\TrustedBrowser { - $fields = $this->db->selectFirst(self::$table_name, [], ['cookie_hash' => $cookie_hash]); + try { + $fields = $this->db->selectFirst(self::$table_name, [], ['cookie_hash' => $cookie_hash]); + } catch (\Exception $exception) { + throw new TrustedBrowserPersistenceException(sprintf('Internal server error when retrieving cookie hash \'%s\'', $cookie_hash)); + } if (!$this->db->isResult($fields)) { - throw new NotFoundException(''); + throw new TrustedBrowserNotFoundException(sprintf('Cookie hash \'%s\' not found', $cookie_hash)); } return $this->factory->createFromTableRow($fields); } - public function selectAllByUid(int $uid): TrustedBrowsers + /** + * @param int $uid + * + * @return TwoFactor\Collection\TrustedBrowsers + * + * @throws TrustedBrowserPersistenceException + */ + public function selectAllByUid(int $uid): TwoFactor\Collection\TrustedBrowsers { - $rows = $this->db->selectToArray(self::$table_name, [], ['uid' => $uid]); + try { + $rows = $this->db->selectToArray(self::$table_name, [], ['uid' => $uid]); - $trustedBrowsers = []; - foreach ($rows as $fields) { - $trustedBrowsers[] = $this->factory->createFromTableRow($fields); + $trustedBrowsers = []; + foreach ($rows as $fields) { + $trustedBrowsers[] = $this->factory->createFromTableRow($fields); + } + return new TwoFactor\Collection\TrustedBrowsers($trustedBrowsers); + + } catch (\Exception $exception) { + throw new TrustedBrowserPersistenceException(sprintf('selection for uid \'%s\' wasn\'t successful.', $uid)); } - - return new TrustedBrowsers($trustedBrowsers); } /** - * @param Model\TrustedBrowser $trustedBrowser + * @param TwoFactor\Model\TrustedBrowser $trustedBrowser + * * @return bool - * @throws \Exception + * + * @throws TrustedBrowserPersistenceException */ - public function save(Model\TrustedBrowser $trustedBrowser): bool + public function save(TwoFactor\Model\TrustedBrowser $trustedBrowser): bool { - return $this->db->insert(self::$table_name, $trustedBrowser->toArray(), $this->db::INSERT_UPDATE); + try { + return $this->db->insert(self::$table_name, $trustedBrowser->toArray(), $this->db::INSERT_UPDATE); + } catch (\Exception $exception) { + throw new TrustedBrowserPersistenceException(sprintf('Couldn\'t save trusted Browser with cookie_hash \'%s\'', $trustedBrowser->cookie_hash)); + } } /** - * @param Model\TrustedBrowser $trustedBrowser + * @param TwoFactor\Model\TrustedBrowser $trustedBrowser + * * @return bool - * @throws \Exception + * + * @throws TrustedBrowserPersistenceException */ - public function remove(Model\TrustedBrowser $trustedBrowser): bool + public function remove(TwoFactor\Model\TrustedBrowser $trustedBrowser): bool { - return $this->db->delete(self::$table_name, ['cookie_hash' => $trustedBrowser->cookie_hash]); + try { + return $this->db->delete(self::$table_name, ['cookie_hash' => $trustedBrowser->cookie_hash]); + } catch (\Exception $exception) { + throw new TrustedBrowserPersistenceException(sprintf('Couldn\'t delete trusted Browser with cookie hash \'%s\'', $trustedBrowser->cookie_hash)); + } } /** * @param int $local_user * @param string $cookie_hash + * * @return bool - * @throws \Exception + * + * @throws TrustedBrowserPersistenceException */ public function removeForUser(int $local_user, string $cookie_hash): bool { - return $this->db->delete(self::$table_name, ['cookie_hash' => $cookie_hash,'uid' => $local_user]); + try { + return $this->db->delete(self::$table_name, ['cookie_hash' => $cookie_hash, 'uid' => $local_user]); + } catch (\Exception $exception) { + throw new TrustedBrowserPersistenceException(sprintf('Couldn\'t delete trusted Browser for user \'%s\' and cookie hash \'%s\'', $local_user, $cookie_hash)); + } } /** * @param int $local_user * @return bool - * @throws \Exception */ public function removeAllForUser(int $local_user): bool { - return $this->db->delete(self::$table_name, ['uid' => $local_user]); + try { + return $this->db->delete(self::$table_name, ['uid' => $local_user]); + } catch (\Exception $exception) { + throw new TrustedBrowserPersistenceException(sprintf('Couldn\'t delete trusted Browsers for user \'%s\'', $local_user)); + } } } diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 6e892cf254..321bdc9e6b 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -119,7 +119,7 @@ abstract class MailBuilder { $this->recipientUid = $user['uid'] ?? 0; try { - $this->l10n = $user['language'] ? $this->l10n->withLang($user['language']) : $this->l10n; + $this->l10n = isset($user['language']) ? $this->l10n->withLang($user['language']) : $this->l10n; } catch (Exception $e) { $this->logger->warning('cannot use language.', ['user' => $user, 'exception' => $e]); } @@ -164,7 +164,7 @@ abstract class MailBuilder * * @return string[][] */ - public function getHeaders() + public function getHeaders(): array { return $this->headers; } @@ -182,7 +182,7 @@ abstract class MailBuilder * @param string[][] $headers * @return $this */ - public function withHeaders(array $headers) + public function withHeaders(array $headers): MailBuilder { $this->headers = $headers; diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index 1341aaf33e..d045698233 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -141,7 +141,7 @@ class Emailer $countMessageId += count($value); } } - if ($countMessageId > 0) { + if ($countMessageId > 1) { $this->logger->warning('More than one Message-ID found - RFC violation', ['email' => $email]); } diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index 4a4f6a5710..9f732acb6e 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -55,7 +55,7 @@ class HTTPSignature * @return array with verification data * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function verifyMagic($key) + public static function verifyMagic(string $key): array { $headers = null; $spoofable = false; @@ -139,7 +139,7 @@ class HTTPSignature * * @return array */ - public static function createSig($head, $prvkey, $keyid = 'Key') + public static function createSig(array $head, string $prvkey, string $keyid = 'Key'): array { $return_headers = []; if (!empty($head)) { @@ -166,7 +166,7 @@ class HTTPSignature * * @return array */ - private static function sign($head, $prvkey, $alg = 'sha256') + private static function sign(array $head, string $prvkey, string $alg = 'sha256'): array { $ret = []; $headers = ''; @@ -204,7 +204,7 @@ class HTTPSignature * - \e string \b signature * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function parseSigheader($header) + public static function parseSigheader(string $header): array { // Remove obsolete folds $header = preg_replace('/\n\s+/', ' ', $header); @@ -251,7 +251,7 @@ class HTTPSignature * @return string Decrypted signature string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function decryptSigheader(array $headers, string $prvkey) + private static function decryptSigheader(array $headers, string $prvkey): string { if (!empty($headers['iv']) && !empty($headers['key']) && !empty($headers['data'])) { return Crypto::unencapsulate($headers, $prvkey); @@ -341,7 +341,7 @@ class HTTPSignature * @param boolean $success Transmission status * @param boolean $shared The inbox is a shared inbox */ - static public function setInboxStatus($url, $success, $shared = false) + static public function setInboxStatus(string $url, bool $success, bool $shared = false) { $now = DateTimeFormat::utcNow(); @@ -403,21 +403,21 @@ class HTTPSignature * @return array JSON array * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function fetch($request, $uid) + public static function fetch(string $request, int $uid): array { $curlResult = self::fetchRaw($request, $uid); if (empty($curlResult)) { - return false; + return []; } if (!$curlResult->isSuccess() || empty($curlResult->getBody())) { - return false; + return []; } $content = json_decode($curlResult->getBody(), true); if (empty($content) || !is_array($content)) { - return false; + return []; } return $content; @@ -438,7 +438,7 @@ class HTTPSignature * @return \Friendica\Network\HTTPClient\Capability\ICanHandleHttpResponses CurlResult * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function fetchRaw($request, $uid = 0, $opts = [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::JSON_AS]]) + public static function fetchRaw(string $request, int $uid = 0, array $opts = [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::JSON_AS]]) { $header = []; @@ -488,13 +488,13 @@ class HTTPSignature /** * Gets a signer from a given HTTP request * - * @param $content - * @param $http_headers + * @param string $content + * @param array $http_headers * - * @return string Signer + * @return string|null|false Signer * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getSigner($content, $http_headers) + public static function getSigner(string $content, array $http_headers) { if (empty($http_headers['HTTP_SIGNATURE'])) { Logger::debug('No HTTP_SIGNATURE header'); @@ -686,13 +686,13 @@ class HTTPSignature /** * fetches a key for a given id and actor * - * @param $id - * @param $actor + * @param string $id + * @param string $actor * * @return array with actor url and public key * @throws \Exception */ - private static function fetchKey($id, $actor) + private static function fetchKey(string $id, string $actor): array { $url = (strpos($id, '#') ? substr($id, 0, strpos($id, '#')) : $id); @@ -709,6 +709,6 @@ class HTTPSignature } Logger::notice('Key could not be fetched', ['url' => $url, 'actor' => $actor]); - return false; + return []; } } diff --git a/src/Util/Images.php b/src/Util/Images.php index c268916cc9..eb1e8c4375 100644 --- a/src/Util/Images.php +++ b/src/Util/Images.php @@ -34,23 +34,23 @@ class Images /** * Maps Mime types to Imagick formats * - * @return array + * @return array Format map */ public static function getFormatsMap() { - $m = [ + return [ 'image/jpeg' => 'JPG', + 'image/jpg' => 'JPG', 'image/png' => 'PNG', - 'image/gif' => 'GIF' + 'image/gif' => 'GIF', ]; - - return $m; } /** - * Return file extension for mime type - * @param string $mimetype - * @return string + * Return file extension for MIME type + * + * @param string $mimetype MIME type + * @return string File extension for MIME type */ public static function getExtensionByMimeType(string $mimetype): string { @@ -63,9 +63,14 @@ class Images $imagetype = IMAGETYPE_GIF; break; - default: + case 'image/jpeg': + case 'image/jpg': $imagetype = IMAGETYPE_JPEG; break; + + default: // Unknown type must be a blob then + return 'blob'; + break; } return image_type_to_extension($imagetype); @@ -76,11 +81,13 @@ class Images * * @return array */ - public static function supportedTypes() + public static function supportedTypes(): array { $types = [ - 'image/jpeg' => 'jpg' + 'image/jpeg' => 'jpg', + 'image/jpg' => 'jpg', ]; + if (class_exists('Imagick')) { // Imagick::queryFormats won't help us a lot there... // At least, not yet, other parts of friendica uses this array @@ -102,21 +109,20 @@ class Images * * @param string $image_data Image data * @param string $filename File name (for guessing the type via the extension) - * @param string $mime default mime type - * - * @return string + * @param string $default Default MIME type + * @return string MIME type * @throws \Exception */ - public static function getMimeTypeByData(string $image_data, string $filename = '', string $mime = '') + public static function getMimeTypeByData(string $image_data, string $filename = '', string $default = ''): string { - if (substr($mime, 0, 6) == 'image/') { - Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $mime]); - return $mime; + if (substr($default, 0, 6) == 'image/') { + Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $default]); + return $default; } $image = @getimagesizefromstring($image_data); if (!empty($image['mime'])) { - Logger::info('Mime type detected via data', ['filename' => $filename, 'default' => $mime, 'mime' => $image['mime']]); + Logger::info('Mime type detected via data', ['filename' => $filename, 'default' => $default, 'mime' => $image['mime']]); return $image['mime']; } @@ -128,21 +134,20 @@ class Images * * @param string $sourcefile Source file of the image * @param string $filename File name (for guessing the type via the extension) - * @param string $mime default mime type - * - * @return string + * @param string $default default MIME type + * @return string MIME type * @throws \Exception */ - public static function getMimeTypeBySource(string $sourcefile, string $filename = '', string $mime = '') + public static function getMimeTypeBySource(string $sourcefile, string $filename = '', string $default = ''): string { - if (substr($mime, 0, 6) == 'image/') { - Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $mime]); - return $mime; + if (substr($default, 0, 6) == 'image/') { + Logger::info('Using default mime type', ['filename' => $filename, 'mime' => $default]); + return $default; } $image = @getimagesize($sourcefile); if (!empty($image['mime'])) { - Logger::info('Mime type detected via file', ['filename' => $filename, 'default' => $mime, 'image' => $image]); + Logger::info('Mime type detected via file', ['filename' => $filename, 'default' => $default, 'image' => $image]); return $image['mime']; } @@ -150,14 +155,13 @@ class Images } /** - * Guess image mimetype from the filename + * Guess image MIME type from the filename's extension * - * @param string $filename Image filename - * - * @return string + * @param string $filename Image filename + * @return string Guessed MIME type by extension * @throws \Exception */ - public static function guessTypeByExtension(string $filename) + public static function guessTypeByExtension(string $filename): string { $ext = pathinfo(parse_url($filename, PHP_URL_PATH), PATHINFO_EXTENSION); $types = self::supportedTypes(); @@ -173,11 +177,13 @@ class Images } /** + * Gets info array from given URL, cached data has priority + * * @param string $url - * @return array + * @return array Info * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getInfoFromURLCached($url) + public static function getInfoFromURLCached(string $url): array { $data = []; @@ -195,15 +201,17 @@ class Images DI::cache()->set($cacheKey, $data); } - return $data; + return $data ?? []; } /** + * Gets info from URL uncached + * * @param string $url - * @return array + * @return array Info array * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function getInfoFromURL($url) + public static function getInfoFromURL(string $url): array { $data = []; @@ -239,16 +247,18 @@ class Images $data['size'] = $filesize; } - return $data; + return is_array($data) ? $data : []; } /** - * @param integer $width - * @param integer $height - * @param integer $max - * @return array + * Returns scaling information + * + * @param integer $width Width + * @param integer $height Height + * @param integer $max Max width/height + * @return array Scaling dimensions */ - public static function getScalingDimensions($width, $height, $max) + public static function getScalingDimensions(int $width, int $height, int $max): array { if ((!$width) || (!$height)) { return ['width' => 0, 'height' => 0]; diff --git a/src/Util/LDSignature.php b/src/Util/LDSignature.php index b5a55ea359..ed6030145d 100644 --- a/src/Util/LDSignature.php +++ b/src/Util/LDSignature.php @@ -31,12 +31,24 @@ use Friendica\Model\APContact; */ class LDSignature { - public static function isSigned($data) + /** + * Checks if element 'signature' is found and not empty + * + * @param array $data + * @return bool + */ + public static function isSigned(array $data): bool { return !empty($data['signature']); } - public static function getSigner($data) + /** + * Returns actor (signer) from given data + * + * @param array $data + * @return mixed Returns actor or false on error + */ + public static function getSigner(array $data) { if (!self::isSigned($data)) { return false; @@ -66,13 +78,20 @@ class LDSignature } } - public static function sign($data, $owner) + /** + * Signs given data by owner's signature + * + * @param array $data Data to sign + * @param array $owner Owner information, like URL + * @return array Merged array of $data and signature + */ + public static function sign(array $data, array $owner): array { $options = [ 'type' => 'RsaSignature2017', 'nonce' => Strings::getRandomHex(64), 'creator' => $owner['url'] . '#main-key', - 'created' => DateTimeFormat::utcNow(DateTimeFormat::ATOM) + 'created' => DateTimeFormat::utcNow(DateTimeFormat::ATOM), ]; $ohash = self::hash(self::signableOptions($options)); @@ -82,13 +101,25 @@ class LDSignature return array_merge($data, ['signature' => $options]); } - private static function signableData($data) + /** + * Removes element 'signature' from array + * + * @param array $data + * @return array With no element 'signature' + */ + private static function signableData(array $data): array { unset($data['signature']); return $data; } - private static function signableOptions($options) + /** + * Removes some elements and adds '@context' to it + * + * @param array $options + * @return array With some removed elements and added '@context' element + */ + private static function signableOptions(array $options): array { $newopts = ['@context' => 'https://w3id.org/identity/v1']; @@ -99,7 +130,13 @@ class LDSignature return array_merge($newopts, $options); } - private static function hash($obj) + /** + * Hashes normalized object + * + * @param ??? $obj + * @return string SHA256 hash + */ + private static function hash($obj): string { return hash('sha256', JsonLD::normalize($obj)); } diff --git a/src/Util/Mimetype.php b/src/Util/Mimetype.php index d7a702d71c..ca57648771 100644 --- a/src/Util/Mimetype.php +++ b/src/Util/Mimetype.php @@ -29,7 +29,7 @@ class Mimetype * @param string $filename filename * @return mixed array or string */ - public static function getContentType($filename) + public static function getContentType(string $filename) { $mime_types = [ diff --git a/src/Util/Network.php b/src/Util/Network.php index 2cc603e501..23def7e57f 100644 --- a/src/Util/Network.php +++ b/src/Util/Network.php @@ -101,7 +101,7 @@ class Network * @param string $addr The email address * @return boolean True if it's a valid email address, false if it's not */ - public static function isEmailDomainValid(string $addr) + public static function isEmailDomainValid(string $addr): bool { if (DI::config()->get('system', 'disable_email_validation')) { return true; @@ -132,7 +132,7 @@ class Network * @param string $url URL which get tested * @return boolean True if url is allowed otherwise return false */ - public static function isUrlAllowed(string $url) + public static function isUrlAllowed(string $url): bool { $h = @parse_url($url); @@ -177,7 +177,7 @@ class Network * * @return boolean */ - public static function isUrlBlocked(string $url) + public static function isUrlBlocked(string $url): bool { $host = @parse_url($url, PHP_URL_HOST); if (!$host) { @@ -206,7 +206,7 @@ class Network * * @return boolean */ - public static function isRedirectBlocked(string $url) + public static function isRedirectBlocked(string $url): bool { $host = @parse_url($url, PHP_URL_HOST); if (!$host) { @@ -237,7 +237,7 @@ class Network * or if allowed list is not configured * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function isEmailDomainAllowed(string $email) + public static function isEmailDomainAllowed(string $email): bool { $domain = strtolower(substr($email, strpos($email, '@') + 1)); if (!$domain) { @@ -261,7 +261,7 @@ class Network * @param array $domain_list * @return boolean */ - public static function isDomainAllowed(string $domain, array $domain_list) + public static function isDomainAllowed(string $domain, array $domain_list): bool { $found = false; @@ -276,7 +276,7 @@ class Network return $found; } - public static function lookupAvatarByEmail(string $email) + public static function lookupAvatarByEmail(string $email): string { $avatar['size'] = 300; $avatar['email'] = $email; @@ -299,11 +299,12 @@ class Network * @param string $url Any user-submitted URL that may contain tracking params * @return string The same URL stripped of tracking parameters */ - public static function stripTrackingQueryParams(string $url) + public static function stripTrackingQueryParams(string $url): string { $urldata = parse_url($url); - if (!empty($urldata["query"])) { - $query = $urldata["query"]; + + if (!empty($urldata['query'])) { + $query = $urldata['query']; parse_str($query, $querydata); if (is_array($querydata)) { @@ -311,30 +312,32 @@ class Network if (in_array( $param, [ - "utm_source", "utm_medium", "utm_term", "utm_content", "utm_campaign", - "wt_mc", "pk_campaign", "pk_kwd", "mc_cid", "mc_eid", - "fb_action_ids", "fb_action_types", "fb_ref", - "awesm", "wtrid", - "woo_campaign", "woo_source", "woo_medium", "woo_content", "woo_term"] + 'utm_source', 'utm_medium', 'utm_term', 'utm_content', 'utm_campaign', + // As seen from Purism + 'mtm_source', 'mtm_medium', 'mtm_term', 'mtm_content', 'mtm_campaign', + 'wt_mc', 'pk_campaign', 'pk_kwd', 'mc_cid', 'mc_eid', + 'fb_action_ids', 'fb_action_types', 'fb_ref', + 'awesm', 'wtrid', + 'woo_campaign', 'woo_source', 'woo_medium', 'woo_content', 'woo_term'] ) ) { - $pair = $param . "=" . urlencode($value); - $url = str_replace($pair, "", $url); + $pair = $param . '=' . urlencode($value); + $url = str_replace($pair, '', $url); // Second try: if the url isn't encoded completely - $pair = $param . "=" . str_replace(" ", "+", $value); - $url = str_replace($pair, "", $url); + $pair = $param . '=' . str_replace(' ', '+', $value); + $url = str_replace($pair, '', $url); // Third try: Maybey the url isn't encoded at all - $pair = $param . "=" . $value; - $url = str_replace($pair, "", $url); + $pair = $param . '=' . $value; + $url = str_replace($pair, '', $url); - $url = str_replace(["?&", "&&"], ["?", ""], $url); + $url = str_replace(['?&', '&&'], ['?', ''], $url); } } } - if (substr($url, -1, 1) == "?") { + if (substr($url, -1, 1) == '?') { $url = substr($url, 0, -1); } } @@ -355,8 +358,10 @@ class Network return $url; } - $base = ['scheme' => parse_url($basepath, PHP_URL_SCHEME), - 'host' => parse_url($basepath, PHP_URL_HOST)]; + $base = [ + 'scheme' => parse_url($basepath, PHP_URL_SCHEME), + 'host' => parse_url($basepath, PHP_URL_HOST), + ]; $parts = array_merge($base, parse_url('/' . ltrim($url, '/'))); return self::unparseURL($parts); @@ -367,12 +372,12 @@ class Network * * @param string $url1 * @param string $url2 - * @return string The matching part + * @return string The matching part or empty string on error */ - public static function getUrlMatch(string $url1, string $url2) + public static function getUrlMatch(string $url1, string $url2): string { - if (($url1 == "") || ($url2 == "")) { - return ""; + if (($url1 == '') || ($url2 == '')) { + return ''; } $url1 = Strings::normaliseLink($url1); @@ -381,67 +386,67 @@ class Network $parts1 = parse_url($url1); $parts2 = parse_url($url2); - if (!isset($parts1["host"]) || !isset($parts2["host"])) { - return ""; + if (!isset($parts1['host']) || !isset($parts2['host'])) { + return ''; } - if (empty($parts1["scheme"])) { - $parts1["scheme"] = ''; + if (empty($parts1['scheme'])) { + $parts1['scheme'] = ''; } - if (empty($parts2["scheme"])) { - $parts2["scheme"] = ''; + if (empty($parts2['scheme'])) { + $parts2['scheme'] = ''; } - if ($parts1["scheme"] != $parts2["scheme"]) { - return ""; + if ($parts1['scheme'] != $parts2['scheme']) { + return ''; } - if (empty($parts1["host"])) { - $parts1["host"] = ''; + if (empty($parts1['host'])) { + $parts1['host'] = ''; } - if (empty($parts2["host"])) { - $parts2["host"] = ''; + if (empty($parts2['host'])) { + $parts2['host'] = ''; } - if ($parts1["host"] != $parts2["host"]) { - return ""; + if ($parts1['host'] != $parts2['host']) { + return ''; } - if (empty($parts1["port"])) { - $parts1["port"] = ''; + if (empty($parts1['port'])) { + $parts1['port'] = ''; } - if (empty($parts2["port"])) { - $parts2["port"] = ''; + if (empty($parts2['port'])) { + $parts2['port'] = ''; } - if ($parts1["port"] != $parts2["port"]) { - return ""; + if ($parts1['port'] != $parts2['port']) { + return ''; } - $match = $parts1["scheme"]."://".$parts1["host"]; + $match = $parts1['scheme'] . '://' . $parts1['host']; - if ($parts1["port"]) { - $match .= ":".$parts1["port"]; + if ($parts1['port']) { + $match .= ':' . $parts1['port']; } - if (empty($parts1["path"])) { - $parts1["path"] = ''; + if (empty($parts1['path'])) { + $parts1['path'] = ''; } - if (empty($parts2["path"])) { - $parts2["path"] = ''; + if (empty($parts2['path'])) { + $parts2['path'] = ''; } - $pathparts1 = explode("/", $parts1["path"]); - $pathparts2 = explode("/", $parts2["path"]); + $pathparts1 = explode('/', $parts1['path']); + $pathparts2 = explode('/', $parts2['path']); $i = 0; - $path = ""; + $path = ''; do { $path1 = $pathparts1[$i] ?? ''; $path2 = $pathparts2[$i] ?? ''; if ($path1 == $path2) { - $path .= $path1."/"; + $path .= $path1 . '/'; } } while (($path1 == $path2) && ($i++ <= count($pathparts1))); @@ -454,11 +459,10 @@ class Network * Glue url parts together * * @param array $parsed URL parts - * - * @return string The glued URL. + * @return string|null The glued URL or null on error * @deprecated since version 2021.12, use GuzzleHttp\Psr7\Uri::fromParts($parts) instead */ - public static function unparseURL(array $parsed) + public static function unparseURL(array $parsed): string { $get = function ($key) use ($parsed) { return isset($parsed[$key]) ? $parsed[$key] : null; @@ -471,15 +475,15 @@ class Network $scheme = $get('scheme'); $query = $get('query'); $fragment = $get('fragment'); - $authority = ($userinfo !== null ? $userinfo."@" : '') . + $authority = ($userinfo !== null ? $userinfo . '@' : '') . $get('host') . ($port ? ":$port" : ''); - return (strlen($scheme) ? $scheme.":" : '') . - (strlen($authority) ? "//".$authority : '') . + return (strlen($scheme) ? $scheme . ':' : '') . + (strlen($authority) ? '//' . $authority : '') . $get('path') . - (strlen($query) ? "?".$query : '') . - (strlen($fragment) ? "#".$fragment : ''); + (strlen($query) ? '?' . $query : '') . + (strlen($fragment) ? '#' . $fragment : ''); } /** @@ -509,11 +513,10 @@ class Network /** * Switch the scheme of an url between http and https * - * @param string $url URL - * - * @return string switched URL + * @param string $url + * @return string Switched URL */ - public static function switchScheme(string $url) + public static function switchScheme(string $url): string { $scheme = parse_url($url, PHP_URL_SCHEME); if (empty($scheme)) { @@ -536,7 +539,7 @@ class Network * @param array $additionalParams Associative array of parameters * @return string */ - public static function appendQueryParam(string $path, array $additionalParams) + public static function appendQueryParam(string $path, array $additionalParams): string { $parsed = parse_url($path); @@ -560,6 +563,7 @@ class Network * * @param string $etag The page etag * @param string $last_modified The page last modification UTC date + * @return void * @throws \Exception */ public static function checkEtagModified(string $etag, string $last_modified) @@ -599,7 +603,7 @@ class Network * @param string $url * @return bool */ - public static function isLocalLink(string $url) + public static function isLocalLink(string $url): bool { return (strpos(Strings::normaliseLink($url), Strings::normaliseLink(DI::baseUrl())) !== false); } @@ -610,7 +614,7 @@ class Network * @param string $url * @return bool */ - public static function isValidHttpUrl(string $url) + public static function isValidHttpUrl(string $url): bool { $scheme = parse_url($url, PHP_URL_SCHEME); return !empty($scheme) && in_array($scheme, ['http', 'https']) && parse_url($url, PHP_URL_HOST); diff --git a/src/Util/ParseUrl.php b/src/Util/ParseUrl.php index 8d83296758..0183d6b14a 100644 --- a/src/Util/ParseUrl.php +++ b/src/Util/ParseUrl.php @@ -60,7 +60,7 @@ class ParseUrl * @param int $timeout * @return array content type */ - public static function getContentType(string $url, string $accept = HttpClientAccept::DEFAULT, int $timeout = 0) + public static function getContentType(string $url, string $accept = HttpClientAccept::DEFAULT, int $timeout = 0): array { if (!empty($timeout)) { $options = [HttpClientOptions::TIMEOUT => $timeout]; @@ -108,7 +108,7 @@ class ParseUrl * @see ParseUrl::getSiteinfo() for more information about scraping * embeddable content */ - public static function getSiteinfoCached($url, $do_oembed = true): array + public static function getSiteinfoCached(string $url, bool $do_oembed = true): array { if (empty($url)) { return [ @@ -187,7 +187,7 @@ class ParseUrl * * @endverbatim */ - public static function getSiteinfo($url, $do_oembed = true, $count = 1) + public static function getSiteinfo(string $url, bool $do_oembed = true, int $count = 1) { if (empty($url)) { return [ @@ -550,12 +550,15 @@ class ParseUrl { if (!empty($siteinfo['images'])) { array_walk($siteinfo['images'], function (&$image) use ($page_url) { - // According to the specifications someone could place a picture url into the content field as well. - // But this doesn't seem to happen in the wild, so we don't cover it here. + /* + * According to the specifications someone could place a picture + * URL into the content field as well. But this doesn't seem to + * happen in the wild, so we don't cover it here. + */ if (!empty($image['url'])) { $image['url'] = self::completeUrl($image['url'], $page_url); $photodata = Images::getInfoFromURLCached($image['url']); - if (!empty($photodata) && ($photodata[0] > 50) && ($photodata[1] > 50)) { + if (($photodata) && ($photodata[0] > 50) && ($photodata[1] > 50)) { $image['src'] = $image['url']; $image['width'] = $photodata[0]; $image['height'] = $photodata[1]; @@ -640,15 +643,16 @@ class ParseUrl * @param string $string Tags * @return array with formatted Hashtags */ - public static function convertTagsToArray($string) + public static function convertTagsToArray(string $string): array { $arr_tags = str_getcsv($string); if (count($arr_tags)) { // add the # sign to every tag - array_walk($arr_tags, ["self", "arrAddHashes"]); + array_walk($arr_tags, ['self', 'arrAddHashes']); return $arr_tags; } + return []; } /** @@ -660,9 +664,9 @@ class ParseUrl * @param int $k Counter for internal use * @return void */ - private static function arrAddHashes(&$tag, $k) + private static function arrAddHashes(string &$tag, int $k) { - $tag = "#" . $tag; + $tag = '#' . $tag; } /** @@ -679,41 +683,41 @@ class ParseUrl * * @return string The url with a scheme */ - private static function completeUrl($url, $scheme) + private static function completeUrl(string $url, string $scheme): string { $urlarr = parse_url($url); // If the url does allready have an scheme // we can stop the process here - if (isset($urlarr["scheme"])) { - return($url); + if (isset($urlarr['scheme'])) { + return $url; } $schemearr = parse_url($scheme); - $complete = $schemearr["scheme"]."://".$schemearr["host"]; + $complete = $schemearr['scheme'] . '://' . $schemearr['host']; - if (!empty($schemearr["port"])) { - $complete .= ":".$schemearr["port"]; + if (!empty($schemearr['port'])) { + $complete .= ':' . $schemearr['port']; } - if (!empty($urlarr["path"])) { - if (strpos($urlarr["path"], "/") !== 0) { - $complete .= "/"; + if (!empty($urlarr['path'])) { + if (strpos($urlarr['path'], '/') !== 0) { + $complete .= '/'; } - $complete .= $urlarr["path"]; + $complete .= $urlarr['path']; } - if (!empty($urlarr["query"])) { - $complete .= "?".$urlarr["query"]; + if (!empty($urlarr['query'])) { + $complete .= '?' . $urlarr['query']; } - if (!empty($urlarr["fragment"])) { - $complete .= "#".$urlarr["fragment"]; + if (!empty($urlarr['fragment'])) { + $complete .= '#' . $urlarr['fragment']; } - return($complete); + return $complete; } /** @@ -723,7 +727,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseParts(array $siteinfo, array $jsonld) + private static function parseParts(array $siteinfo, array $jsonld): array { if (!empty($jsonld['@graph']) && is_array($jsonld['@graph'])) { foreach ($jsonld['@graph'] as $part) { @@ -768,7 +772,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLd(array $siteinfo, array $jsonld) + private static function parseJsonLd(array $siteinfo, array $jsonld): array { $type = JsonLD::fetchElement($jsonld, '@type'); if (empty($type)) { @@ -861,7 +865,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLdAuthor(array $siteinfo, array $jsonld) + private static function parseJsonLdAuthor(array $siteinfo, array $jsonld): array { $jsonldinfo = []; @@ -945,7 +949,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLdArticle(array $siteinfo, array $jsonld) + private static function parseJsonLdArticle(array $siteinfo, array $jsonld): array { $jsonldinfo = []; @@ -1015,7 +1019,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLdWebPage(array $siteinfo, array $jsonld) + private static function parseJsonLdWebPage(array $siteinfo, array $jsonld): array { $jsonldinfo = []; @@ -1054,7 +1058,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLdWebSite(array $siteinfo, array $jsonld) + private static function parseJsonLdWebSite(array $siteinfo, array $jsonld): array { $jsonldinfo = []; @@ -1092,7 +1096,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLdWebOrganization(array $siteinfo, array $jsonld) + private static function parseJsonLdWebOrganization(array $siteinfo, array $jsonld): array { $jsonldinfo = []; @@ -1138,7 +1142,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLdWebPerson(array $siteinfo, array $jsonld) + private static function parseJsonLdWebPerson(array $siteinfo, array $jsonld): array { $jsonldinfo = []; @@ -1183,7 +1187,7 @@ class ParseUrl * @param array $jsonld * @return array siteinfo */ - private static function parseJsonLdMediaObject(array $siteinfo, array $jsonld, string $name) + private static function parseJsonLdMediaObject(array $siteinfo, array $jsonld, string $name): array { $media = []; diff --git a/src/Util/PidFile.php b/src/Util/PidFile.php index 6f8233a6a0..38408bcf4b 100644 --- a/src/Util/PidFile.php +++ b/src/Util/PidFile.php @@ -97,7 +97,8 @@ class PidFile * * @return boolean|string PID or "false" if not created */ - static public function create($file) { + static public function create(string $file) + { $pid = self::pidFromFile($file); // We have a process id? then we quit @@ -119,7 +120,8 @@ class PidFile * * @return boolean Is it running? */ - static public function delete($file) { + static public function delete(string $file): bool + { return @unlink($file); } } diff --git a/src/Util/Proxy.php b/src/Util/Proxy.php index 16f635e3a0..ed0ae8affc 100644 --- a/src/Util/Proxy.php +++ b/src/Util/Proxy.php @@ -76,11 +76,10 @@ class Proxy * * @param string $url The URL to proxyfy * @param string $size One of the Proxy::SIZE_* constants - * * @return string The proxyfied URL or relative path * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function proxifyUrl($url, $size = '') + public static function proxifyUrl(string $url, string $size = ''): string { if (!DI::config()->get('system', 'proxify_content')) { return $url; @@ -133,11 +132,10 @@ class Proxy * proxy storage directory. * * @param string $html Un-proxified HTML code - * * @return string Proxified HTML code * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function proxifyHtml($html) + public static function proxifyHtml(string $html): string { $html = str_replace(Strings::normaliseLink(DI::baseUrl()) . '/', DI::baseUrl() . '/', $html); @@ -151,7 +149,7 @@ class Proxy * @return boolean * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function isLocalImage($url) + public static function isLocalImage(string $url): bool { if (substr($url, 0, 1) == '/') { return true; @@ -170,7 +168,7 @@ class Proxy * @param string $url URL to parse * @return array Associative array of query string parameters */ - private static function parseQuery($url) + private static function parseQuery(string $url): array { $query = parse_url($url, PHP_URL_QUERY); $query = html_entity_decode($query); @@ -187,7 +185,7 @@ class Proxy * @return string Proxified HTML image tag * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function replaceUrl(array $matches) + private static function replaceUrl(array $matches): string { // if the picture seems to be from another picture cache then take the original source $queryvar = self::parseQuery($matches[2]); diff --git a/src/Util/ReversedFileReader.php b/src/Util/ReversedFileReader.php index 0566002de2..cda78ad0ab 100644 --- a/src/Util/ReversedFileReader.php +++ b/src/Util/ReversedFileReader.php @@ -55,7 +55,7 @@ class ReversedFileReader implements \Iterator * @param string $filename File to open * @return $this */ - public function open(string $filename) + public function open(string $filename): ReversedFileReader { $this->fh = fopen($filename, 'r'); if (!$this->fh) { @@ -73,9 +73,10 @@ class ReversedFileReader implements \Iterator /** * Read $size bytes behind last position * + * @param int $size * @return string */ - private function _read($size) + private function _read(int $size): string { $this->pos -= $size; fseek($this->fh, $this->pos); @@ -86,7 +87,7 @@ class ReversedFileReader implements \Iterator * Read next line from end of file * Return null if no lines are left to read * - * @return ?string + * @return string|null Depending on data being buffered */ private function _readline() { @@ -140,7 +141,7 @@ class ReversedFileReader implements \Iterator * @see Iterator::key() * @return int */ - public function key() + public function key(): int { return $this->key; } @@ -151,7 +152,7 @@ class ReversedFileReader implements \Iterator * @see Iterator::current() * @return string */ - public function current() + public function current(): string { return $this->value; } @@ -162,7 +163,7 @@ class ReversedFileReader implements \Iterator * @see Iterator::valid() * @return bool */ - public function valid() + public function valid(): bool { return ! is_null($this->value); } diff --git a/src/Util/Strings.php b/src/Util/Strings.php index 8666d30c18..44ddc73259 100644 --- a/src/Util/Strings.php +++ b/src/Util/Strings.php @@ -32,11 +32,11 @@ class Strings /** * Generates a pseudo-random string of hexadecimal characters * - * @param int $size - * @return string + * @param int $size Size of string (default: 64) + * @return string Pseudo-random string * @throws \Exception */ - public static function getRandomHex($size = 64) + public static function getRandomHex(int $size = 64): string { $byte_size = ceil($size / 2); @@ -51,10 +51,9 @@ class Strings * Checks, if the given string is a valid hexadecimal code * * @param string $hexCode - * * @return bool */ - public static function isHex($hexCode) + public static function isHex(string $hexCode): bool { return !empty($hexCode) ? @preg_match("/^[a-f0-9]{2,}$/i", $hexCode) && !(strlen($hexCode) & 1) : false; } @@ -75,10 +74,9 @@ class Strings * Generate a string that's random, but usually pronounceable. Used to generate initial passwords * * @param int $len length - * * @return string */ - public static function getRandomName($len) + public static function getRandomName(int $len): string { if ($len <= 0) { return ''; @@ -161,11 +159,10 @@ class Strings * * @param string $network Network name of the contact (e.g. dfrn, rss and so on) * @param string $url The contact url - * * @return string Formatted network name * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function formatNetworkName($network, $url = '') + public static function formatNetworkName(string $network, string $url = ''): string { if ($network != '') { if ($url != '') { @@ -176,6 +173,8 @@ class Strings return $network_name; } + + return ''; } /** @@ -187,7 +186,7 @@ class Strings * * @return string Transformed string. */ - public static function deindent($text, $chr = "[\t ]", $count = NULL) + public static function deindent(string $text, string $chr = "[\t ]", int $count = null): string { $lines = explode("\n", $text); @@ -216,7 +215,7 @@ class Strings * * @return string Size with measured units. */ - public static function formatBytes($bytes, $precision = 2) + public static function formatBytes(int $bytes, int $precision = 2): string { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); @@ -231,10 +230,9 @@ class Strings * Protect percent characters in sprintf calls * * @param string $s String to transform. - * * @return string Transformed string. */ - public static function protectSprintf($s) + public static function protectSprintf(string $s): string { return str_replace('%', '%%', $s); } @@ -244,10 +242,9 @@ class Strings * * @param string $s URL to encode * @param boolean $strip_padding Optional. Default false - * * @return string Encoded URL */ - public static function base64UrlEncode($s, $strip_padding = false) + public static function base64UrlEncode(string $s, bool $strip_padding = false): string { $s = strtr(base64_encode($s), '+/', '-_'); @@ -260,18 +257,13 @@ class Strings /** * Decode Base64 Encoded URL and translate -_ to +/ - * @param string $s URL to decode * + * @param string $s URL to decode * @return string Decoded URL * @throws \Exception */ - public static function base64UrlDecode($s) + public static function base64UrlDecode(string $s): string { - if (is_array($s)) { - Logger::notice('base64url_decode: illegal input: ', ['backtrace' => debug_backtrace()]); - return $s; - } - /* * // Placeholder for new rev of salmon which strips base64 padding. * // PHP base64_decode handles the un-padded input without requiring this step @@ -295,10 +287,9 @@ class Strings * Normalize url * * @param string $url URL to be normalized. - * * @return string Normalized URL. */ - public static function normaliseLink($url) + public static function normaliseLink(string $url): string { $ret = str_replace(['https:', '//www.'], ['http:', '//'], $url); return rtrim($ret, '/'); @@ -308,10 +299,9 @@ class Strings * Normalize OpenID identity * * @param string $s OpenID Identity - * * @return string normalized OpenId Identity */ - public static function normaliseOpenID($s) + public static function normaliseOpenID(string $s): string { return trim(str_replace(['http://', 'https://'], ['', ''], $s), '/'); } @@ -327,7 +317,7 @@ class Strings * @return boolean True if the URLs match, otherwise False * */ - public static function compareLink($a, $b) + public static function compareLink(string $a, string $b): bool { return (strcasecmp(self::normaliseLink($a), self::normaliseLink($b)) === 0); } @@ -338,7 +328,7 @@ class Strings * @param string $uri * @return string */ - public static function ensureQueryParameter($uri) + public static function ensureQueryParameter(string $uri): string { if (strpos($uri, '?') === false && ($pos = strpos($uri, '&')) !== false) { $uri = substr($uri, 0, $pos) . '?' . substr($uri, $pos + 1); @@ -354,7 +344,7 @@ class Strings * @param array $chars * @return bool */ - public static function startsWithChars($string, array $chars) + public static function startsWithChars(string $string, array $chars): bool { $return = in_array(substr(trim($string), 0, 1), $chars); @@ -369,7 +359,7 @@ class Strings * @param string $start * @return bool */ - public static function startsWith(string $string, string $start) + public static function startsWith(string $string, string $start): bool { $return = substr_compare($string, $start, 0, strlen($start)) === 0; @@ -384,7 +374,7 @@ class Strings * @param string $end * @return bool */ - public static function endsWith(string $string, string $end) + public static function endsWith(string $string, string $end): string { $return = substr_compare($string, $end, -strlen($end)) === 0; @@ -397,7 +387,7 @@ class Strings * @return string * @see https://daringfireball.net/2010/07/improved_regex_for_matching_urls */ - public static function autoLinkRegEx() + public static function autoLinkRegEx(): string { return '@ (?. + * + */ + +namespace Friendica\Util\Writer; + +use Exception; +use Friendica\Database\Definition\DbaDefinition; + +/** + * SQL writer utility for the database definition + */ +class DbaDefinitionSqlWriter +{ + /** + * Creates a complete SQL definition bases on a give DBA Definition class + * + * @param DbaDefinition $definition The DBA definition class + * + * @return string The SQL definition as a string + * + * @throws Exception in case of parameter failures + */ + public static function create(DbaDefinition $definition): string + { + $sqlString = "-- ------------------------------------------\n"; + $sqlString .= "-- " . FRIENDICA_PLATFORM . " " . FRIENDICA_VERSION . " (" . FRIENDICA_CODENAME . ")\n"; + $sqlString .= "-- DB_UPDATE_VERSION " . DB_UPDATE_VERSION . "\n"; + $sqlString .= "-- ------------------------------------------\n\n\n"; + + foreach ($definition->getAll() as $tableName => $tableStructure) { + $sqlString .= "--\n"; + $sqlString .= "-- TABLE $tableName\n"; + $sqlString .= "--\n"; + $sqlString .= static::createTable($tableName, $tableStructure); + } + + return $sqlString; + } + + /** + * Creates the SQL definition of one table + * + * @param string $tableName The table name + * @param array $tableStructure The table structure + * + * @return string The SQL definition + * + * @throws Exception in cases of structure failures + */ + public static function createTable(string $tableName, array $tableStructure): string + { + $engine = ''; + $comment = ''; + $sql_rows = []; + $primary_keys = []; + $foreign_keys = []; + + foreach ($tableStructure['fields'] as $fieldName => $field) { + $sql_rows[] = '`' . static::escape($fieldName) . '` ' . self::fieldCommand($field); + if (!empty($field['primary'])) { + $primary_keys[] = $fieldName; + } + if (!empty($field['foreign'])) { + $foreign_keys[$fieldName] = $field; + } + } + + if (!empty($tableStructure['indexes'])) { + foreach ($tableStructure['indexes'] as $indexName => $fieldNames) { + $sql_index = self::createIndex($indexName, $fieldNames, ''); + if (!is_null($sql_index)) { + $sql_rows[] = $sql_index; + } + } + } + + foreach ($foreign_keys as $fieldName => $parameters) { + $sql_rows[] = self::foreignCommand($fieldName, $parameters); + } + + if (isset($tableStructure['engine'])) { + $engine = ' ENGINE=' . $tableStructure['engine']; + } + + if (isset($tableStructure['comment'])) { + $comment = " COMMENT='" . static::escape($tableStructure['comment']) . "'"; + } + + $sql = implode(",\n\t", $sql_rows); + + $sql = sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n\t", static::escape($tableName)) . $sql . + "\n)" . $engine . " DEFAULT COLLATE utf8mb4_general_ci" . $comment; + return $sql . ";\n\n"; + } + + /** + * Standard escaping for SQL definitions + * + * @param string $sqlString the SQL string to escape + * + * @return string escaped SQL string + */ + public static function escape(string $sqlString): string + { + return str_replace("'", "\\'", $sqlString); + } + + /** + * Creates the SQL definition to add a foreign key + * + * @param string $keyName The foreign key name + * @param array $parameters The given parameters of the foreign key + * + * @return string The SQL definition + */ + public static function addForeignKey(string $keyName, array $parameters): string + { + return sprintf("ADD %s", static::foreignCommand($keyName, $parameters)); + } + + /** + * Creates the SQL definition to drop a foreign key + * + * @param string $keyName The foreign key name + * + * @return string The SQL definition + */ + public static function dropForeignKey(string $keyName): string + { + return sprintf("DROP FOREIGN KEY `%s`", $keyName); + } + + /** + * Creates the SQL definition to drop an index + * + * @param string $indexName The index name + * + * @return string The SQL definition + */ + public static function dropIndex(string $indexName): string + { + return sprintf("DROP INDEX `%s`", static::escape($indexName)); + } + + /** + * Creates the SQL definition to add a table field + * + * @param string $fieldName The table field name + * @param array $parameters The parameters of the table field + * + * @return string The SQL definition + */ + public static function addTableField(string $fieldName, array $parameters): string + { + return sprintf("ADD `%s` %s", static::escape($fieldName), static::fieldCommand($parameters)); + } + + /** + * Creates the SQL definition to modify a table field + * + * @param string $fieldName The table field name + * @param array $parameters The paramters to modify + * + * @return string The SQL definition + */ + public static function modifyTableField(string $fieldName, array $parameters): string + { + return sprintf("MODIFY `%s` %s", static::escape($fieldName), self::fieldCommand($parameters, false)); + } + + /** + * Returns SQL statement for field + * + * @param array $parameters Parameters for SQL statement + * @param boolean $create Whether to include PRIMARY KEY statement (unused) + * @return string SQL statement part + */ + public static function fieldCommand(array $parameters, bool $create = true): string + { + $fieldstruct = $parameters['type']; + + if (isset($parameters['Collation'])) { + $fieldstruct .= ' COLLATE ' . $parameters['Collation']; + } + + if (isset($parameters['not null'])) { + $fieldstruct .= ' NOT NULL'; + } + + if (isset($parameters['default'])) { + if (strpos(strtolower($parameters['type']), 'int') !== false) { + $fieldstruct .= ' DEFAULT ' . $parameters['default']; + } else { + $fieldstruct .= " DEFAULT '" . $parameters['default'] . "'"; + } + } + if (isset($parameters['extra'])) { + $fieldstruct .= ' ' . $parameters['extra']; + } + + if (isset($parameters['comment'])) { + $fieldstruct .= " COMMENT '" . static::escape($parameters['comment']) . "'"; + } + + /*if (($parameters['primary'] != '') && $create) + $fieldstruct .= ' PRIMARY KEY';*/ + + return $fieldstruct; + } + + /** + * Creates the SQL definition to create an index + * + * @param string $indexName The index name + * @param array $fieldNames The field names of this index + * @param string $method The method to create the index (default is ADD) + * + * @return string The SQL definition + * @throws Exception in cases the paramter contains invalid content + */ + public static function createIndex(string $indexName, array $fieldNames, string $method = 'ADD'): string + { + $method = strtoupper(trim($method)); + if ($method != '' && $method != 'ADD') { + throw new Exception("Invalid parameter 'method' in self::createIndex(): '$method'"); + } + + if (in_array($fieldNames[0], ['UNIQUE', 'FULLTEXT'])) { + $index_type = array_shift($fieldNames); + $method .= " " . $index_type; + } + + $names = ""; + foreach ($fieldNames as $fieldName) { + if ($names != '') { + $names .= ','; + } + + if (preg_match('|(.+)\((\d+)\)|', $fieldName, $matches)) { + $names .= "`" . static::escape($matches[1]) . "`(" . intval($matches[2]) . ")"; + } else { + $names .= "`" . static::escape($fieldName) . "`"; + } + } + + if ($indexName == 'PRIMARY') { + return sprintf("%s PRIMARY KEY(%s)", $method, $names); + } + + + return sprintf("%s INDEX `%s` (%s)", $method, static::escape($indexName), $names); + } + + /** + * Creates the SQL definition for foreign keys + * + * @param string $foreignKeyName The foreign key name + * @param array $parameters The parameters of the foreign key + * + * @return string The SQL definition + */ + public static function foreignCommand(string $foreignKeyName, array $parameters): string + { + $foreign_table = array_keys($parameters['foreign'])[0]; + $foreign_field = array_values($parameters['foreign'])[0]; + + $sql = "FOREIGN KEY (`" . $foreignKeyName . "`) REFERENCES `" . $foreign_table . "` (`" . $foreign_field . "`)"; + + if (!empty($parameters['foreign']['on update'])) { + $sql .= " ON UPDATE " . strtoupper($parameters['foreign']['on update']); + } else { + $sql .= " ON UPDATE RESTRICT"; + } + + if (!empty($parameters['foreign']['on delete'])) { + $sql .= " ON DELETE " . strtoupper($parameters['foreign']['on delete']); + } else { + $sql .= " ON DELETE CASCADE"; + } + + return $sql; + } +} diff --git a/src/Util/Writer/DocWriter.php b/src/Util/Writer/DocWriter.php new file mode 100644 index 0000000000..a63f6a6493 --- /dev/null +++ b/src/Util/Writer/DocWriter.php @@ -0,0 +1,145 @@ +. + * + */ + +namespace Friendica\Util\Writer; + +use Friendica\Core\Renderer; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Network\HTTPException\ServiceUnavailableException; + +/** + * Utility class to write content into the '/doc' directory + */ +class DocWriter +{ + /** + * Creates all database definitions as Markdown fields and create the mkdoc config file. + * + * @param DbaDefinition $definition The Database definition class + * @param string $basePath The basepath of Friendica + * + * @return void + * @throws ServiceUnavailableException in really unexpected cases! + */ + public static function writeDbDefinition(DbaDefinition $definition, string $basePath) + { + $tables = []; + foreach ($definition->getAll() as $name => $definition) { + $indexes = [ + [ + 'name' => 'Name', + 'fields' => 'Fields', + ], + [ + 'name' => '-', + 'fields' => '-', + ] + ]; + + $lengths = ['name' => 4, 'fields' => 6]; + foreach ($definition['indexes'] as $key => $value) { + $fieldlist = implode(', ', $value); + $indexes[] = ['name' => $key, 'fields' => $fieldlist]; + $lengths['name'] = max($lengths['name'], strlen($key)); + $lengths['fields'] = max($lengths['fields'], strlen($fieldlist)); + } + + array_walk_recursive($indexes, function (&$value, $key) use ($lengths) { + $value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' '); + }); + + $foreign = []; + $fields = [ + [ + 'name' => 'Field', + 'comment' => 'Description', + 'type' => 'Type', + 'null' => 'Null', + 'primary' => 'Key', + 'default' => 'Default', + 'extra' => 'Extra', + ], + [ + 'name' => '-', + 'comment' => '-', + 'type' => '-', + 'null' => '-', + 'primary' => '-', + 'default' => '-', + 'extra' => '-', + ] + ]; + $lengths = [ + 'name' => 5, + 'comment' => 11, + 'type' => 4, + 'null' => 4, + 'primary' => 3, + 'default' => 7, + 'extra' => 5, + ]; + foreach ($definition['fields'] as $key => $value) { + $field = []; + $field['name'] = $key; + $field['comment'] = $value['comment'] ?? ''; + $field['type'] = $value['type']; + $field['null'] = ($value['not null'] ?? false) ? 'NO' : 'YES'; + $field['primary'] = ($value['primary'] ?? false) ? 'PRI' : ''; + $field['default'] = $value['default'] ?? 'NULL'; + $field['extra'] = $value['extra'] ?? ''; + + foreach ($field as $fieldName => $fieldvalue) { + $lengths[$fieldName] = max($lengths[$fieldName] ?? 0, strlen($fieldvalue)); + } + $fields[] = $field; + + if (!empty($value['foreign'])) { + $foreign[] = [ + 'field' => $key, + 'targettable' => array_keys($value['foreign'])[0], + 'targetfield' => array_values($value['foreign'])[0] + ]; + } + } + + array_walk_recursive($fields, function (&$value, $key) use ($lengths) { + $value = str_pad($value, $lengths[$key], $value === '-' ? '-' : ' '); + }); + + $tables[] = ['name' => $name, 'comment' => $definition['comment']]; + $content = Renderer::replaceMacros(Renderer::getMarkupTemplate('structure.tpl'), [ + '$name' => $name, + '$comment' => $definition['comment'], + '$fields' => $fields, + '$indexes' => $indexes, + '$foreign' => $foreign, + ]); + $filename = $basePath . '/doc/database/db_' . $name . '.md'; + file_put_contents($filename, $content); + } + asort($tables); + $content = Renderer::replaceMacros(Renderer::getMarkupTemplate('tables.tpl'), [ + '$tables' => $tables, + ]); + $filename = $basePath . '/doc/database.md'; + file_put_contents($filename, $content); + } +} diff --git a/src/Util/Writer/ViewDefinitionSqlWriter.php b/src/Util/Writer/ViewDefinitionSqlWriter.php new file mode 100644 index 0000000000..429a7dc5cb --- /dev/null +++ b/src/Util/Writer/ViewDefinitionSqlWriter.php @@ -0,0 +1,98 @@ +. + * + */ + +namespace Friendica\Util\Writer; + +use Friendica\Database\Definition\ViewDefinition; + +/** + * SQL writer utility for the db view definition + */ +class ViewDefinitionSqlWriter +{ + /** + * Creates a complete SQL definition bases on a give View Definition class + * + * @param ViewDefinition $definition The View definition class + * + * @return string The SQL definition as a string + */ + public static function create(ViewDefinition $definition): string + { + $sqlString = ''; + + foreach ($definition->getAll() as $viewName => $viewStructure) { + $sqlString .= "--\n"; + $sqlString .= "-- VIEW $viewName\n"; + $sqlString .= "--\n"; + $sqlString .= static::dropView($viewName); + $sqlString .= static::createView($viewName, $viewStructure); + } + + return $sqlString; + } + + /** + * Creates the SQL definition to drop a view + * + * @param string $viewName the view name + * + * @return string The SQL definition + */ + public static function dropView(string $viewName): string + { + return sprintf("DROP VIEW IF EXISTS `%s`", static::escape($viewName)) . ";\n"; + } + + /** + * Creates the SQL definition to create a new view + * + * @param string $viewName The view name + * @param array $viewStructure The structure information of the view + * + * @return string The SQL definition + */ + public static function createView(string $viewName, array $viewStructure): string + { + $sql_rows = []; + foreach ($viewStructure['fields'] as $fieldname => $origin) { + if (is_string($origin)) { + $sql_rows[] = $origin . " AS `" . static::escape($fieldname) . "`"; + } elseif (is_array($origin) && (sizeof($origin) == 2)) { + $sql_rows[] = "`" . static::escape($origin[0]) . "`.`" . static::escape($origin[1]) . "` AS `" . static::escape($fieldname) . "`"; + } + } + return sprintf("CREATE VIEW `%s` AS SELECT \n\t", static::escape($viewName)) . + implode(",\n\t", $sql_rows) . "\n\t" . $viewStructure['query'] . ";\n\n"; + } + + /** + * Standard escaping for SQL definitions + * + * @param string $sqlString the SQL string to escape + * + * @return string escaped SQL string + */ + public static function escape(string $sqlString): string + { + return str_replace("'", "\\'", $sqlString); + } +} diff --git a/src/Util/XML.php b/src/Util/XML.php index f00cb7894c..0424400a82 100644 --- a/src/Util/XML.php +++ b/src/Util/XML.php @@ -21,6 +21,9 @@ namespace Friendica\Util; +use DOMDocument; +use DOMElement; +use DOMNode; use DOMXPath; use Friendica\Core\Logger; use Friendica\Core\System; @@ -35,26 +38,25 @@ class XML * Creates an XML structure out of a given array * * @param array $array The array of the XML structure that will be generated - * @param object $xml The createdXML will be returned by reference + * @param object $xml The created XML will be returned by reference * @param bool $remove_header Should the XML header be removed or not? * @param array $namespaces List of namespaces * @param bool $root interally used parameter. Mustn't be used from outside. - * - * @return string The created XML + * @return void */ - public static function fromArray($array, &$xml, $remove_header = false, $namespaces = [], $root = true) + public static function fromArray(array $array, &$xml, bool $remove_header = false, array $namespaces = [], bool $root = true) { if ($root) { foreach ($array as $key => $value) { foreach ($namespaces as $nskey => $nsvalue) { - $key .= " xmlns".($nskey == "" ? "":":").$nskey.'="'.$nsvalue.'"'; + $key .= ' xmlns' . ($nskey == '' ? '' : ':') . $nskey . '="' . $nsvalue . '"'; } if (is_array($value)) { - $root = new SimpleXMLElement("<".$key."/>"); + $root = new SimpleXMLElement('<' . $key . '/>'); self::fromArray($value, $root, $remove_header, $namespaces, false); } else { - $root = new SimpleXMLElement("<".$key.">".self::escape($value).""); + $root = new SimpleXMLElement('<' . $key . '>' . self::escape($value ?? '') . ''); } $dom = dom_import_simplexml($root)->ownerDocument; @@ -88,11 +90,11 @@ class XML continue; } - $element_parts = explode(":", $key); + $element_parts = explode(':', $key); if ((count($element_parts) > 1) && isset($namespaces[$element_parts[0]])) { $namespace = $namespaces[$element_parts[0]]; - } elseif (isset($namespaces[""])) { - $namespace = $namespaces[""]; + } elseif (isset($namespaces[''])) { + $namespace = $namespaces['']; } else { $namespace = null; } @@ -102,13 +104,13 @@ class XML $key = $element_parts[1]; } - if (substr($key, 0, 11) == "@attributes") { + if (substr($key, 0, 11) == '@attributes') { if (!isset($element) || !is_array($value)) { continue; } foreach ($value as $attr_key => $attr_value) { - $element_parts = explode(":", $attr_key); + $element_parts = explode(':', $attr_key); if ((count($element_parts) > 1) && isset($namespaces[$element_parts[0]])) { $namespace = $namespaces[$element_parts[0]]; } else { @@ -122,7 +124,7 @@ class XML } if (!is_array($value)) { - $element = $xml->addChild($key, self::escape($value), $namespace); + $element = $xml->addChild($key, self::escape($value ?? ''), $namespace); } elseif (is_array($value)) { $element = $xml->addChild($key, null, $namespace); self::fromArray($value, $element, $remove_header, $namespaces, false); @@ -138,7 +140,7 @@ class XML * @param string $elementname Name of the XML element of the target * @return void */ - public static function copy(&$source, &$target, $elementname) + public static function copy(&$source, &$target, string $elementname) { if (count($source->children()) == 0) { $target->addChild($elementname, self::escape($source)); @@ -153,20 +155,20 @@ class XML /** * Create an XML element * - * @param \DOMDocument $doc XML root + * @param DOMDocument $doc XML root * @param string $element XML element name * @param string $value XML value * @param array $attributes array containing the attributes * * @return \DOMElement XML element object */ - public static function createElement(\DOMDocument $doc, $element, $value = "", $attributes = []) + public static function createElement(DOMDocument $doc, string $element, string $value = '', array $attributes = []): DOMElement { $element = $doc->createElement($element, self::escape($value)); foreach ($attributes as $key => $value) { $attribute = $doc->createAttribute($key); - $attribute->value = self::escape($value); + $attribute->value = self::escape($value ?? ''); $element->appendChild($attribute); } return $element; @@ -175,22 +177,21 @@ class XML /** * Create an XML and append it to the parent object * - * @param \DOMDocument $doc XML root - * @param object $parent parent object - * @param string $element XML element name - * @param string $value XML value - * @param array $attributes array containing the attributes + * @param DOMDocument $doc XML root + * @param DOMElement $parent parent object + * @param string $element XML element name + * @param string $value XML value + * @param array $attributes Array containing the attributes * @return void */ - public static function addElement(\DOMDocument $doc, $parent, $element, $value = "", $attributes = []) + public static function addElement(DOMDocument $doc, DOMElement &$parent, string $element, string $value = '', array $attributes = []) { $element = self::createElement($doc, $element, $value, $attributes); $parent->appendChild($element); } /** - * Convert an XML document to a normalised, case-corrected array - * used by webfinger + * Convert an XML document to a normalised, case-corrected array used by webfinger * * @param object $xml_element The XML document * @param integer $recursion_depth recursion counter for internal use - default 0 @@ -198,11 +199,11 @@ class XML * * @return array | string The array from the xml element or the string */ - public static function elementToArray($xml_element, &$recursion_depth = 0) + public static function elementToArray($xml_element, int &$recursion_depth = 0) { // If we're getting too deep, bail out if ($recursion_depth > 512) { - return(null); + return null; } $xml_element_copy = ''; @@ -217,7 +218,7 @@ class XML if (is_array($xml_element)) { $result_array = []; if (count($xml_element) <= 0) { - return (trim(strval($xml_element_copy))); + return trim(strval($xml_element_copy)); } foreach ($xml_element as $key => $value) { @@ -233,9 +234,9 @@ class XML ]; } - return ($result_array); + return $result_array; } else { - return (trim(strval($xml_element))); + return trim(strval($xml_element)); } } @@ -261,7 +262,7 @@ class XML * @return array The parsed XML in an array form. Use print_r() to see the resulting array structure. * @throws \Exception */ - public static function toArray($contents, $namespaces = true, $get_attributes = 1, $priority = 'attribute') + public static function toArray(string $contents, bool $namespaces = true, int $get_attributes = 1, string $priority = 'attribute'): array { if (!$contents) { return []; @@ -300,7 +301,7 @@ class XML Logger::debug('libxml: parse: ' . $err->code . " at " . $err->line . ":" . $err->column . " : " . $err->message); } libxml_clear_errors(); - return; + return []; } //Initializations @@ -414,20 +415,20 @@ class XML } } - return($xml_array); + return $xml_array; } /** * Delete a node in a XML object * - * @param \DOMDocument $doc XML document + * @param DOMDocument $doc XML document * @param string $node Node name * @return void */ - public static function deleteNode(\DOMDocument $doc, $node) + public static function deleteNode(DOMDocument $doc, string $node) { $xpath = new DOMXPath($doc); - $list = $xpath->query("//".$node); + $list = $xpath->query('//' . $node); foreach ($list as $child) { $child->parentNode->removeChild($child); } @@ -436,9 +437,9 @@ class XML /** * Parse XML string * - * @param string $s - * @param boolean $suppress_log - * @return Object + * @param string $s XML string to parse into object + * @param boolean $suppress_log Whether to supressing logging + * @return SimpleXMLElement|bool SimpleXMLElement or false on failure */ public static function parseString(string $s, bool $suppress_log = false) { @@ -458,7 +459,15 @@ class XML return $x; } - public static function getFirstNodeValue(DOMXPath $xpath, $element, $context = null) + /** + * Gets first node value + * + * @param DOMXPath $xpath XPath object + * @param string $element Element name + * @param DOMNode $context Context object or NULL + * @return string XML node value or empty string on failure + */ + public static function getFirstNodeValue(DOMXPath $xpath, string $element, DOMNode $context = null) { $result = @$xpath->evaluate($element, $context); if (!is_object($result)) { @@ -473,7 +482,15 @@ class XML return $first_item->nodeValue; } - public static function getFirstAttributes(DOMXPath $xpath, $element, $context = null) + /** + * Gets first attributes + * + * @param DOMXPath $xpath XPath object + * @param string $element Element name + * @param DOMNode $context Context object or NULL + * @return ???|bool First element's attributes field or false on failure + */ + public static function getFirstAttributes(DOMXPath $xpath, string $element, DOMNode $context = null) { $result = @$xpath->query($element, $context); if (!is_object($result)) { @@ -488,9 +505,17 @@ class XML return $first_item->attributes; } - public static function getFirstValue($xpath, $search, $context) + /** + * Gets first node's value + * + * @param DOMXPath $xpath XPath object + * @param string $element Element name + * @param DOMNode $context Context object or NULL + * @return string First value or empty string on failure + */ + public static function getFirstValue(DOMXPath $xpath, string $element, DOMNode $context = null): string { - $result = @$xpath->query($search, $context); + $result = @$xpath->query($element, $context); if (!is_object($result)) { return ''; } @@ -508,32 +533,31 @@ class XML * * @param string $str * @return string Escaped text. + * @todo Move this generic method to Util\Strings and also rewrite all other findingd */ - public static function escape($str) + public static function escape(string $str): string { - $buffer = htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); - $buffer = trim($buffer); - - return $buffer; + return trim(htmlspecialchars($str, ENT_QUOTES, 'UTF-8')); } /** - * undo an escape + * Undo an escape * * @param string $s xml escaped text * @return string unescaped text + * @todo Move this generic method to Util\Strings and also rewrite all other findingd */ - public static function unescape($s) + public static function unescape(string $s): string { - $ret = htmlspecialchars_decode($s, ENT_QUOTES); - return $ret; + return htmlspecialchars_decode($s, ENT_QUOTES); } /** - * apply escape() to all values of array $val, recursively + * Apply escape() to all values of array $val, recursively * - * @param array $val - * @return array|string + * @param array|bool|string $val Value of type bool, array or string + * @return array|string Returns array if array provided or string in other cases + * @todo Move this generic method to Util\Strings */ public static function arrayEscape($val) { diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index c09181d3e6..7f64a9d6a2 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -257,19 +257,19 @@ class Delivery /** * Deliver content via DFRN * - * @param string $cmd Command - * @param array $contact Contact record of the receiver - * @param array $owner Owner record of the sender - * @param array $items Item record of the content and the parent - * @param array $target_item Item record of the content - * @param boolean $public_message Is the content public? - * @param boolean $top_level Is it a thread starter? - * @param boolean $followup Is it an answer to a remote post? - * @param int $server_protocol The protocol of the server + * @param string $cmd Command + * @param array $contact Contact record of the receiver + * @param array $owner Owner record of the sender + * @param array $items Item record of the content and the parent + * @param array $target_item Item record of the content + * @param boolean $public_message Is the content public? + * @param boolean $top_level Is it a thread starter? + * @param boolean $followup Is it an answer to a remote post? + * @param int|null $server_protocol The protocol of the server * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function deliverDFRN($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup, $server_protocol) + private static function deliverDFRN(string $cmd, array $contact, array $owner, array $items, array $target_item, bool $public_message, bool $top_level, bool $followup, int $server_protocol = null) { // Transmit Diaspora reshares via Diaspora if the Friendica contact support Diaspora if (Diaspora::isReshare($target_item['body'] ?? '') && !empty(FContact::getByURL($contact['addr'], false))) { @@ -384,7 +384,7 @@ class Delivery * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup) + private static function deliverDiaspora(string $cmd, array $contact, array $owner, array $items, array $target_item, bool $public_message, bool $top_level, bool $followup) { // We don't treat Forum 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'] != Model\User::ACCOUNT_TYPE_COMMUNITY); @@ -475,12 +475,13 @@ class Delivery * @param array $owner Owner record of the sender * @param array $target_item Item record of the content * @param array $thr_parent Item record of the direct parent in the thread + * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function deliverMail($cmd, $contact, $owner, $target_item, $thr_parent) + private static function deliverMail(string $cmd, array $contact, array $owner, array $target_item, array $thr_parent) { - if (DI::config()->get('system','imap_disabled')) { + if (DI::config()->get('system', 'imap_disabled')) { return; } @@ -570,10 +571,16 @@ class Delivery } } - Email::send($addr, $subject, $headers, $target_item); + // Try to send email + $success = Email::send($addr, $subject, $headers, $target_item); - Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Model\Post\DeliveryData::MAIL); - - Logger::info('Delivered via mail', ['guid' => $target_item['guid'], 'to' => $addr, 'subject' => $subject]); + if ($success) { + // Success + Model\Post\DeliveryData::incrementQueueDone($target_item['uri-id'], Model\Post\DeliveryData::MAIL); + Logger::info('Delivered via mail', ['guid' => $target_item['guid'], 'to' => $addr, 'subject' => $subject]); + } else { + // Failed + Logger::warning('Delivery of mail has FAILED', ['to' => $addr, 'subject' => $subject, 'guid' => $target_item['guid']]); + } } } diff --git a/src/Worker/Directory.php b/src/Worker/Directory.php index d6294d0498..bb8041a225 100644 --- a/src/Worker/Directory.php +++ b/src/Worker/Directory.php @@ -34,7 +34,7 @@ use Friendica\Network\HTTPClient\Client\HttpClientAccept; */ class Directory { - public static function execute($url = '') + public static function execute(string $url = '') { $dir = Search::getGlobalDirectory(); diff --git a/src/Worker/ExpirePosts.php b/src/Worker/ExpirePosts.php index 52d792ea62..d09376d60e 100644 --- a/src/Worker/ExpirePosts.php +++ b/src/Worker/ExpirePosts.php @@ -122,7 +122,7 @@ class ExpirePosts $rows = 0; $userposts = DBA::select('post-user', [], ["`uri-id` not in (select `uri-id` from `post`)"]); while ($fields = DBA::fetch($userposts)) { - $post_fields = DBStructure::getFieldsForTable('post', $fields); + $post_fields = DI::dbaDefinition()->truncateFieldsForTable('post', $fields); DBA::insert('post', $post_fields, Database::INSERT_IGNORE); $rows++; } @@ -136,7 +136,7 @@ class ExpirePosts $rows = 0; $userposts = DBA::select('post-user', [], ["`gravity` = ? AND `uri-id` not in (select `uri-id` from `post-thread`)", GRAVITY_PARENT]); while ($fields = DBA::fetch($userposts)) { - $post_fields = DBStructure::getFieldsForTable('post-thread', $fields); + $post_fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread', $fields); $post_fields['commented'] = $post_fields['changed'] = $post_fields['created']; DBA::insert('post-thread', $post_fields, Database::INSERT_IGNORE); $rows++; @@ -151,7 +151,7 @@ class ExpirePosts $rows = 0; $userposts = DBA::select('post-user', [], ["`gravity` = ? AND `id` not in (select `post-user-id` from `post-thread-user`)", GRAVITY_PARENT]); while ($fields = DBA::fetch($userposts)) { - $post_fields = DBStructure::getFieldsForTable('post-thread-user', $fields); + $post_fields = DI::dbaDefinition()->truncateFieldsForTable('post-thread-user', $fields); $post_fields['commented'] = $post_fields['changed'] = $post_fields['created']; DBA::insert('post-thread-user', $post_fields, Database::INSERT_IGNORE); $rows++; diff --git a/src/Worker/MergeContact.php b/src/Worker/MergeContact.php index 2378d98e17..e1383f2110 100644 --- a/src/Worker/MergeContact.php +++ b/src/Worker/MergeContact.php @@ -30,9 +30,9 @@ class MergeContact /** * Replace all occurences of the given contact id and replace it * - * @param integer $new_cid - * @param integer $old_cid - * @param integer $uid + * @param integer $new_cid New contact id + * @param integer $old_cid Old contact id + * @param integer $uid User id */ public static function execute(int $new_cid, int $old_cid, int $uid) { diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 2039448e14..8c0801c66d 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -81,7 +81,7 @@ class Notifier $uid = $message['uid']; $recipients[] = $message['contact-id']; - $mail = ActivityPub\Transmitter::ItemArrayFromMail($target_id); + $mail = ActivityPub\Transmitter::getItemArrayFromMail($target_id); $inboxes = ActivityPub\Transmitter::fetchTargetInboxes($mail, $uid, true); foreach ($inboxes as $inbox => $receivers) { $ap_contacts = array_merge($ap_contacts, $receivers); diff --git a/src/Worker/OnePoll.php b/src/Worker/OnePoll.php index 66b9851cf2..65f2277b73 100644 --- a/src/Worker/OnePoll.php +++ b/src/Worker/OnePoll.php @@ -41,11 +41,11 @@ use Friendica\Util\Strings; class OnePoll { - public static function execute($contact_id = 0, $command = '') + public static function execute(int $contact_id = 0, string $command = '') { Logger::notice('Start polling/probing contact', ['id' => $contact_id]); - $force = ($command == "force"); + $force = ($command == 'force'); if (empty($contact_id)) { Logger::notice('no contact provided'); @@ -118,6 +118,7 @@ class OnePoll * * @param array $contact The personal contact entry * @param array $fields The fields that are updated + * @return void * @throws \Exception */ private static function updateContact(array $contact, array $fields) diff --git a/src/Worker/ProfileUpdate.php b/src/Worker/ProfileUpdate.php index ba15436d84..e26abf7e20 100644 --- a/src/Worker/ProfileUpdate.php +++ b/src/Worker/ProfileUpdate.php @@ -31,7 +31,14 @@ use Friendica\Protocol\ActivityPub; * Send updated profile data to Diaspora and ActivityPub */ class ProfileUpdate { - public static function execute($uid = 0) { + /** + * Sends updated profile data to Diaspora and ActivityPub + * + * @param int $uid User id (optional, default: 0) + * @return void + */ + public static function execute(int $uid = 0) + { if (empty($uid)) { return; } @@ -43,7 +50,13 @@ class ProfileUpdate { foreach ($inboxes as $inbox => $receivers) { Logger::info('Profile update for user ' . $uid . ' to ' . $inbox .' via ActivityPub'); Worker::add(['priority' => $a->getQueueValue('priority'), 'created' => $a->getQueueValue('created'), 'dont_fork' => true], - 'APDelivery', Delivery::PROFILEUPDATE, 0, $inbox, $uid, $receivers); + 'APDelivery', + Delivery::PROFILEUPDATE, + 0, + $inbox, + $uid, + $receivers + ); } Diaspora::sendProfile($uid); diff --git a/src/Worker/PubSubPublish.php b/src/Worker/PubSubPublish.php index e84ac3152e..1bfc3657ae 100644 --- a/src/Worker/PubSubPublish.php +++ b/src/Worker/PubSubPublish.php @@ -29,7 +29,13 @@ use Friendica\Protocol\OStatus; class PubSubPublish { - public static function execute($pubsubpublish_id = 0) + /** + * Publishes subscriber id + * + * @param int $pubsubpublish_id Push subscriber id + * @return void + */ + public static function execute(int $pubsubpublish_id = 0) { if ($pubsubpublish_id == 0) { return; @@ -38,7 +44,13 @@ class PubSubPublish self::publish($pubsubpublish_id); } - private static function publish($id) + /** + * Publishes push subscriber + * + * @param int $id Push subscriber id + * @return void + */ + private static function publish(int $id) { $subscriber = DBA::selectFirst('push_subscriber', [], ['id' => $id]); if (!DBA::isResult($subscriber)) { @@ -48,7 +60,7 @@ class PubSubPublish /// @todo Check server status with GServer::check() // Before this can be done we need a way to safely detect the server url. - Logger::info("Generate feed of user " . $subscriber['nickname']. " to " . $subscriber['callback_url']. " - last updated " . $subscriber['last_update']); + Logger::info('Generate feed of user ' . $subscriber['nickname'] . ' to ' . $subscriber['callback_url'] . ' - last updated ' . $subscriber['last_update']); $last_update = $subscriber['last_update']; $params = OStatus::feed($subscriber['nickname'], $last_update); @@ -57,11 +69,11 @@ class PubSubPublish return; } - $hmac_sig = hash_hmac("sha1", $params, $subscriber['secret']); + $hmac_sig = hash_hmac('sha1', $params, $subscriber['secret']); $headers = [ 'Content-type' => 'application/atom+xml', - 'Link' => sprintf("<%s>;rel=hub,<%s>;rel=self", + 'Link' => sprintf('<%s>;rel=hub,<%s>;rel=self', DI::baseUrl() . '/pubsubhubbub/' . $subscriber['nickname'], $subscriber['topic']), 'X-Hub-Signature' => 'sha1=' . $hmac_sig]; diff --git a/src/Worker/PushSubscription.php b/src/Worker/PushSubscription.php index 45ecb62291..f82f469146 100644 --- a/src/Worker/PushSubscription.php +++ b/src/Worker/PushSubscription.php @@ -26,6 +26,7 @@ use Friendica\Content\Text\Plaintext; use Friendica\Core\Logger; use Friendica\Database\DBA; use Friendica\DI; +use Friendica\Factory\Api\Mastodon\Notification as NotificationFactory; use Friendica\Model\Contact; use Friendica\Model\Post; use Friendica\Model\Subscription as ModelSubscription; @@ -37,6 +38,13 @@ use Minishlink\WebPush\Subscription; class PushSubscription { + /** + * Creates push subscription by subscription and notification ids + * + * @param int $sid Subscription id + * @param int $nid Notification id + * @return void + */ public static function execute(int $sid, int $nid) { Logger::info('Start', ['subscription' => $sid, 'notification' => $nid]); @@ -48,7 +56,7 @@ class PushSubscription } try { - $Notification = DI::notification()->selectOneById($nid); + $notification = DI::notification()->selectOneById($nid); } catch (NotFoundException $e) { Logger::info('Notification not found', ['notification' => $nid]); return; @@ -60,7 +68,7 @@ class PushSubscription return; } - $user = User::getById($Notification->uid); + $user = User::getById($notification->uid); if (empty($user)) { Logger::info('User not found', ['application' => $subscription['uid']]); return; @@ -68,21 +76,21 @@ class PushSubscription $l10n = DI::l10n()->withLang($user['language']); - if ($Notification->actorId) { - $actor = Contact::getById($Notification->actorId); + if ($notification->actorId) { + $actor = Contact::getById($notification->actorId); } $body = ''; - if ($Notification->targetUriId) { - $post = Post::selectFirst([], ['uri-id' => $Notification->targetUriId, 'uid' => [0, $Notification->uid]]); + if ($notification->targetUriId) { + $post = Post::selectFirst([], ['uri-id' => $notification->targetUriId, 'uid' => [0, $notification->uid]]); if (!empty($post['body'])) { $body = BBCode::toPlaintext($post['body'], false); - $body = Plaintext::shorten($body, 160, $Notification->uid); + $body = Plaintext::shorten($body, 160, $notification->uid); } } - $message = DI::notificationFactory()->getMessageFromNotification($Notification); + $message = DI::notificationFactory()->getMessageFromNotification($notification); $title = $message['plain'] ?: ''; $push = Subscription::create([ @@ -94,11 +102,12 @@ class PushSubscription ], ]); + // @todo Only used for logging? $payload = [ 'access_token' => $application_token['access_token'], 'preferred_locale' => $user['language'], 'notification_id' => $nid, - 'notification_type' => \Friendica\Factory\Api\Mastodon\Notification::getType($Notification), + 'notification_type' => NotificationFactory::getType($notification), 'icon' => $actor['thumb'] ?? '', 'title' => $title ?: $l10n->t('Notification from Friendica'), 'body' => $body ?: $l10n->t('Empty Post'), diff --git a/src/Worker/RemoveUser.php b/src/Worker/RemoveUser.php index e209aec07f..6a2d54422e 100644 --- a/src/Worker/RemoveUser.php +++ b/src/Worker/RemoveUser.php @@ -29,7 +29,13 @@ use Friendica\Model\Post; * Removes orphaned data from deleted users */ class RemoveUser { - public static function execute($uid) + /** + * Removes user by id + * + * @param int $uid User id + * @return void + */ + public static function execute(int $uid) { // Only delete if the user is archived $condition = ['account_removed' => true, 'uid' => $uid]; diff --git a/src/Worker/UpdateContact.php b/src/Worker/UpdateContact.php index edabaf163c..8de3629caf 100644 --- a/src/Worker/UpdateContact.php +++ b/src/Worker/UpdateContact.php @@ -28,9 +28,11 @@ class UpdateContact { /** * Update contact data via probe + * * @param int $contact_id Contact ID + * @return void */ - public static function execute($contact_id) + public static function execute(int $contact_id) { $success = Contact::updateFromProbe($contact_id); diff --git a/src/Worker/UpdateContacts.php b/src/Worker/UpdateContacts.php index 2beb890918..9dc0bacca7 100644 --- a/src/Worker/UpdateContacts.php +++ b/src/Worker/UpdateContacts.php @@ -102,7 +102,7 @@ class UpdateContacts * @param array $ids * @return array contact ids */ - private static function getContactsToUpdate(array $condition, int $limit, array $ids = []) + private static function getContactsToUpdate(array $condition, int $limit, array $ids = []): array { $contacts = DBA::select('contact', ['id'], $condition, ['limit' => $limit]); while ($contact = DBA::fetch($contacts)) { diff --git a/src/Worker/UpdateGServer.php b/src/Worker/UpdateGServer.php index 1085c467c7..d180f34c45 100644 --- a/src/Worker/UpdateGServer.php +++ b/src/Worker/UpdateGServer.php @@ -30,8 +30,10 @@ class UpdateGServer { /** * Update the given server + * * @param string $server_url Server URL * @param boolean $only_nodeinfo Only use nodeinfo for server detection + * @return void */ public static function execute(string $server_url, bool $only_nodeinfo = false) { diff --git a/src/Worker/UpdateServerPeers.php b/src/Worker/UpdateServerPeers.php index 98ae88a97b..09c88499ec 100644 --- a/src/Worker/UpdateServerPeers.php +++ b/src/Worker/UpdateServerPeers.php @@ -32,7 +32,9 @@ class UpdateServerPeers { /** * Query the given server for their known peers + * * @param string $gserver Server URL + * @return void */ public static function execute(string $url) { diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index d365f98050..758c33d0da 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1469); + define('DB_UPDATE_VERSION', 1473); } return [ @@ -358,6 +358,7 @@ return [ "cookie_hash" => ["type" => "varchar(80)", "not null" => "1", "primary" => "1", "comment" => "Trusted cookie hash"], "uid" => ["type" => "mediumint unsigned", "not null" => "1", "foreign" => ["user" => "uid"], "comment" => "User ID"], "user_agent" => ["type" => "text", "comment" => "User agent string"], + "trusted" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "Whenever this browser should be trusted or not"], "created" => ["type" => "datetime", "not null" => "1", "comment" => "Datetime the trusted browser was recorded"], "last_used" => ["type" => "datetime", "comment" => "Datetime the trusted browser was last used"], ], @@ -1252,13 +1253,13 @@ return [ "fields" => [ "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], "uri-id" => ["type" => "int unsigned", "not null" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"], - "url" => ["type" => "varbinary(511)", "not null" => "1", "comment" => "Media URL"], + "url" => ["type" => "varbinary(1024)", "not null" => "1", "comment" => "Media URL"], "type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Media type"], "mimetype" => ["type" => "varchar(60)", "comment" => ""], "height" => ["type" => "smallint unsigned", "comment" => "Height of the media"], "width" => ["type" => "smallint unsigned", "comment" => "Width of the media"], - "size" => ["type" => "int unsigned", "comment" => "Media size"], - "preview" => ["type" => "varbinary(255)", "comment" => "Preview URL"], + "size" => ["type" => "bigint unsigned", "comment" => "Media size"], + "preview" => ["type" => "varbinary(512)", "comment" => "Preview URL"], "preview-height" => ["type" => "smallint unsigned", "comment" => "Height of the preview picture"], "preview-width" => ["type" => "smallint unsigned", "comment" => "Width of the preview picture"], "description" => ["type" => "text", "comment" => ""], @@ -1272,7 +1273,7 @@ return [ ], "indexes" => [ "PRIMARY" => ["id"], - "uri-id-url" => ["UNIQUE", "uri-id", "url"], + "uri-id-url" => ["UNIQUE", "uri-id", "url(512)"], "uri-id-id" => ["uri-id", "id"], ] ], diff --git a/static/defaults.config.php b/static/defaults.config.php index 619ac3c2bd..8b2b223f6f 100644 --- a/static/defaults.config.php +++ b/static/defaults.config.php @@ -632,6 +632,17 @@ return [ // Timeout in seconds for fetching the XRD links and other requests with an expected shorter timeout 'xrd_timeout' => 20, ], + 'proxy' => [ + // forwarded_for_headers (String) + // A comma separated list of all allowed header values to retrieve the real client IP + // The headers are evaluated in order. + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR', + + // trusted_proxies (String) + // A comma separated list of all trusted proxies, which will get skipped during client IP retrieval + // IP ranges and CIDR notations are allowed + 'trusted_proxies' => '', + ], 'experimental' => [ // exp_themes (Boolean) // Show experimental themes in user settings. diff --git a/static/dependencies.config.php b/static/dependencies.config.php index c11d51cbaa..5aba529db2 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -43,6 +43,8 @@ use Friendica\Core\Lock; use Friendica\Core\Session\Capability\IHandleSessions; use Friendica\Core\Storage\Repository\StorageManager; use Friendica\Database\Database; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; use Friendica\Factory; use Friendica\Core\Storage\Capability\ICanWriteToStorage; use Friendica\Model\User\Cookie; @@ -106,6 +108,22 @@ return [ ['create', [], Dice::CHAIN_CALL], ] ], + DbaDefinition::class => [ + 'constructParams' => [ + [Dice::INSTANCE => '$basepath'], + ], + 'call' => [ + ['load', [false], Dice::CHAIN_CALL], + ], + ], + ViewDefinition::class => [ + 'constructParams' => [ + [Dice::INSTANCE => '$basepath'], + ], + 'call' => [ + ['load', [false], Dice::CHAIN_CALL], + ], + ], Database::class => [ 'constructParams' => [ [Dice::INSTANCE => \Psr\Log\NullLogger::class], @@ -208,7 +226,7 @@ return [ ], Cookie::class => [ 'constructParams' => [ - $_SERVER, $_COOKIE + $_COOKIE ], ], ICanWriteToStorage::class => [ @@ -238,4 +256,9 @@ return [ $_SERVER ], ], + App\Request::class => [ + 'constructParams' => [ + $_SERVER + ], + ] ]; diff --git a/static/env.config.php b/static/env.config.php index a83b85b52b..207016d07c 100644 --- a/static/env.config.php +++ b/static/env.config.php @@ -61,4 +61,8 @@ return [ 'REDIS_PORT' => ['system', 'redis_port'], 'REDIS_PW' => ['system', 'redis_password'], 'REDIS_DB' => ['system', 'redis_db'], + + // Proxy Config + 'FRIENDICA_FORWARDED_HEADERS' => ['proxy', 'forwarded_for_headers'], + 'FRIENDICA_TRUSTED_PROXIES' => ['proxy', 'trusted_proxies'], ]; diff --git a/static/routes.config.php b/static/routes.config.php index 72964d2308..dac56a1255 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -165,6 +165,8 @@ return [ '/2fa' => [ '[/]' => [Module\Security\TwoFactor\Verify::class, [R::GET, R::POST]], '/recovery' => [Module\Security\TwoFactor\Recovery::class, [R::GET, R::POST]], + '/trust' => [Module\Security\TwoFactor\Trust::class, [R::GET, R::POST]], + '/signout' => [Module\Security\TwoFactor\SignOut::class, [R::GET, R::POST]], ], '/api' => [ diff --git a/static/settings.config.php b/static/settings.config.php index ea7558e5f7..8e62e9bb3e 100644 --- a/static/settings.config.php +++ b/static/settings.config.php @@ -114,6 +114,10 @@ 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, + // jpeg_quality (Integer) // Sets the ImageMagick quality level for JPEG images. Values ranges from 50 (awful) to 100 (near perfect). 'jpeg_quality' => 100, diff --git a/tests/Util/AppDouble.php b/tests/Util/AppDouble.php index 1288ec68be..28689425a2 100644 --- a/tests/Util/AppDouble.php +++ b/tests/Util/AppDouble.php @@ -43,7 +43,7 @@ class AppDouble extends App $this->isLoggedIn = $isLoggedIn; } - public function isLoggedIn() + public function isLoggedIn(): bool { return $this->isLoggedIn; } diff --git a/tests/Util/Database/ExtendedPDO.php b/tests/Util/Database/ExtendedPDO.php index b127e312ca..b36c126d5b 100644 --- a/tests/Util/Database/ExtendedPDO.php +++ b/tests/Util/Database/ExtendedPDO.php @@ -33,7 +33,7 @@ class ExtendedPDO extends PDO /** * @var array Database drivers that support SAVEPOINT * statements. */ - protected static $_supportedDrivers = ["pgsql", "mysql"]; + protected static $_supportedDrivers = ['pgsql', 'mysql']; /** * @var int the current transaction depth @@ -80,9 +80,9 @@ class ExtendedPDO extends PDO /** * Commit current transaction * - * @return bool|void + * @return bool */ - public function commit() + public function commit(): bool { // We don't want to "really" commit something, so skip the most outer hierarchy if ($this->_transactionDepth <= 1 && $this->hasSavepoint()) { @@ -92,28 +92,29 @@ class ExtendedPDO extends PDO $this->_transactionDepth--; - $this->exec("RELEASE SAVEPOINT LEVEL{$this->_transactionDepth}"); + return $this->exec("RELEASE SAVEPOINT LEVEL{$this->_transactionDepth}"); } /** * Rollback current transaction, * * @throws PDOException if there is no transaction started - * @return bool|void + * @return bool Whether rollback was successful */ - public function rollBack() + public function rollback(): bool { $this->_transactionDepth--; - if($this->_transactionDepth <= 0 || !$this->hasSavepoint()) { + if ($this->_transactionDepth <= 0 || !$this->hasSavepoint()) { $this->_transactionDepth = 0; try { - parent::rollBack(); + return parent::rollBack(); } catch (PDOException $e) { // this shouldn't happen, but it does ... } } else { - $this->exec("ROLLBACK TO SAVEPOINT LEVEL{$this->_transactionDepth}"); + return $this->exec("ROLLBACK TO SAVEPOINT LEVEL{$this->_transactionDepth}"); } + return false; } } diff --git a/tests/Util/Database/StaticDatabase.php b/tests/Util/Database/StaticDatabase.php index a6b2575f59..3e981b8d53 100644 --- a/tests/Util/Database/StaticDatabase.php +++ b/tests/Util/Database/StaticDatabase.php @@ -45,9 +45,9 @@ class StaticDatabase extends Database /** * Override the behaviour of connect, due there is just one, static connection at all * - * @return bool|void + * @return bool Success */ - public function connect() + public function connect(): bool { if (!is_null($this->connection) && $this->connected()) { return true; @@ -81,7 +81,7 @@ class StaticDatabase extends Database } /** Mock for locking tables */ - public function lock($table) + public function lock($table): bool { if ($this->_locked) { return false; @@ -94,7 +94,7 @@ class StaticDatabase extends Database } /** Mock for unlocking tables */ - public function unlock() + public function unlock(): bool { // See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html $this->performCommit(); @@ -110,7 +110,7 @@ class StaticDatabase extends Database * * @return bool Was the command executed successfully? */ - public function commit() + public function commit(): bool { if (!$this->performCommit()) { return false; @@ -129,6 +129,9 @@ class StaticDatabase extends Database */ public static function statConnect(array $server) { + // Init variables + $db_host = $db_user = $db_data = $db_pw = ''; + // Use environment variables for mysql if they are set beforehand if (!empty($server['MYSQL_HOST']) && (!empty($server['MYSQL_USERNAME']) || !empty($server['MYSQL_USER'])) @@ -158,14 +161,14 @@ class StaticDatabase extends Database $serverdata = explode(':', $serveraddr); $server = $serverdata[0]; if (count($serverdata) > 1) { - $port = trim($serverdata[1]); + $port = (int) trim($serverdata[1]); } $server = trim($server); $user = trim($db_user); - $pass = trim($db_pw ?? ''); + $pass = trim($db_pw); $db = trim($db_data); - if (!(strlen($server) && strlen($user))) { + if (!(strlen($server) && strlen($user) && strlen($db))) { return; } @@ -179,7 +182,18 @@ class StaticDatabase extends Database self::$staticConnection = @new ExtendedPDO($connect, $user, $pass); self::$staticConnection->setAttribute(PDO::ATTR_AUTOCOMMIT,0); } catch (PDOException $e) { - /// @TODO At least log exception, don't ignore it! + /* + * @TODO Try to find a way to log this exception as it contains valueable information + * @nupplaphil@github.com comment: + * + * There is no easy possibility to add a logger here, that's why + * there isn't any yet and instead a placeholder.. This execution + * point is a critical state during a testrun, and tbh I'd like to + * leave here no further logic (yet) because I spent hours debugging + * cases, where transactions weren't fully closed and + * strange/unpredictable errors occur (sometimes -mainly during + * debugging other errors :) ...) + */ } } diff --git a/tests/Util/VFSTrait.php b/tests/Util/VFSTrait.php index 53d37f85c8..f2ac81bfbf 100644 --- a/tests/Util/VFSTrait.php +++ b/tests/Util/VFSTrait.php @@ -50,6 +50,7 @@ trait VFSTrait $this->root = vfsStream::setup('friendica', 0777, $structure); $this->setConfigFile('dbstructure.config.php', true); + $this->setConfigFile('dbview.config.php', true); $this->setConfigFile('defaults.config.php', true); $this->setConfigFile('settings.config.php', true); $this->setConfigFile('local.config.php'); diff --git a/tests/src/App/RequestTest.php b/tests/src/App/RequestTest.php new file mode 100644 index 0000000000..4ab557358a --- /dev/null +++ b/tests/src/App/RequestTest.php @@ -0,0 +1,129 @@ +. + * + */ + +namespace Friendica\Test\src\App; + +use Friendica\App\Request; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Test\MockedTest; + +class RequestTest extends MockedTest +{ + public function dataServerArray(): array + { + return [ + 'default' => [ + 'server' => ['REMOTE_ADDR' => '1.2.3.4'], + 'config' => [ + 'trusted_proxies' => '', + 'forwarded_for_headers' => '', + ], + 'assertion' => '1.2.3.4', + ], + 'proxy_1' => [ + 'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'], + 'config' => [ + 'trusted_proxies' => '1.2.3.4', + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR', + ], + 'assertion' => '4.5.6.7', + ], + 'proxy_2' => [ + 'server' => ['HTTP_X_FORWARDED_FOR' => '4.5.6.7, 1.2.3.4', 'REMOTE_ADDR' => '1.2.3.4'], + 'config' => [ + 'trusted_proxies' => '1.2.3.4', + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR', + ], + 'assertion' => '4.5.6.7', + ], + 'proxy_CIDR_multiple_proxies' => [ + 'server' => ['HTTP_X_FORWARDED_FOR' => '4.5.6.7, 1.2.3.4', 'REMOTE_ADDR' => '10.0.1.1'], + 'config' => [ + 'trusted_proxies' => '10.0.0.0/16, 1.2.3.4', + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR', + ], + 'assertion' => '4.5.6.7', + ], + 'proxy_wrong_CIDR' => [ + 'server' => ['HTTP_X_FORWARDED_FOR' => '4.5.6.7, 1.2.3.4', 'REMOTE_ADDR' => '10.1.0.1'], + 'config' => [ + 'trusted_proxies' => '10.0.0.0/24, 1.2.3.4', + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR', + ], + 'assertion' => '10.1.0.1', + ], + 'proxy_3' => [ + 'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'], + 'config' => [ + 'trusted_proxies' => '1.2.3.4', + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR', + ], + 'assertion' => '4.5.6.7', + ], + 'proxy_multiple_header_1' => [ + 'server' => ['HTTP_X_FORWARDED' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'], + 'config' => [ + 'trusted_proxies' => '1.2.3.4', + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR, HTTP_X_FORWARDED', + ], + 'assertion' => '4.5.6.7', + ], + 'proxy_multiple_header_2' => [ + 'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_X_FORWARDED' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'], + 'config' => [ + 'trusted_proxies' => '1.2.3.4', + 'forwarded_for_headers' => 'HTTP_X_FORWARDED_FOR, HTTP_X_FORWARDED', + ], + 'assertion' => '4.5.6.7', + ], + 'proxy_multiple_header_wrong' => [ + 'server' => ['HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_X_FORWARDED' => '1.2.3.4, 4.5.6.7', 'REMOTE_ADDR' => '1.2.3.4'], + 'config' => [ + 'trusted_proxies' => '1.2.3.4', + 'forwarded_for_headers' => '', + ], + 'assertion' => '1.2.3.4', + ], + 'no_remote_addr' => [ + 'server' => [], + 'config' => [ + 'trusted_proxies' => '1.2.3.4', + 'forwarded_for_headers' => '', + ], + 'assertion' => '0.0.0.0', + ], + ]; + } + + /** + * @dataProvider dataServerArray + */ + public function testRemoteAddress(array $server, array $config, string $assertion) + { + $configClass = \Mockery::mock(IManageConfigValues::class); + $configClass->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn($config['trusted_proxies']); + $configClass->shouldReceive('get')->with('proxy', 'forwarded_for_headers', Request::DEFAULT_FORWARD_FOR_HEADER)->andReturn($config['forwarded_for_headers']); + + $request = new Request($configClass, $server); + + self::assertEquals($assertion, $request->getRemoteAddress()); + } +} diff --git a/tests/src/Content/Text/BBCodeTest.php b/tests/src/Content/Text/BBCodeTest.php index a5a27057fb..9f293b706c 100644 --- a/tests/src/Content/Text/BBCodeTest.php +++ b/tests/src/Content/Text/BBCodeTest.php @@ -467,4 +467,130 @@ Karl Marx - Die ursprüngliche Akkumulation self::assertEquals($expected, $actual); } + + public function dataFetchShareAttributes(): array + { + return [ + 'no-tag' => [ + 'expected' => [], + 'text' => 'Venture the only home we\'ve ever known laws of physics tendrils of gossamer clouds a still more glorious dawn awaits Sea of Tranquility. With pretty stories for which there\'s little good evidence the ash of stellar alchemy corpus callosum preserve and cherish that pale blue dot descended from astronomers preserve and cherish that pale blue dot. A mote of dust suspended in a sunbeam paroxysm of global death two ghostly white figures in coveralls and helmets are softly dancing descended from astronomers star stuff harvesting star light gathered by gravity and billions upon billions upon billions upon billions upon billions upon billions upon billions.', + ], + 'just-open' => [ + 'expected' => [], + 'text' => '[share]', + ], + 'empty-tag' => [ + 'expected' => [ + 'author' => '', + 'profile' => '', + 'avatar' => '', + 'link' => '', + 'posted' => '', + 'guid' => '', + 'comment' => '', + 'shared' => '', + ], + 'text' => '[share][/share]', + ], + 'comment-shared' => [ + 'expected' => [ + 'author' => '', + 'profile' => '', + 'avatar' => '', + 'link' => '', + 'posted' => '', + 'guid' => '', + 'comment' => 'comment', + 'shared' => 'shared', + ], + 'text' => ' comment + [share] + shared + [/share]', + ], + 'all-attributes' => [ + 'expected' => [ + 'author' => 'Hypolite Petovan', + 'profile' => 'https://friendica.mrpetovan.com/profile/hypolite', + 'avatar' => 'https://friendica.mrpetovan.com/photo/20682437145daa4e85f019a278584494-5.png', + 'link' => 'https://friendica.mrpetovan.com/display/735a2029-1062-ab23-42e4-f9c631220243', + 'posted' => '2022-06-16 12:34:10', + 'guid' => '735a2029-1062-ab23-42e4-f9c631220243', + 'comment' => '', + 'shared' => 'George Lucas: I made a science-fiction universe with a straightforward anti-authoritarianism plot where even the libertarian joins the rebellion. +Disney: So a morally grey “choose your side” story, right? +Lucas: For the right price, yes.', + ], + 'text' => "[share + author='Hypolite Petovan' + profile='https://friendica.mrpetovan.com/profile/hypolite' + avatar='https://friendica.mrpetovan.com/photo/20682437145daa4e85f019a278584494-5.png' + link='https://friendica.mrpetovan.com/display/735a2029-1062-ab23-42e4-f9c631220243' + posted='2022-06-16 12:34:10' + guid='735a2029-1062-ab23-42e4-f9c631220243' + ]George Lucas: I made a science-fiction universe with a straightforward anti-authoritarianism plot where even the libertarian joins the rebellion. +Disney: So a morally grey “choose your side” story, right? +Lucas: For the right price, yes.[/share]", + ], + 'optional-attributes' => [ + 'expected' => [ + 'author' => 'Hypolite Petovan', + 'profile' => 'https://friendica.mrpetovan.com/profile/hypolite', + 'avatar' => 'https://friendica.mrpetovan.com/photo/20682437145daa4e85f019a278584494-5.png', + 'link' => 'https://friendica.mrpetovan.com/display/735a2029-1062-ab23-42e4-f9c631220243', + 'posted' => '2022-06-16 12:34:10', + 'guid' => '', + 'comment' => '', + 'shared' => 'George Lucas: I made a science-fiction universe with a straightforward anti-authoritarianism plot where even the libertarian joins the rebellion. +Disney: So a morally grey “choose your side” story, right? +Lucas: For the right price, yes.', + ], + 'text' => "[share + author='Hypolite Petovan' + profile='https://friendica.mrpetovan.com/profile/hypolite' + avatar='https://friendica.mrpetovan.com/photo/20682437145daa4e85f019a278584494-5.png' + link='https://friendica.mrpetovan.com/display/735a2029-1062-ab23-42e4-f9c631220243' + posted='2022-06-16 12:34:10' + ]George Lucas: I made a science-fiction universe with a straightforward anti-authoritarianism plot where even the libertarian joins the rebellion. +Disney: So a morally grey “choose your side” story, right? +Lucas: For the right price, yes.[/share]", + ], + 'double-quotes' => [ + 'expected' => [ + 'author' => 'Hypolite Petovan', + 'profile' => 'https://friendica.mrpetovan.com/profile/hypolite', + 'avatar' => 'https://friendica.mrpetovan.com/photo/20682437145daa4e85f019a278584494-5.png', + 'link' => 'https://friendica.mrpetovan.com/display/735a2029-1062-ab23-42e4-f9c631220243', + 'posted' => '2022-06-16 12:34:10', + 'guid' => '', + 'comment' => '', + 'shared' => 'George Lucas: I made a science-fiction universe with a straightforward anti-authoritarianism plot where even the libertarian joins the rebellion. +Disney: So a morally grey “choose your side” story, right? +Lucas: For the right price, yes.', + ], + 'text' => '[share + author="Hypolite Petovan" + profile="https://friendica.mrpetovan.com/profile/hypolite" + avatar="https://friendica.mrpetovan.com/photo/20682437145daa4e85f019a278584494-5.png" + link="https://friendica.mrpetovan.com/display/735a2029-1062-ab23-42e4-f9c631220243" + posted="2022-06-16 12:34:10" + ]George Lucas: I made a science-fiction universe with a straightforward anti-authoritarianism plot where even the libertarian joins the rebellion. +Disney: So a morally grey “choose your side” story, right? +Lucas: For the right price, yes.[/share]', + ], + ]; + } + + /** + * @dataProvider dataFetchShareAttributes + * + * @param array $expected Expected attribute array + * @param string $text Input text + */ + public function testFetchShareAttributes(array $expected, string $text) + { + $actual = BBCode::fetchShareAttributes($text); + + self::assertEquals($expected, $actual); + } } diff --git a/tests/src/Core/Cache/CacheTest.php b/tests/src/Core/Cache/CacheTest.php index 88154c9d22..c249aefbfa 100644 --- a/tests/src/Core/Cache/CacheTest.php +++ b/tests/src/Core/Cache/CacheTest.php @@ -237,4 +237,13 @@ abstract class CacheTest extends MockedTest self::assertNotContains('value1', $list); self::assertNotContains('value2', $list); } + + /** + * @small + */ + public function testSpaceInKey() + { + self::assertTrue($this->instance->set('key space', 'value')); + self::assertEquals('value', $this->instance->get('key space')); + } } diff --git a/tests/src/Core/Cache/DatabaseCacheTest.php b/tests/src/Core/Cache/DatabaseCacheTest.php index b8d49aa0cc..71b488bcb1 100644 --- a/tests/src/Core/Cache/DatabaseCacheTest.php +++ b/tests/src/Core/Cache/DatabaseCacheTest.php @@ -23,6 +23,8 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache; use Friendica\Core\Config\Factory\Config; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; use Friendica\Test\DatabaseTestTrait; use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Test\Util\VFSTrait; @@ -57,7 +59,10 @@ class DatabaseCacheTest extends CacheTest $loader = (new Config())->createConfigFileLoader($this->root->url(), []); $configCache = $configFactory->createCache($loader); - $dba = new StaticDatabase($configCache, $profiler, $logger); + $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); + $viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); + + $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition, $logger); $this->cache = new Cache\Type\DatabaseCache('database', $dba); return $this->cache; diff --git a/tests/src/Core/Storage/DatabaseStorageTest.php b/tests/src/Core/Storage/DatabaseStorageTest.php index 8f8dc8bf1c..75bbc4239b 100644 --- a/tests/src/Core/Storage/DatabaseStorageTest.php +++ b/tests/src/Core/Storage/DatabaseStorageTest.php @@ -23,6 +23,8 @@ namespace Friendica\Test\src\Core\Storage; use Friendica\Core\Config\Factory\Config; use Friendica\Core\Storage\Type\Database; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; use Friendica\Test\DatabaseTestTrait; use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Test\Util\VFSTrait; @@ -56,7 +58,10 @@ class DatabaseStorageTest extends StorageTest $loader = (new Config())->createConfigFileLoader($this->root->url(), []); $configCache = $configFactory->createCache($loader); - $dba = new StaticDatabase($configCache, $profiler, $logger); + $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); + $viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); + + $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition, $logger); return new Database($dba); } diff --git a/tests/src/Core/Storage/Repository/StorageManagerTest.php b/tests/src/Core/Storage/Repository/StorageManagerTest.php index cce12b790a..99dee27a63 100644 --- a/tests/src/Core/Storage/Repository/StorageManagerTest.php +++ b/tests/src/Core/Storage/Repository/StorageManagerTest.php @@ -37,6 +37,8 @@ use Friendica\Core\Storage\Repository\StorageManager; use Friendica\Core\Storage\Type\Filesystem; use Friendica\Core\Storage\Type\SystemResource; use Friendica\Database\Database; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; use Friendica\DI; use Friendica\Core\Config\Factory\Config; use Friendica\Core\Config\Repository; @@ -82,7 +84,10 @@ class StorageManagerTest extends DatabaseTest $loader = $configFactory->createConfigFileLoader($this->root->url(), []); $configCache = $configFactory->createCache($loader); - $this->dba = new StaticDatabase($configCache, $profiler, $this->logger); + $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); + $viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); + + $this->dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition, $this->logger); $configModel = new Repository\Config($this->dba, new Mode(Mode::DBCONFIGAVAILABLE)); $this->config = new PreloadConfig($configCache, $configModel); diff --git a/tests/src/Database/DBATest.php b/tests/src/Database/DBATest.php index c92133ac54..febe9c8c62 100644 --- a/tests/src/Database/DBATest.php +++ b/tests/src/Database/DBATest.php @@ -55,9 +55,6 @@ class DBATest extends DatabaseTest self::assertTrue(DBA::exists('config', [])); self::assertFalse(DBA::exists('notable', [])); - self::assertTrue(DBA::exists('config', null)); - self::assertFalse(DBA::exists('notable', null)); - self::assertTrue(DBA::exists('config', ['k' => 'hostname'])); self::assertFalse(DBA::exists('config', ['k' => 'nonsense'])); } diff --git a/tests/src/Database/DBStructureTest.php b/tests/src/Database/DBStructureTest.php index 638a98ed7a..613e2f7832 100644 --- a/tests/src/Database/DBStructureTest.php +++ b/tests/src/Database/DBStructureTest.php @@ -45,7 +45,6 @@ class DBStructureTest extends DatabaseTest */ public function testExists() { self::assertTrue(DBStructure::existsTable('config')); - self::assertFalse(DBStructure::existsTable('notatable')); self::assertTrue(DBStructure::existsColumn('config', ['k'])); diff --git a/tests/src/Model/User/CookieTest.php b/tests/src/Model/User/CookieTest.php index 9021605f82..fa99a0b75b 100644 --- a/tests/src/Model/User/CookieTest.php +++ b/tests/src/Model/User/CookieTest.php @@ -22,6 +22,7 @@ namespace Friendica\Test\src\Model\User; use Friendica\App\BaseURL; +use Friendica\App\Request; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Model\User\Cookie; use Friendica\Test\MockedTest; @@ -35,13 +36,15 @@ class CookieTest extends MockedTest /** @var MockInterface|BaseURL */ private $baseUrl; + const SERVER_ARRAY = ['REMOTE_ADDR' => '1.2.3.4']; + protected function setUp(): void { StaticCookie::clearStatic(); parent::setUp(); - $this->config = \Mockery::mock(IManageConfigValues::class); + $this->config = \Mockery::mock(IManageConfigValues::class); $this->baseUrl = \Mockery::mock(BaseURL::class); } @@ -60,8 +63,11 @@ class CookieTest extends MockedTest $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn('1235')->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once(); + $this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once(); - $cookie = new Cookie($this->config, $this->baseUrl); + $request = new Request($this->config,static::SERVER_ARRAY); + + $cookie = new Cookie($request, $this->config, $this->baseUrl); self::assertInstanceOf(Cookie::class, $cookie); } @@ -124,8 +130,11 @@ class CookieTest extends MockedTest $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn('1235')->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once(); + $this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once(); - $cookie = new Cookie($this->config, $this->baseUrl, [], $cookieData); + $request = new Request($this->config, static::SERVER_ARRAY); + + $cookie = new Cookie($request, $this->config, $this->baseUrl, $cookieData); self::assertInstanceOf(Cookie::class, $cookie); if (isset($uid)) { @@ -182,8 +191,11 @@ class CookieTest extends MockedTest $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverPrivateKey)->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn('7')->once(); + $this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once(); - $cookie = new Cookie($this->config, $this->baseUrl); + $request = new Request($this->config, static::SERVER_ARRAY); + + $cookie = new Cookie($request, $this->config, $this->baseUrl); self::assertInstanceOf(Cookie::class, $cookie); self::assertEquals($assertTrue, $cookie->comparePrivateDataHash($assertHash, $password, $userPrivateKey)); @@ -239,8 +251,13 @@ class CookieTest extends MockedTest $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverKey)->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once(); + $this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once(); + $this->config->shouldReceive('get')->with('proxy', 'forwarded_for_headers')->andReturn(Request::DEFAULT_FORWARD_FOR_HEADER); - $cookie = new StaticCookie($this->config, $this->baseUrl, $serverArray); + + $request = new Request($this->config, $serverArray); + + $cookie = new StaticCookie($request, $this->config, $this->baseUrl); self::assertInstanceOf(Cookie::class, $cookie); $cookie->setMultiple([ @@ -261,8 +278,12 @@ class CookieTest extends MockedTest $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn($serverKey)->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once(); + $this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once(); + $this->config->shouldReceive('get')->with('proxy', 'forwarded_for_headers')->andReturn(Request::DEFAULT_FORWARD_FOR_HEADER); - $cookie = new StaticCookie($this->config, $this->baseUrl, $serverArray); + $request = new Request($this->config, $serverArray); + + $cookie = new StaticCookie($request, $this->config, $this->baseUrl, $serverArray); self::assertInstanceOf(Cookie::class, $cookie); $cookie->set('uid', $uid); @@ -283,8 +304,11 @@ class CookieTest extends MockedTest $this->baseUrl->shouldReceive('getSSLPolicy')->andReturn(true)->once(); $this->config->shouldReceive('get')->with('system', 'site_prvkey')->andReturn(24)->once(); $this->config->shouldReceive('get')->with('system', 'auth_cookie_lifetime', Cookie::DEFAULT_EXPIRE)->andReturn(Cookie::DEFAULT_EXPIRE)->once(); + $this->config->shouldReceive('get')->with('proxy', 'trusted_proxies', '')->andReturn('')->once(); - $cookie = new StaticCookie($this->config, $this->baseUrl); + $request = new Request($this->config, static::SERVER_ARRAY); + + $cookie = new StaticCookie($request, $this->config, $this->baseUrl); self::assertInstanceOf(Cookie::class, $cookie); self::assertEquals('test', StaticCookie::$_COOKIE[Cookie::NAME]); diff --git a/tests/src/Network/HTTPClient/Client/HTTPClientTest.php b/tests/src/Network/HTTPClient/Client/HTTPClientTest.php index a6a873c83a..cbe2a84366 100644 --- a/tests/src/Network/HTTPClient/Client/HTTPClientTest.php +++ b/tests/src/Network/HTTPClient/Client/HTTPClientTest.php @@ -49,4 +49,19 @@ class HTTPClientTest extends MockedTest self::assertFalse(DI::httpClient()->get('https://friendica.local')->isSuccess()); } + + /** + * Test for issue https://github.com/friendica/friendica/issues/11726 + */ + public function testRedirect() + { + $this->httpRequestHandler->setHandler(new MockHandler([ + new Response(302, ['Location' => 'https://mastodon.social/about']), + new Response(200, ['Location' => 'https://mastodon.social']), + ])); + + $result = DI::httpClient()->get('https://mastodon.social'); + self::assertEquals('https://mastodon.social', $result->getUrl()); + self::assertEquals('https://mastodon.social/about', $result->getRedirectUrl()); + } } diff --git a/tests/src/Security/TwoFactor/Factory/TrustedBrowserTest.php b/tests/src/Security/TwoFactor/Factory/TrustedBrowserTest.php index 84a118eb80..7bb07a1335 100644 --- a/tests/src/Security/TwoFactor/Factory/TrustedBrowserTest.php +++ b/tests/src/Security/TwoFactor/Factory/TrustedBrowserTest.php @@ -38,6 +38,7 @@ class TrustedBrowserTest extends MockedTest 'uid' => 42, 'user_agent' => 'PHPUnit', 'created' => DateTimeFormat::utcNow(), + 'trusted' => true, 'last_used' => null, ]; @@ -57,6 +58,7 @@ class TrustedBrowserTest extends MockedTest 'uid' => null, 'user_agent' => null, 'created' => null, + 'trusted' => true, 'last_used' => null, ]; @@ -69,14 +71,15 @@ class TrustedBrowserTest extends MockedTest { $factory = new TrustedBrowser(new NullLogger()); - $uid = 42; + $uid = 42; $userAgent = 'PHPUnit'; - $trustedBrowser = $factory->createForUserWithUserAgent($uid, $userAgent); + $trustedBrowser = $factory->createForUserWithUserAgent($uid, $userAgent, true); $this->assertNotEmpty($trustedBrowser->cookie_hash); $this->assertEquals($uid, $trustedBrowser->uid); $this->assertEquals($userAgent, $trustedBrowser->user_agent); + $this->assertTrue($trustedBrowser->trusted); $this->assertNotEmpty($trustedBrowser->created); } } diff --git a/tests/src/Security/TwoFactor/Model/TrustedBrowserTest.php b/tests/src/Security/TwoFactor/Model/TrustedBrowserTest.php index 0c91ea5e5e..cf5db0ffd8 100644 --- a/tests/src/Security/TwoFactor/Model/TrustedBrowserTest.php +++ b/tests/src/Security/TwoFactor/Model/TrustedBrowserTest.php @@ -36,12 +36,14 @@ class TrustedBrowserTest extends MockedTest $hash, 42, 'PHPUnit', + true, DateTimeFormat::utcNow() ); $this->assertEquals($hash, $trustedBrowser->cookie_hash); $this->assertEquals(42, $trustedBrowser->uid); $this->assertEquals('PHPUnit', $trustedBrowser->user_agent); + $this->assertTrue($trustedBrowser->trusted); $this->assertNotEmpty($trustedBrowser->created); } @@ -54,6 +56,7 @@ class TrustedBrowserTest extends MockedTest $hash, 42, 'PHPUnit', + true, $past, $past ); diff --git a/tests/src/Util/StringsTest.php b/tests/src/Util/StringsTest.php index 6f0fc32fe3..830f97b2f2 100644 --- a/tests/src/Util/StringsTest.php +++ b/tests/src/Util/StringsTest.php @@ -113,22 +113,18 @@ class StringsTest extends TestCase 'input' => '', 'valid' => false, ], - 'nullHex' => [ - 'input' => null, - 'valid' => false, - ], ]; } /** * Tests if the string is a valid hexadecimal value * - * @param string|null $input - * @param bool $valid + * @param string $input Input string + * @param bool $valid Whether testing on valid or invalid * * @dataProvider dataIsHex */ - public function testIsHex(string $input = null, bool $valid = false) + public function testIsHex(string $input, bool $valid = false) { self::assertEquals($valid, Strings::isHex($input)); } diff --git a/update.php b/update.php index 6635bd813c..d66691b962 100644 --- a/update.php +++ b/update.php @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * - * Automatic post-databse structure change updates + * Automatic post-database structure change updates * * These functions are responsible for doing critical post update changes to the data (not the structure) in the database. * @@ -40,8 +40,10 @@ * If you need to run a script before the database update, name the function "pre_update_4712()" */ +use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Logger; use Friendica\Core\Storage\Capability\ICanReadFromStorage; +use Friendica\Core\Storage\Type\Database as DatabaseStorage; use Friendica\Core\Update; use Friendica\Core\Worker; use Friendica\Database\Database; @@ -979,7 +981,7 @@ function update_1429() return Update::FAILED; } - DI::config()->set("system", "post_update_version", 1423); + DI::config()->set('system', 'post_update_version', 1423); return Update::SUCCESS; } @@ -988,9 +990,9 @@ function update_1434() { $name = DI::config()->get('storage', 'name'); - // in case of an empty config, set "Database" as default storage backend + // In case of an empty config, set "Database" as default storage backend if (empty($name)) { - DI::config()->set('storage', 'name', \Friendica\Core\Storage\Type\Database::getName()); + DI::config()->set('storage', 'name', DatabaseStorage::getName()); } // In case of a Using deprecated storage class value, set the right name for it @@ -1079,10 +1081,7 @@ function update_1446() // In case the distributed cache driver is the default value, but the current cache driver isn't default, // we assume that the distributed cache driver should be the same as the current cache driver - if ( - $distributed_cache_driver_source === \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC - && $cache_driver_source > \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC - ) { + if ($distributed_cache_driver_source === Cache::SOURCE_STATIC && $cache_driver_source > Cache::SOURCE_STATIC) { DI::config()->set('system', 'distributed_cache_driver', DI::config()->get('system', 'cache_driver')); } diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 333a0aaa66..178d909dfa 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2022.09-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-06-13 05:45+0000\n" +"POT-Creation-Date: 2022-07-07 17:00-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -28,7 +28,7 @@ msgid "Access denied." msgstr "" #: mod/cal.php:63 mod/cal.php:80 mod/photos.php:69 mod/photos.php:140 -#: mod/photos.php:798 src/Model/Profile.php:231 src/Module/Feed.php:72 +#: mod/photos.php:798 src/Model/Profile.php:232 src/Module/Feed.php:72 #: src/Module/HCard.php:52 src/Module/Profile/Common.php:41 #: src/Module/Profile/Common.php:52 src/Module/Profile/Contacts.php:40 #: src/Module/Profile/Contacts.php:50 src/Module/Profile/Media.php:38 @@ -43,8 +43,8 @@ msgstr "" msgid "Access to this profile has been restricted." msgstr "" -#: mod/cal.php:243 mod/events.php:374 src/Content/Nav.php:194 -#: src/Content/Nav.php:258 src/Module/BaseProfile.php:84 +#: mod/cal.php:243 mod/events.php:374 src/Content/Nav.php:196 +#: src/Content/Nav.php:260 src/Module/BaseProfile.php:84 #: src/Module/BaseProfile.php:95 view/theme/frio/theme.php:229 #: view/theme/frio/theme.php:233 msgid "Events" @@ -62,21 +62,21 @@ msgstr "" msgid "Next" msgstr "" -#: mod/cal.php:249 mod/events.php:383 src/Model/Event.php:457 +#: mod/cal.php:249 mod/events.php:383 src/Model/Event.php:456 msgid "today" msgstr "" -#: mod/cal.php:250 mod/events.php:384 src/Model/Event.php:458 +#: mod/cal.php:250 mod/events.php:384 src/Model/Event.php:457 #: src/Util/Temporal.php:334 msgid "month" msgstr "" -#: mod/cal.php:251 mod/events.php:385 src/Model/Event.php:459 +#: mod/cal.php:251 mod/events.php:385 src/Model/Event.php:458 #: src/Util/Temporal.php:335 msgid "week" msgstr "" -#: mod/cal.php:252 mod/events.php:386 src/Model/Event.php:460 +#: mod/cal.php:252 mod/events.php:386 src/Model/Event.php:459 #: src/Util/Temporal.php:336 msgid "day" msgstr "" @@ -106,7 +106,7 @@ msgstr "" #: mod/display.php:143 mod/photos.php:802 #: src/Module/Conversation/Community.php:175 src/Module/Directory.php:49 -#: src/Module/Search/Index.php:50 +#: src/Module/Search/Index.php:65 msgid "Public access denied." msgstr "" @@ -119,7 +119,7 @@ msgid "The feed for this item is unavailable." msgstr "" #: mod/editpost.php:38 mod/events.php:217 mod/follow.php:56 mod/follow.php:130 -#: mod/item.php:181 mod/item.php:186 mod/item.php:875 mod/message.php:69 +#: mod/item.php:181 mod/item.php:186 mod/item.php:880 mod/message.php:69 #: mod/message.php:111 mod/notes.php:44 mod/ostatus_subscribe.php:33 #: mod/photos.php:160 mod/photos.php:891 mod/repair_ostatus.php:31 #: mod/settings.php:40 mod/settings.php:50 mod/settings.php:156 @@ -159,13 +159,13 @@ msgstr "" msgid "Edit post" msgstr "" -#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:875 +#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:882 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:73 msgid "Save" msgstr "" #: mod/editpost.php:92 mod/photos.php:1338 src/Content/Conversation.php:338 -#: src/Module/Contact/Poke.php:176 src/Object/Post.php:989 +#: src/Module/Contact/Poke.php:176 src/Object/Post.php:993 msgid "Loading..." msgstr "" @@ -231,7 +231,7 @@ msgstr "" #: mod/editpost.php:107 mod/message.php:200 mod/message.php:358 #: mod/photos.php:1489 mod/wallmessage.php:142 src/Content/Conversation.php:368 #: src/Content/Conversation.php:713 src/Module/Item/Compose.php:177 -#: src/Object/Post.php:528 +#: src/Object/Post.php:538 msgid "Please wait" msgstr "" @@ -263,7 +263,7 @@ msgstr "" #: mod/editpost.php:128 mod/events.php:513 mod/photos.php:1337 #: mod/photos.php:1393 mod/photos.php:1467 src/Content/Conversation.php:383 -#: src/Module/Item/Compose.php:172 src/Object/Post.php:999 +#: src/Module/Item/Compose.php:172 src/Object/Post.php:1003 msgid "Preview" msgstr "" @@ -271,52 +271,53 @@ msgstr "" #: mod/follow.php:144 mod/photos.php:1004 mod/photos.php:1105 mod/tagrm.php:35 #: mod/tagrm.php:127 mod/unfollow.php:97 src/Content/Conversation.php:386 #: src/Module/Contact/Revoke.php:108 src/Module/RemoteFollow.php:127 +#: src/Module/Security/TwoFactor/SignOut.php:125 msgid "Cancel" msgstr "" #: mod/editpost.php:134 src/Content/Conversation.php:343 -#: src/Module/Item/Compose.php:163 src/Object/Post.php:990 +#: src/Module/Item/Compose.php:163 src/Object/Post.php:994 msgid "Bold" msgstr "" #: mod/editpost.php:135 src/Content/Conversation.php:344 -#: src/Module/Item/Compose.php:164 src/Object/Post.php:991 +#: src/Module/Item/Compose.php:164 src/Object/Post.php:995 msgid "Italic" msgstr "" #: mod/editpost.php:136 src/Content/Conversation.php:345 -#: src/Module/Item/Compose.php:165 src/Object/Post.php:992 +#: src/Module/Item/Compose.php:165 src/Object/Post.php:996 msgid "Underline" msgstr "" #: mod/editpost.php:137 src/Content/Conversation.php:346 -#: src/Module/Item/Compose.php:166 src/Object/Post.php:993 +#: src/Module/Item/Compose.php:166 src/Object/Post.php:997 msgid "Quote" msgstr "" #: mod/editpost.php:138 src/Content/Conversation.php:347 -#: src/Module/Item/Compose.php:167 src/Object/Post.php:994 +#: src/Module/Item/Compose.php:167 src/Object/Post.php:998 msgid "Code" msgstr "" #: mod/editpost.php:139 src/Content/Conversation.php:349 -#: src/Module/Item/Compose.php:169 src/Object/Post.php:996 +#: src/Module/Item/Compose.php:169 src/Object/Post.php:1000 msgid "Link" msgstr "" #: mod/editpost.php:140 src/Content/Conversation.php:350 -#: src/Module/Item/Compose.php:170 src/Object/Post.php:997 +#: src/Module/Item/Compose.php:170 src/Object/Post.php:1001 msgid "Link or Media" msgstr "" #: mod/editpost.php:143 src/Content/Conversation.php:393 -#: src/Content/Widget/VCard.php:113 src/Model/Profile.php:462 +#: src/Content/Widget/VCard.php:113 src/Model/Profile.php:463 #: src/Module/Admin/Logs/View.php:93 msgid "Message" msgstr "" #: mod/editpost.php:144 src/Content/Conversation.php:394 -#: src/Module/Settings/TwoFactor/Trusted.php:137 +#: src/Module/Settings/TwoFactor/Trusted.php:138 msgid "Browser" msgstr "" @@ -366,8 +367,8 @@ msgstr "" #: src/Module/Install.php:286 src/Module/Install.php:291 #: src/Module/Install.php:305 src/Module/Install.php:320 #: src/Module/Install.php:347 src/Module/Register.php:148 -#: src/Module/Security/TwoFactor/Verify.php:100 -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Security/TwoFactor/Verify.php:101 +#: src/Module/Settings/TwoFactor/Index.php:141 #: src/Module/Settings/TwoFactor/Verify.php:154 msgid "Required" msgstr "" @@ -386,8 +387,8 @@ msgid "Description:" msgstr "" #: mod/events.php:504 src/Content/Widget/VCard.php:104 src/Model/Event.php:80 -#: src/Model/Event.php:107 src/Model/Event.php:466 src/Model/Event.php:915 -#: src/Model/Profile.php:370 src/Module/Contact/Profile.php:369 +#: src/Model/Event.php:107 src/Model/Event.php:465 src/Model/Event.php:915 +#: src/Model/Profile.php:371 src/Module/Contact/Profile.php:369 #: src/Module/Directory.php:148 src/Module/Notifications/Introductions.php:185 #: src/Module/Profile/Profile.php:194 msgid "Location:" @@ -413,7 +414,7 @@ msgstr "" #: src/Module/Install.php:252 src/Module/Install.php:294 #: src/Module/Install.php:331 src/Module/Invite.php:178 #: src/Module/Item/Compose.php:162 src/Module/Profile/Profile.php:247 -#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:988 +#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:992 #: view/theme/duepuntozero/config.php:69 view/theme/frio/config.php:160 #: view/theme/quattro/config.php:71 view/theme/vier/config.php:119 msgid "Submit" @@ -432,7 +433,7 @@ msgstr "" msgid "Failed to remove event" msgstr "" -#: mod/fbrowser.php:61 src/Content/Nav.php:192 src/Module/BaseProfile.php:64 +#: mod/fbrowser.php:61 src/Content/Nav.php:194 src/Module/BaseProfile.php:64 #: view/theme/frio/theme.php:227 msgid "Photos" msgstr "" @@ -466,8 +467,8 @@ msgstr "" msgid "OStatus support is disabled. Contact can't be added." msgstr "" -#: mod/follow.php:138 src/Content/Item.php:443 src/Content/Widget.php:78 -#: src/Model/Contact.php:1102 src/Model/Contact.php:1114 +#: mod/follow.php:138 src/Content/Item.php:459 src/Content/Widget.php:80 +#: src/Model/Contact.php:1104 src/Model/Contact.php:1116 #: view/theme/vier/theme.php:172 msgid "Connect/Follow" msgstr "" @@ -520,19 +521,19 @@ msgstr "" msgid "Empty post discarded." msgstr "" -#: mod/item.php:687 +#: mod/item.php:692 msgid "Post updated." msgstr "" -#: mod/item.php:697 mod/item.php:702 +#: mod/item.php:702 mod/item.php:707 msgid "Item wasn't stored." msgstr "" -#: mod/item.php:713 +#: mod/item.php:718 msgid "Item couldn't be fetched." msgstr "" -#: mod/item.php:853 src/Module/Admin/Themes/Details.php:39 +#: mod/item.php:858 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 msgid "Item not found." @@ -688,7 +689,7 @@ msgstr "" msgid "Profile Match" msgstr "" -#: mod/message.php:46 mod/message.php:126 src/Content/Nav.php:286 +#: mod/message.php:46 mod/message.php:126 src/Content/Nav.php:288 msgid "New Message" msgstr "" @@ -714,7 +715,7 @@ msgstr "" msgid "Discard" msgstr "" -#: mod/message.php:133 src/Content/Nav.php:283 view/theme/frio/theme.php:234 +#: mod/message.php:133 src/Content/Nav.php:285 view/theme/frio/theme.php:234 msgid "Messages" msgstr "" @@ -1068,16 +1069,16 @@ msgstr "" #: mod/photos.php:1333 mod/photos.php:1389 mod/photos.php:1463 #: src/Module/Contact.php:544 src/Module/Item/Compose.php:160 -#: src/Object/Post.php:985 +#: src/Object/Post.php:989 msgid "This is you" msgstr "" #: mod/photos.php:1335 mod/photos.php:1391 mod/photos.php:1465 -#: src/Object/Post.php:522 src/Object/Post.php:987 +#: src/Object/Post.php:532 src/Object/Post.php:991 msgid "Comment" msgstr "" -#: mod/photos.php:1424 src/Content/Conversation.php:629 src/Object/Post.php:247 +#: mod/photos.php:1424 src/Content/Conversation.php:629 src/Object/Post.php:256 msgid "Select" msgstr "" @@ -1087,19 +1088,19 @@ msgstr "" msgid "Delete" msgstr "" -#: mod/photos.php:1486 src/Object/Post.php:369 +#: mod/photos.php:1486 src/Object/Post.php:379 msgid "Like" msgstr "" -#: mod/photos.php:1487 src/Object/Post.php:369 +#: mod/photos.php:1487 src/Object/Post.php:379 msgid "I like this (toggle)" msgstr "" -#: mod/photos.php:1488 src/Object/Post.php:370 +#: mod/photos.php:1488 src/Object/Post.php:380 msgid "Dislike" msgstr "" -#: mod/photos.php:1490 src/Object/Post.php:370 +#: mod/photos.php:1490 src/Object/Post.php:380 msgid "I don't like this (toggle)" msgstr "" @@ -1128,7 +1129,7 @@ msgstr "" msgid "Contact not found." msgstr "" -#: mod/removeme.php:65 src/Navigation/Notifications/Repository/Notify.php:482 +#: mod/removeme.php:65 src/Navigation/Notifications/Repository/Notify.php:483 msgid "[Friendica System Notify]" msgstr "" @@ -1166,7 +1167,7 @@ msgid "Resubscribing to OStatus contacts" msgstr "" #: mod/repair_ostatus.php:46 src/Module/Debug/ActivityPubConversion.php:134 -#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:97 +#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:98 msgid "Error" msgid_plural "Errors" msgstr[0] "" @@ -1188,7 +1189,7 @@ msgstr "" msgid "Name" msgstr "" -#: mod/settings.php:177 src/Content/Nav.php:212 +#: mod/settings.php:177 src/Content/Nav.php:214 msgid "Home Page" msgstr "" @@ -1386,7 +1387,7 @@ msgstr "" msgid "Action after import:" msgstr "" -#: mod/settings.php:350 src/Content/Nav.php:280 +#: mod/settings.php:350 src/Content/Nav.php:282 msgid "Mark as seen" msgstr "" @@ -1404,19 +1405,19 @@ msgid "" "hours." msgstr "" -#: mod/suggest.php:55 src/Content/Widget.php:81 view/theme/vier/theme.php:175 +#: mod/suggest.php:55 src/Content/Widget.php:83 view/theme/vier/theme.php:175 msgid "Friend Suggestions" msgstr "" -#: mod/tagger.php:78 src/Content/Item.php:342 src/Model/Item.php:2699 +#: mod/tagger.php:78 src/Content/Item.php:354 src/Model/Item.php:2728 msgid "photo" msgstr "" -#: mod/tagger.php:78 src/Content/Item.php:337 src/Content/Item.php:346 +#: mod/tagger.php:78 src/Content/Item.php:348 src/Content/Item.php:358 msgid "status" msgstr "" -#: mod/tagger.php:111 src/Content/Item.php:356 +#: mod/tagger.php:111 src/Content/Item.php:368 #, php-format msgid "%1$s tagged %2$s's %3$s with %4$s" msgstr "" @@ -1430,7 +1431,7 @@ msgid "Select a tag to remove: " msgstr "" #: mod/tagrm.php:126 src/Module/Settings/Delegation.php:179 -#: src/Module/Settings/TwoFactor/Trusted.php:140 +#: src/Module/Settings/TwoFactor/Trusted.php:142 msgid "Remove" msgstr "" @@ -1522,7 +1523,7 @@ msgstr "" msgid "File upload failed." msgstr "" -#: mod/wall_upload.php:218 src/Model/Photo.php:1061 +#: mod/wall_upload.php:218 src/Model/Photo.php:1087 msgid "Wall Photos" msgstr "" @@ -1546,11 +1547,11 @@ msgid "" "your site allow private mail from unknown senders." msgstr "" -#: src/App.php:463 +#: src/App.php:473 msgid "No system theme config value set." msgstr "" -#: src/App.php:584 +#: src/App.php:594 msgid "Apologies but the website is unavailable at the moment." msgstr "" @@ -1568,56 +1569,56 @@ msgstr "" msgid "toggle mobile" msgstr "" -#: src/App/Router.php:275 +#: src/App/Router.php:282 #, php-format msgid "Method not allowed for this module. Allowed method(s): %s" msgstr "" -#: src/App/Router.php:277 src/Module/HTTPException/PageNotFound.php:34 +#: src/App/Router.php:284 src/Module/HTTPException/PageNotFound.php:49 msgid "Page not found." msgstr "" -#: src/App/Router.php:305 +#: src/App/Router.php:312 msgid "You must be logged in to use addons. " msgstr "" -#: src/BaseModule.php:377 +#: src/BaseModule.php:392 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:404 +#: src/BaseModule.php:419 msgid "All contacts" msgstr "" -#: src/BaseModule.php:409 src/Content/Widget.php:233 src/Core/ACL.php:194 +#: src/BaseModule.php:424 src/Content/Widget.php:235 src/Core/ACL.php:194 #: src/Module/Contact.php:367 src/Module/PermissionTooltip.php:122 #: src/Module/PermissionTooltip.php:144 msgid "Followers" msgstr "" -#: src/BaseModule.php:414 src/Content/Widget.php:234 src/Module/Contact.php:368 +#: src/BaseModule.php:429 src/Content/Widget.php:236 src/Module/Contact.php:368 msgid "Following" msgstr "" -#: src/BaseModule.php:419 src/Content/Widget.php:235 src/Module/Contact.php:369 +#: src/BaseModule.php:434 src/Content/Widget.php:237 src/Module/Contact.php:369 msgid "Mutual friends" msgstr "" -#: src/BaseModule.php:427 +#: src/BaseModule.php:442 msgid "Common" msgstr "" -#: src/Console/Addon.php:177 src/Console/Addon.php:202 +#: src/Console/Addon.php:175 src/Console/Addon.php:199 msgid "Addon not found" msgstr "" -#: src/Console/Addon.php:181 +#: src/Console/Addon.php:179 msgid "Addon already enabled" msgstr "" -#: src/Console/Addon.php:206 +#: src/Console/Addon.php:203 msgid "Addon already disabled" msgstr "" @@ -1840,78 +1841,78 @@ msgstr "" msgid "Monthly" msgstr "" -#: src/Content/ContactSelector.php:123 +#: src/Content/ContactSelector.php:126 msgid "DFRN" msgstr "" -#: src/Content/ContactSelector.php:124 +#: src/Content/ContactSelector.php:127 msgid "OStatus" msgstr "" -#: src/Content/ContactSelector.php:125 +#: src/Content/ContactSelector.php:128 msgid "RSS/Atom" msgstr "" -#: src/Content/ContactSelector.php:126 src/Module/Admin/Users/Active.php:129 +#: src/Content/ContactSelector.php:129 src/Module/Admin/Users/Active.php:129 #: src/Module/Admin/Users/Blocked.php:130 src/Module/Admin/Users/Create.php:73 #: src/Module/Admin/Users/Deleted.php:88 src/Module/Admin/Users/Index.php:142 #: src/Module/Admin/Users/Index.php:162 src/Module/Admin/Users/Pending.php:104 msgid "Email" msgstr "" -#: src/Content/ContactSelector.php:127 src/Module/Debug/Babel.php:307 +#: src/Content/ContactSelector.php:130 src/Module/Debug/Babel.php:307 msgid "Diaspora" msgstr "" -#: src/Content/ContactSelector.php:128 +#: src/Content/ContactSelector.php:131 msgid "Zot!" msgstr "" -#: src/Content/ContactSelector.php:129 +#: src/Content/ContactSelector.php:132 msgid "LinkedIn" msgstr "" -#: src/Content/ContactSelector.php:130 +#: src/Content/ContactSelector.php:133 msgid "XMPP/IM" msgstr "" -#: src/Content/ContactSelector.php:131 +#: src/Content/ContactSelector.php:134 msgid "MySpace" msgstr "" -#: src/Content/ContactSelector.php:132 +#: src/Content/ContactSelector.php:135 msgid "Google+" msgstr "" -#: src/Content/ContactSelector.php:133 +#: src/Content/ContactSelector.php:136 msgid "pump.io" msgstr "" -#: src/Content/ContactSelector.php:134 +#: src/Content/ContactSelector.php:137 msgid "Twitter" msgstr "" -#: src/Content/ContactSelector.php:135 +#: src/Content/ContactSelector.php:138 msgid "Discourse" msgstr "" -#: src/Content/ContactSelector.php:136 +#: src/Content/ContactSelector.php:139 msgid "Diaspora Connector" msgstr "" -#: src/Content/ContactSelector.php:137 +#: src/Content/ContactSelector.php:140 msgid "GNU Social Connector" msgstr "" -#: src/Content/ContactSelector.php:138 +#: src/Content/ContactSelector.php:141 msgid "ActivityPub" msgstr "" -#: src/Content/ContactSelector.php:139 +#: src/Content/ContactSelector.php:142 msgid "pnut" msgstr "" -#: src/Content/ContactSelector.php:175 +#: src/Content/ContactSelector.php:178 #, php-format msgid "%s (via %s)" msgstr "" @@ -2016,7 +2017,7 @@ msgid "Visible to everybody" msgstr "" #: src/Content/Conversation.php:308 src/Module/Item/Compose.php:171 -#: src/Object/Post.php:998 +#: src/Object/Post.php:1002 msgid "Please enter a image/video/audio/webpage URL:" msgstr "" @@ -2049,7 +2050,7 @@ msgid "Share" msgstr "" #: src/Content/Conversation.php:348 src/Module/Item/Compose.php:168 -#: src/Object/Post.php:995 +#: src/Object/Post.php:999 msgid "Image" msgstr "" @@ -2061,25 +2062,25 @@ msgstr "" msgid "Scheduled at" msgstr "" -#: src/Content/Conversation.php:657 src/Object/Post.php:235 +#: src/Content/Conversation.php:657 src/Object/Post.php:244 msgid "Pinned item" msgstr "" -#: src/Content/Conversation.php:673 src/Object/Post.php:476 -#: src/Object/Post.php:477 +#: src/Content/Conversation.php:673 src/Object/Post.php:486 +#: src/Object/Post.php:487 #, php-format msgid "View %s's profile @ %s" msgstr "" -#: src/Content/Conversation.php:686 src/Object/Post.php:464 +#: src/Content/Conversation.php:686 src/Object/Post.php:474 msgid "Categories:" msgstr "" -#: src/Content/Conversation.php:687 src/Object/Post.php:465 +#: src/Content/Conversation.php:687 src/Object/Post.php:475 msgid "Filed under:" msgstr "" -#: src/Content/Conversation.php:695 src/Object/Post.php:490 +#: src/Content/Conversation.php:695 src/Object/Post.php:500 #, php-format msgid "%s from %s" msgstr "" @@ -2249,8 +2250,8 @@ msgstr "" msgid "Display membership date in profile" msgstr "" -#: src/Content/ForumManager.php:151 src/Content/Nav.php:239 -#: src/Content/Text/HTML.php:896 src/Content/Widget.php:522 +#: src/Content/ForumManager.php:151 src/Content/Nav.php:241 +#: src/Content/Text/HTML.php:903 src/Content/Widget.php:524 msgid "Forums" msgstr "" @@ -2258,64 +2259,64 @@ msgstr "" msgid "External link to forum" msgstr "" -#: src/Content/ForumManager.php:156 src/Content/Widget.php:501 +#: src/Content/ForumManager.php:156 src/Content/Widget.php:503 msgid "show less" msgstr "" -#: src/Content/ForumManager.php:157 src/Content/Widget.php:403 -#: src/Content/Widget.php:502 +#: src/Content/ForumManager.php:157 src/Content/Widget.php:405 +#: src/Content/Widget.php:504 msgid "show more" msgstr "" -#: src/Content/Item.php:301 +#: src/Content/Item.php:306 #, php-format msgid "%1$s poked %2$s" msgstr "" -#: src/Content/Item.php:334 src/Model/Item.php:2697 +#: src/Content/Item.php:345 src/Model/Item.php:2726 msgid "event" msgstr "" -#: src/Content/Item.php:422 view/theme/frio/theme.php:254 +#: src/Content/Item.php:438 view/theme/frio/theme.php:254 msgid "Follow Thread" msgstr "" -#: src/Content/Item.php:423 src/Model/Contact.php:1107 +#: src/Content/Item.php:439 src/Model/Contact.php:1109 msgid "View Status" msgstr "" -#: src/Content/Item.php:424 src/Content/Item.php:446 src/Model/Contact.php:1041 -#: src/Model/Contact.php:1099 src/Model/Contact.php:1108 +#: src/Content/Item.php:440 src/Content/Item.php:462 src/Model/Contact.php:1043 +#: src/Model/Contact.php:1101 src/Model/Contact.php:1110 #: src/Module/Directory.php:158 src/Module/Settings/Profile/Index.php:225 msgid "View Profile" msgstr "" -#: src/Content/Item.php:425 src/Model/Contact.php:1109 +#: src/Content/Item.php:441 src/Model/Contact.php:1111 msgid "View Photos" msgstr "" -#: src/Content/Item.php:426 src/Model/Contact.php:1100 -#: src/Model/Contact.php:1110 +#: src/Content/Item.php:442 src/Model/Contact.php:1102 +#: src/Model/Contact.php:1112 msgid "Network Posts" msgstr "" -#: src/Content/Item.php:427 src/Model/Contact.php:1101 -#: src/Model/Contact.php:1111 +#: src/Content/Item.php:443 src/Model/Contact.php:1103 +#: src/Model/Contact.php:1113 msgid "View Contact" msgstr "" -#: src/Content/Item.php:428 src/Model/Contact.php:1112 +#: src/Content/Item.php:444 src/Model/Contact.php:1114 msgid "Send PM" msgstr "" -#: src/Content/Item.php:429 src/Module/Admin/Blocklist/Contact.php:100 +#: src/Content/Item.php:445 src/Module/Admin/Blocklist/Contact.php:100 #: src/Module/Admin/Users/Active.php:140 src/Module/Admin/Users/Index.php:154 #: src/Module/Contact.php:398 src/Module/Contact/Profile.php:348 #: src/Module/Contact/Profile.php:449 msgid "Block" msgstr "" -#: src/Content/Item.php:430 src/Module/Contact.php:399 +#: src/Content/Item.php:446 src/Module/Contact.php:399 #: src/Module/Contact/Profile.php:349 src/Module/Contact/Profile.php:457 #: src/Module/Notifications/Introductions.php:132 #: src/Module/Notifications/Introductions.php:204 @@ -2323,11 +2324,11 @@ msgstr "" msgid "Ignore" msgstr "" -#: src/Content/Item.php:434 src/Object/Post.php:445 +#: src/Content/Item.php:450 src/Object/Post.php:455 msgid "Languages" msgstr "" -#: src/Content/Item.php:438 src/Model/Contact.php:1113 +#: src/Content/Item.php:454 src/Model/Contact.php:1115 msgid "Poke" msgstr "" @@ -2343,256 +2344,256 @@ msgstr "" msgid "Clear notifications" msgstr "" -#: src/Content/Nav.php:96 src/Content/Text/HTML.php:883 +#: src/Content/Nav.php:96 src/Content/Text/HTML.php:890 msgid "@name, !forum, #tags, content" msgstr "" -#: src/Content/Nav.php:183 src/Module/Security/Login.php:144 +#: src/Content/Nav.php:185 src/Module/Security/Login.php:144 msgid "Logout" msgstr "" -#: src/Content/Nav.php:183 +#: src/Content/Nav.php:185 msgid "End this session" msgstr "" -#: src/Content/Nav.php:185 src/Module/Bookmarklet.php:44 +#: src/Content/Nav.php:187 src/Module/Bookmarklet.php:44 #: src/Module/Security/Login.php:145 msgid "Login" msgstr "" -#: src/Content/Nav.php:185 +#: src/Content/Nav.php:187 msgid "Sign in" msgstr "" -#: src/Content/Nav.php:190 src/Module/BaseProfile.php:56 +#: src/Content/Nav.php:192 src/Module/BaseProfile.php:56 #: src/Module/Contact.php:433 src/Module/Contact/Profile.php:380 -#: src/Module/Settings/TwoFactor/Index.php:112 view/theme/frio/theme.php:225 +#: src/Module/Settings/TwoFactor/Index.php:120 view/theme/frio/theme.php:225 msgid "Status" msgstr "" -#: src/Content/Nav.php:190 src/Content/Nav.php:273 +#: src/Content/Nav.php:192 src/Content/Nav.php:275 #: view/theme/frio/theme.php:225 msgid "Your posts and conversations" msgstr "" -#: src/Content/Nav.php:191 src/Module/BaseProfile.php:48 +#: src/Content/Nav.php:193 src/Module/BaseProfile.php:48 #: src/Module/BaseSettings.php:55 src/Module/Contact.php:457 #: src/Module/Contact/Profile.php:382 src/Module/Profile/Profile.php:241 #: src/Module/Welcome.php:57 view/theme/frio/theme.php:226 msgid "Profile" msgstr "" -#: src/Content/Nav.php:191 view/theme/frio/theme.php:226 +#: src/Content/Nav.php:193 view/theme/frio/theme.php:226 msgid "Your profile page" msgstr "" -#: src/Content/Nav.php:192 view/theme/frio/theme.php:227 +#: src/Content/Nav.php:194 view/theme/frio/theme.php:227 msgid "Your photos" msgstr "" -#: src/Content/Nav.php:193 src/Module/BaseProfile.php:72 +#: src/Content/Nav.php:195 src/Module/BaseProfile.php:72 #: src/Module/BaseProfile.php:75 src/Module/Contact.php:449 #: view/theme/frio/theme.php:228 msgid "Media" msgstr "" -#: src/Content/Nav.php:193 view/theme/frio/theme.php:228 +#: src/Content/Nav.php:195 view/theme/frio/theme.php:228 msgid "Your postings with media" msgstr "" -#: src/Content/Nav.php:194 view/theme/frio/theme.php:229 +#: src/Content/Nav.php:196 view/theme/frio/theme.php:229 msgid "Your events" msgstr "" -#: src/Content/Nav.php:195 +#: src/Content/Nav.php:197 msgid "Personal notes" msgstr "" -#: src/Content/Nav.php:195 +#: src/Content/Nav.php:197 msgid "Your personal notes" msgstr "" -#: src/Content/Nav.php:212 src/Content/Nav.php:273 +#: src/Content/Nav.php:214 src/Content/Nav.php:275 msgid "Home" msgstr "" -#: src/Content/Nav.php:216 src/Module/Register.php:168 +#: src/Content/Nav.php:218 src/Module/Register.php:168 #: src/Module/Security/Login.php:105 msgid "Register" msgstr "" -#: src/Content/Nav.php:216 +#: src/Content/Nav.php:218 msgid "Create an account" msgstr "" -#: src/Content/Nav.php:222 src/Module/Help.php:67 +#: src/Content/Nav.php:224 src/Module/Help.php:67 #: src/Module/Settings/TwoFactor/AppSpecific.php:127 -#: src/Module/Settings/TwoFactor/Index.php:111 +#: src/Module/Settings/TwoFactor/Index.php:119 #: src/Module/Settings/TwoFactor/Recovery.php:105 #: src/Module/Settings/TwoFactor/Verify.php:145 view/theme/vier/theme.php:217 msgid "Help" msgstr "" -#: src/Content/Nav.php:222 +#: src/Content/Nav.php:224 msgid "Help and documentation" msgstr "" -#: src/Content/Nav.php:226 +#: src/Content/Nav.php:228 msgid "Apps" msgstr "" -#: src/Content/Nav.php:226 +#: src/Content/Nav.php:228 msgid "Addon applications, utilities, games" msgstr "" -#: src/Content/Nav.php:230 src/Content/Text/HTML.php:881 -#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:97 +#: src/Content/Nav.php:232 src/Content/Text/HTML.php:888 +#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:112 msgid "Search" msgstr "" -#: src/Content/Nav.php:230 +#: src/Content/Nav.php:232 msgid "Search site content" msgstr "" -#: src/Content/Nav.php:233 src/Content/Text/HTML.php:890 +#: src/Content/Nav.php:235 src/Content/Text/HTML.php:897 msgid "Full Text" msgstr "" -#: src/Content/Nav.php:234 src/Content/Text/HTML.php:891 +#: src/Content/Nav.php:236 src/Content/Text/HTML.php:898 #: src/Content/Widget/TagCloud.php:68 msgid "Tags" msgstr "" -#: src/Content/Nav.php:235 src/Content/Nav.php:294 -#: src/Content/Text/HTML.php:892 src/Module/BaseProfile.php:125 +#: src/Content/Nav.php:237 src/Content/Nav.php:296 +#: src/Content/Text/HTML.php:899 src/Module/BaseProfile.php:125 #: src/Module/BaseProfile.php:128 src/Module/Contact.php:370 #: src/Module/Contact.php:464 view/theme/frio/theme.php:236 msgid "Contacts" msgstr "" -#: src/Content/Nav.php:254 +#: src/Content/Nav.php:256 msgid "Community" msgstr "" -#: src/Content/Nav.php:254 +#: src/Content/Nav.php:256 msgid "Conversations on this and other servers" msgstr "" -#: src/Content/Nav.php:258 src/Module/BaseProfile.php:87 +#: src/Content/Nav.php:260 src/Module/BaseProfile.php:87 #: src/Module/BaseProfile.php:98 view/theme/frio/theme.php:233 msgid "Events and Calendar" msgstr "" -#: src/Content/Nav.php:261 +#: src/Content/Nav.php:263 msgid "Directory" msgstr "" -#: src/Content/Nav.php:261 +#: src/Content/Nav.php:263 msgid "People directory" msgstr "" -#: src/Content/Nav.php:263 src/Module/BaseAdmin.php:85 +#: src/Content/Nav.php:265 src/Module/BaseAdmin.php:88 msgid "Information" msgstr "" -#: src/Content/Nav.php:263 +#: src/Content/Nav.php:265 msgid "Information about this friendica instance" msgstr "" -#: src/Content/Nav.php:266 src/Module/Admin/Tos.php:76 -#: src/Module/BaseAdmin.php:96 src/Module/Register.php:176 +#: src/Content/Nav.php:268 src/Module/Admin/Tos.php:76 +#: src/Module/BaseAdmin.php:99 src/Module/Register.php:176 #: src/Module/Tos.php:87 msgid "Terms of Service" msgstr "" -#: src/Content/Nav.php:266 +#: src/Content/Nav.php:268 msgid "Terms of Service of this Friendica instance" msgstr "" -#: src/Content/Nav.php:271 view/theme/frio/theme.php:232 +#: src/Content/Nav.php:273 view/theme/frio/theme.php:232 msgid "Network" msgstr "" -#: src/Content/Nav.php:271 view/theme/frio/theme.php:232 +#: src/Content/Nav.php:273 view/theme/frio/theme.php:232 msgid "Conversations from your friends" msgstr "" -#: src/Content/Nav.php:277 +#: src/Content/Nav.php:279 msgid "Introductions" msgstr "" -#: src/Content/Nav.php:277 +#: src/Content/Nav.php:279 msgid "Friend Requests" msgstr "" -#: src/Content/Nav.php:278 src/Module/BaseNotifications.php:148 +#: src/Content/Nav.php:280 src/Module/BaseNotifications.php:148 #: src/Module/Notifications/Introductions.php:73 msgid "Notifications" msgstr "" -#: src/Content/Nav.php:279 +#: src/Content/Nav.php:281 msgid "See all notifications" msgstr "" -#: src/Content/Nav.php:280 +#: src/Content/Nav.php:282 msgid "Mark all system notifications as seen" msgstr "" -#: src/Content/Nav.php:283 view/theme/frio/theme.php:234 +#: src/Content/Nav.php:285 view/theme/frio/theme.php:234 msgid "Private mail" msgstr "" -#: src/Content/Nav.php:284 +#: src/Content/Nav.php:286 msgid "Inbox" msgstr "" -#: src/Content/Nav.php:285 +#: src/Content/Nav.php:287 msgid "Outbox" msgstr "" -#: src/Content/Nav.php:289 +#: src/Content/Nav.php:291 msgid "Accounts" msgstr "" -#: src/Content/Nav.php:289 +#: src/Content/Nav.php:291 msgid "Manage other pages" msgstr "" -#: src/Content/Nav.php:292 src/Module/Admin/Addons/Details.php:114 +#: src/Content/Nav.php:294 src/Module/Admin/Addons/Details.php:114 #: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:122 #: src/Module/Welcome.php:52 view/theme/frio/theme.php:235 msgid "Settings" msgstr "" -#: src/Content/Nav.php:292 view/theme/frio/theme.php:235 +#: src/Content/Nav.php:294 view/theme/frio/theme.php:235 msgid "Account settings" msgstr "" -#: src/Content/Nav.php:294 view/theme/frio/theme.php:236 +#: src/Content/Nav.php:296 view/theme/frio/theme.php:236 msgid "Manage/edit friends and contacts" msgstr "" -#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:126 +#: src/Content/Nav.php:301 src/Module/BaseAdmin.php:129 msgid "Admin" msgstr "" -#: src/Content/Nav.php:299 +#: src/Content/Nav.php:301 msgid "Site setup and configuration" msgstr "" -#: src/Content/Nav.php:302 +#: src/Content/Nav.php:304 msgid "Navigation" msgstr "" -#: src/Content/Nav.php:302 +#: src/Content/Nav.php:304 msgid "Site map" msgstr "" -#: src/Content/OEmbed.php:299 +#: src/Content/OEmbed.php:317 msgid "Embedding disabled" msgstr "" -#: src/Content/OEmbed.php:417 +#: src/Content/OEmbed.php:441 msgid "Embedded content" msgstr "" @@ -2612,52 +2613,52 @@ msgstr "" msgid "last" msgstr "" -#: src/Content/Text/BBCode.php:990 src/Content/Text/BBCode.php:1784 -#: src/Content/Text/BBCode.php:1785 +#: src/Content/Text/BBCode.php:998 src/Content/Text/BBCode.php:1833 +#: src/Content/Text/BBCode.php:1834 msgid "Image/photo" msgstr "" -#: src/Content/Text/BBCode.php:1163 +#: src/Content/Text/BBCode.php:1188 #, php-format msgid "" "%2$s %3$s" msgstr "" -#: src/Content/Text/BBCode.php:1188 src/Model/Item.php:3271 -#: src/Model/Item.php:3277 src/Model/Item.php:3278 +#: src/Content/Text/BBCode.php:1213 src/Model/Item.php:3301 +#: src/Model/Item.php:3307 src/Model/Item.php:3308 msgid "Link to source" msgstr "" -#: src/Content/Text/BBCode.php:1702 src/Content/Text/HTML.php:933 +#: src/Content/Text/BBCode.php:1751 src/Content/Text/HTML.php:940 msgid "Click to open/close" msgstr "" -#: src/Content/Text/BBCode.php:1733 +#: src/Content/Text/BBCode.php:1782 msgid "$1 wrote:" msgstr "" -#: src/Content/Text/BBCode.php:1789 src/Content/Text/BBCode.php:1790 +#: src/Content/Text/BBCode.php:1838 src/Content/Text/BBCode.php:1839 msgid "Encrypted content" msgstr "" -#: src/Content/Text/BBCode.php:2008 +#: src/Content/Text/BBCode.php:2057 msgid "Invalid source protocol" msgstr "" -#: src/Content/Text/BBCode.php:2023 +#: src/Content/Text/BBCode.php:2072 msgid "Invalid link protocol" msgstr "" -#: src/Content/Text/HTML.php:797 +#: src/Content/Text/HTML.php:805 msgid "Loading more entries..." msgstr "" -#: src/Content/Text/HTML.php:798 +#: src/Content/Text/HTML.php:806 msgid "The end" msgstr "" -#: src/Content/Text/HTML.php:875 src/Content/Widget/VCard.php:109 -#: src/Model/Profile.php:456 +#: src/Content/Text/HTML.php:882 src/Content/Widget/VCard.php:109 +#: src/Model/Profile.php:457 msgid "Follow" msgstr "" @@ -2677,117 +2678,117 @@ msgstr "" msgid "Connect" msgstr "" -#: src/Content/Widget.php:70 +#: src/Content/Widget.php:72 #, php-format msgid "%d invitation available" msgid_plural "%d invitations available" msgstr[0] "" msgstr[1] "" -#: src/Content/Widget.php:76 view/theme/vier/theme.php:170 +#: src/Content/Widget.php:78 view/theme/vier/theme.php:170 msgid "Find People" msgstr "" -#: src/Content/Widget.php:77 view/theme/vier/theme.php:171 +#: src/Content/Widget.php:79 view/theme/vier/theme.php:171 msgid "Enter name or interest" msgstr "" -#: src/Content/Widget.php:79 view/theme/vier/theme.php:173 +#: src/Content/Widget.php:81 view/theme/vier/theme.php:173 msgid "Examples: Robert Morgenstein, Fishing" msgstr "" -#: src/Content/Widget.php:80 src/Module/Contact.php:391 +#: src/Content/Widget.php:82 src/Module/Contact.php:391 #: src/Module/Directory.php:97 view/theme/vier/theme.php:174 msgid "Find" msgstr "" -#: src/Content/Widget.php:82 view/theme/vier/theme.php:176 +#: src/Content/Widget.php:84 view/theme/vier/theme.php:176 msgid "Similar Interests" msgstr "" -#: src/Content/Widget.php:83 view/theme/vier/theme.php:177 +#: src/Content/Widget.php:85 view/theme/vier/theme.php:177 msgid "Random Profile" msgstr "" -#: src/Content/Widget.php:84 view/theme/vier/theme.php:178 +#: src/Content/Widget.php:86 view/theme/vier/theme.php:178 msgid "Invite Friends" msgstr "" -#: src/Content/Widget.php:85 src/Module/Directory.php:89 +#: src/Content/Widget.php:87 src/Module/Directory.php:89 #: view/theme/vier/theme.php:179 msgid "Global Directory" msgstr "" -#: src/Content/Widget.php:87 view/theme/vier/theme.php:181 +#: src/Content/Widget.php:89 view/theme/vier/theme.php:181 msgid "Local Directory" msgstr "" -#: src/Content/Widget.php:209 src/Model/Group.php:570 +#: src/Content/Widget.php:211 src/Model/Group.php:583 #: src/Module/Contact.php:354 src/Module/Welcome.php:76 msgid "Groups" msgstr "" -#: src/Content/Widget.php:211 +#: src/Content/Widget.php:213 msgid "Everyone" msgstr "" -#: src/Content/Widget.php:240 +#: src/Content/Widget.php:242 msgid "Relationships" msgstr "" -#: src/Content/Widget.php:242 src/Module/Contact.php:306 +#: src/Content/Widget.php:244 src/Module/Contact.php:306 #: src/Module/Group.php:293 msgid "All Contacts" msgstr "" -#: src/Content/Widget.php:281 +#: src/Content/Widget.php:283 msgid "Protocols" msgstr "" -#: src/Content/Widget.php:283 +#: src/Content/Widget.php:285 msgid "All Protocols" msgstr "" -#: src/Content/Widget.php:311 +#: src/Content/Widget.php:313 msgid "Saved Folders" msgstr "" -#: src/Content/Widget.php:313 src/Content/Widget.php:344 +#: src/Content/Widget.php:315 src/Content/Widget.php:346 msgid "Everything" msgstr "" -#: src/Content/Widget.php:342 +#: src/Content/Widget.php:344 msgid "Categories" msgstr "" -#: src/Content/Widget.php:399 +#: src/Content/Widget.php:401 #, php-format msgid "%d contact in common" msgid_plural "%d contacts in common" msgstr[0] "" msgstr[1] "" -#: src/Content/Widget.php:495 +#: src/Content/Widget.php:497 msgid "Archives" msgstr "" -#: src/Content/Widget.php:519 +#: src/Content/Widget.php:521 msgid "Persons" msgstr "" -#: src/Content/Widget.php:520 +#: src/Content/Widget.php:522 msgid "Organisations" msgstr "" -#: src/Content/Widget.php:521 src/Model/Contact.php:1537 +#: src/Content/Widget.php:523 src/Model/Contact.php:1537 msgid "News" msgstr "" -#: src/Content/Widget.php:525 src/Module/Settings/Account.php:455 +#: src/Content/Widget.php:527 src/Module/Settings/Account.php:455 msgid "Account Types" msgstr "" -#: src/Content/Widget.php:526 src/Module/Admin/BaseUsers.php:51 +#: src/Content/Widget.php:528 src/Module/Admin/BaseUsers.php:51 msgid "All" msgstr "" @@ -2837,22 +2838,22 @@ msgstr[1] "" msgid "More Trending Tags" msgstr "" -#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:375 +#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:376 #: src/Module/Contact/Profile.php:371 src/Module/Profile/Profile.php:176 msgid "XMPP:" msgstr "" -#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:376 +#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:377 #: src/Module/Contact/Profile.php:373 src/Module/Profile/Profile.php:180 msgid "Matrix:" msgstr "" -#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:468 +#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:469 #: src/Module/Notifications/Introductions.php:199 msgid "Network:" msgstr "" -#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:458 +#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:459 msgid "Unfollow" msgstr "" @@ -3213,206 +3214,206 @@ msgstr "" msgid "Could not connect to database." msgstr "" -#: src/Core/L10n.php:400 src/Model/Event.php:425 +#: src/Core/L10n.php:399 src/Model/Event.php:424 #: src/Module/Settings/Display.php:182 msgid "Monday" msgstr "" -#: src/Core/L10n.php:400 src/Model/Event.php:426 +#: src/Core/L10n.php:399 src/Model/Event.php:425 msgid "Tuesday" msgstr "" -#: src/Core/L10n.php:400 src/Model/Event.php:427 +#: src/Core/L10n.php:399 src/Model/Event.php:426 msgid "Wednesday" msgstr "" -#: src/Core/L10n.php:400 src/Model/Event.php:428 +#: src/Core/L10n.php:399 src/Model/Event.php:427 msgid "Thursday" msgstr "" -#: src/Core/L10n.php:400 src/Model/Event.php:429 +#: src/Core/L10n.php:399 src/Model/Event.php:428 msgid "Friday" msgstr "" -#: src/Core/L10n.php:400 src/Model/Event.php:430 +#: src/Core/L10n.php:399 src/Model/Event.php:429 msgid "Saturday" msgstr "" -#: src/Core/L10n.php:400 src/Model/Event.php:424 +#: src/Core/L10n.php:399 src/Model/Event.php:423 #: src/Module/Settings/Display.php:182 msgid "Sunday" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:445 +#: src/Core/L10n.php:403 src/Model/Event.php:444 msgid "January" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:446 +#: src/Core/L10n.php:403 src/Model/Event.php:445 msgid "February" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:447 +#: src/Core/L10n.php:403 src/Model/Event.php:446 msgid "March" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:448 +#: src/Core/L10n.php:403 src/Model/Event.php:447 msgid "April" msgstr "" -#: src/Core/L10n.php:404 src/Core/L10n.php:424 src/Model/Event.php:436 +#: src/Core/L10n.php:403 src/Core/L10n.php:422 src/Model/Event.php:435 msgid "May" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:449 +#: src/Core/L10n.php:403 src/Model/Event.php:448 msgid "June" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:450 +#: src/Core/L10n.php:403 src/Model/Event.php:449 msgid "July" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:451 +#: src/Core/L10n.php:403 src/Model/Event.php:450 msgid "August" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:452 +#: src/Core/L10n.php:403 src/Model/Event.php:451 msgid "September" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:453 +#: src/Core/L10n.php:403 src/Model/Event.php:452 msgid "October" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:454 +#: src/Core/L10n.php:403 src/Model/Event.php:453 msgid "November" msgstr "" -#: src/Core/L10n.php:404 src/Model/Event.php:455 +#: src/Core/L10n.php:403 src/Model/Event.php:454 msgid "December" msgstr "" -#: src/Core/L10n.php:420 src/Model/Event.php:417 +#: src/Core/L10n.php:418 src/Model/Event.php:416 msgid "Mon" msgstr "" -#: src/Core/L10n.php:420 src/Model/Event.php:418 +#: src/Core/L10n.php:418 src/Model/Event.php:417 msgid "Tue" msgstr "" -#: src/Core/L10n.php:420 src/Model/Event.php:419 +#: src/Core/L10n.php:418 src/Model/Event.php:418 msgid "Wed" msgstr "" -#: src/Core/L10n.php:420 src/Model/Event.php:420 +#: src/Core/L10n.php:418 src/Model/Event.php:419 msgid "Thu" msgstr "" -#: src/Core/L10n.php:420 src/Model/Event.php:421 +#: src/Core/L10n.php:418 src/Model/Event.php:420 msgid "Fri" msgstr "" -#: src/Core/L10n.php:420 src/Model/Event.php:422 +#: src/Core/L10n.php:418 src/Model/Event.php:421 msgid "Sat" msgstr "" -#: src/Core/L10n.php:420 src/Model/Event.php:416 +#: src/Core/L10n.php:418 src/Model/Event.php:415 msgid "Sun" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:432 +#: src/Core/L10n.php:422 src/Model/Event.php:431 msgid "Jan" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:433 +#: src/Core/L10n.php:422 src/Model/Event.php:432 msgid "Feb" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:434 +#: src/Core/L10n.php:422 src/Model/Event.php:433 msgid "Mar" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:435 +#: src/Core/L10n.php:422 src/Model/Event.php:434 msgid "Apr" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:437 +#: src/Core/L10n.php:422 src/Model/Event.php:436 msgid "Jun" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:438 +#: src/Core/L10n.php:422 src/Model/Event.php:437 msgid "Jul" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:439 +#: src/Core/L10n.php:422 src/Model/Event.php:438 msgid "Aug" msgstr "" -#: src/Core/L10n.php:424 +#: src/Core/L10n.php:422 msgid "Sep" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:441 +#: src/Core/L10n.php:422 src/Model/Event.php:440 msgid "Oct" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:442 +#: src/Core/L10n.php:422 src/Model/Event.php:441 msgid "Nov" msgstr "" -#: src/Core/L10n.php:424 src/Model/Event.php:443 +#: src/Core/L10n.php:422 src/Model/Event.php:442 msgid "Dec" msgstr "" -#: src/Core/L10n.php:443 +#: src/Core/L10n.php:441 msgid "poke" msgstr "" -#: src/Core/L10n.php:443 +#: src/Core/L10n.php:441 msgid "poked" msgstr "" -#: src/Core/L10n.php:444 +#: src/Core/L10n.php:442 msgid "ping" msgstr "" -#: src/Core/L10n.php:444 +#: src/Core/L10n.php:442 msgid "pinged" msgstr "" -#: src/Core/L10n.php:445 +#: src/Core/L10n.php:443 msgid "prod" msgstr "" -#: src/Core/L10n.php:445 +#: src/Core/L10n.php:443 msgid "prodded" msgstr "" -#: src/Core/L10n.php:446 +#: src/Core/L10n.php:444 msgid "slap" msgstr "" -#: src/Core/L10n.php:446 +#: src/Core/L10n.php:444 msgid "slapped" msgstr "" -#: src/Core/L10n.php:447 +#: src/Core/L10n.php:445 msgid "finger" msgstr "" -#: src/Core/L10n.php:447 +#: src/Core/L10n.php:445 msgid "fingered" msgstr "" -#: src/Core/L10n.php:448 +#: src/Core/L10n.php:446 msgid "rebuff" msgstr "" -#: src/Core/L10n.php:448 +#: src/Core/L10n.php:446 msgid "rebuffed" msgstr "" #: src/Core/Renderer.php:89 src/Core/Renderer.php:118 src/Core/Renderer.php:145 -#: src/Core/Renderer.php:179 src/Render/FriendicaSmartyEngine.php:56 +#: src/Core/Renderer.php:179 src/Render/FriendicaSmartyEngine.php:69 msgid "" "Friendica can't display this page at the moment, please contact the " "administrator." @@ -3454,12 +3455,12 @@ msgid "" "to version 2021.01 and wait until the postupdate finished version 1383." msgstr "" -#: src/Core/Update.php:152 +#: src/Core/Update.php:153 #, php-format msgid "%s: executing pre update %d" msgstr "" -#: src/Core/Update.php:190 +#: src/Core/Update.php:191 #, php-format msgid "%s: executing post update %d" msgstr "" @@ -3469,7 +3470,7 @@ msgstr "" msgid "Update %s failed. See error logs." msgstr "" -#: src/Core/Update.php:314 +#: src/Core/Update.php:315 #, php-format msgid "" "\n" @@ -3481,51 +3482,51 @@ msgid "" "might be invalid." msgstr "" -#: src/Core/Update.php:320 +#: src/Core/Update.php:321 #, php-format msgid "The error message is\\n[pre]%s[/pre]" msgstr "" -#: src/Core/Update.php:324 src/Core/Update.php:366 +#: src/Core/Update.php:325 src/Core/Update.php:367 msgid "[Friendica Notify] Database update" msgstr "" -#: src/Core/Update.php:360 +#: src/Core/Update.php:361 #, php-format msgid "" "\n" "\t\t\t\t\tThe friendica database was successfully updated from %s to %s." msgstr "" -#: src/Core/UserImport.php:125 +#: src/Core/UserImport.php:126 msgid "Error decoding account file" msgstr "" -#: src/Core/UserImport.php:131 +#: src/Core/UserImport.php:132 msgid "Error! No version data in file! This is not a Friendica account file?" msgstr "" -#: src/Core/UserImport.php:139 +#: src/Core/UserImport.php:140 #, php-format msgid "User '%s' already exists on this server!" msgstr "" -#: src/Core/UserImport.php:175 +#: src/Core/UserImport.php:176 msgid "User creation error" msgstr "" -#: src/Core/UserImport.php:220 +#: src/Core/UserImport.php:221 #, php-format msgid "%d contact not imported" msgid_plural "%d contacts not imported" msgstr[0] "" msgstr[1] "" -#: src/Core/UserImport.php:273 +#: src/Core/UserImport.php:274 msgid "User profile creation error" msgstr "" -#: src/Core/UserImport.php:326 +#: src/Core/UserImport.php:327 msgid "Done. You can now login with your username and password" msgstr "" @@ -3555,7 +3556,7 @@ msgstr "" msgid "There are no tables on MyISAM or InnoDB with the Antelope file format." msgstr "" -#: src/Database/DBStructure.php:158 +#: src/Database/DBStructure.php:157 #, php-format msgid "" "\n" @@ -3563,20 +3564,20 @@ msgid "" "%s\n" msgstr "" -#: src/Database/DBStructure.php:161 +#: src/Database/DBStructure.php:160 msgid "Errors encountered performing database changes: " msgstr "" -#: src/Database/DBStructure.php:549 +#: src/Database/DBStructure.php:563 msgid "Another database update is currently running." msgstr "" -#: src/Database/DBStructure.php:553 +#: src/Database/DBStructure.php:567 #, php-format msgid "%s: Database update" msgstr "" -#: src/Database/DBStructure.php:803 +#: src/Database/DBStructure.php:817 #, php-format msgid "%s: updating %s table." msgstr "" @@ -3607,11 +3608,11 @@ msgstr "" msgid "Legacy module file not found: %s" msgstr "" -#: src/Model/Contact.php:1103 src/Model/Contact.php:1115 +#: src/Model/Contact.php:1105 src/Model/Contact.php:1117 msgid "UnFollow" msgstr "" -#: src/Model/Contact.php:1121 src/Module/Admin/Users/Pending.php:107 +#: src/Model/Contact.php:1123 src/Module/Admin/Users/Pending.php:107 #: src/Module/Notifications/Introductions.php:130 #: src/Module/Notifications/Introductions.php:202 msgid "Approve" @@ -3625,63 +3626,63 @@ msgstr "" msgid "Forum" msgstr "" -#: src/Model/Contact.php:2550 +#: src/Model/Contact.php:2630 msgid "Disallowed profile URL." msgstr "" -#: src/Model/Contact.php:2555 src/Module/Friendica.php:81 +#: src/Model/Contact.php:2635 src/Module/Friendica.php:81 msgid "Blocked domain" msgstr "" -#: src/Model/Contact.php:2560 +#: src/Model/Contact.php:2640 msgid "Connect URL missing." msgstr "" -#: src/Model/Contact.php:2569 +#: src/Model/Contact.php:2649 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "" -#: src/Model/Contact.php:2611 +#: src/Model/Contact.php:2691 msgid "The profile address specified does not provide adequate information." msgstr "" -#: src/Model/Contact.php:2613 +#: src/Model/Contact.php:2693 msgid "No compatible communication protocols or feeds were discovered." msgstr "" -#: src/Model/Contact.php:2616 +#: src/Model/Contact.php:2696 msgid "An author or name was not found." msgstr "" -#: src/Model/Contact.php:2619 +#: src/Model/Contact.php:2699 msgid "No browser URL could be matched to this address." msgstr "" -#: src/Model/Contact.php:2622 +#: src/Model/Contact.php:2702 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "" -#: src/Model/Contact.php:2623 +#: src/Model/Contact.php:2703 msgid "Use mailto: in front of address to force email check." msgstr "" -#: src/Model/Contact.php:2629 +#: src/Model/Contact.php:2709 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "" -#: src/Model/Contact.php:2634 +#: src/Model/Contact.php:2714 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "" -#: src/Model/Contact.php:2693 +#: src/Model/Contact.php:2773 msgid "Unable to retrieve contact information." msgstr "" @@ -3689,41 +3690,41 @@ msgstr "" msgid "l F d, Y \\@ g:i A \\G\\M\\TP (e)" msgstr "" -#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:464 +#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:463 #: src/Model/Event.php:897 msgid "Starts:" msgstr "" -#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:465 +#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:464 #: src/Model/Event.php:901 msgid "Finishes:" msgstr "" -#: src/Model/Event.php:414 +#: src/Model/Event.php:413 msgid "all-day" msgstr "" -#: src/Model/Event.php:440 +#: src/Model/Event.php:439 msgid "Sept" msgstr "" -#: src/Model/Event.php:462 +#: src/Model/Event.php:461 msgid "No events to display" msgstr "" -#: src/Model/Event.php:578 +#: src/Model/Event.php:577 msgid "l, F j" msgstr "" -#: src/Model/Event.php:609 +#: src/Model/Event.php:608 msgid "Edit event" msgstr "" -#: src/Model/Event.php:610 +#: src/Model/Event.php:609 msgid "Duplicate event" msgstr "" -#: src/Model/Event.php:611 +#: src/Model/Event.php:610 msgid "Delete event" msgstr "" @@ -3747,112 +3748,112 @@ msgstr "" msgid "Hide map" msgstr "" -#: src/Model/Event.php:1009 +#: src/Model/Event.php:1010 #, php-format msgid "%s's birthday" msgstr "" -#: src/Model/Event.php:1010 +#: src/Model/Event.php:1011 #, php-format msgid "Happy Birthday %s" msgstr "" -#: src/Model/Group.php:95 +#: 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:486 +#: src/Model/Group.php:499 msgid "Default privacy group for new contacts" msgstr "" -#: src/Model/Group.php:518 +#: src/Model/Group.php:531 msgid "Everybody" msgstr "" -#: src/Model/Group.php:537 +#: src/Model/Group.php:550 msgid "edit" msgstr "" -#: src/Model/Group.php:569 +#: src/Model/Group.php:582 msgid "add" msgstr "" -#: src/Model/Group.php:574 +#: src/Model/Group.php:587 msgid "Edit group" msgstr "" -#: src/Model/Group.php:575 src/Module/Group.php:194 +#: src/Model/Group.php:588 src/Module/Group.php:194 msgid "Contacts not in any group" msgstr "" -#: src/Model/Group.php:577 +#: src/Model/Group.php:590 msgid "Create a new group" msgstr "" -#: src/Model/Group.php:578 src/Module/Group.php:179 src/Module/Group.php:202 +#: src/Model/Group.php:591 src/Module/Group.php:179 src/Module/Group.php:202 #: src/Module/Group.php:277 msgid "Group Name: " msgstr "" -#: src/Model/Group.php:579 +#: src/Model/Group.php:592 msgid "Edit groups" msgstr "" -#: src/Model/Item.php:1795 +#: src/Model/Item.php:1823 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "" -#: src/Model/Item.php:2701 +#: src/Model/Item.php:2730 msgid "activity" msgstr "" -#: src/Model/Item.php:2703 +#: src/Model/Item.php:2732 msgid "comment" msgstr "" -#: src/Model/Item.php:2706 +#: src/Model/Item.php:2735 msgid "post" msgstr "" -#: src/Model/Item.php:2821 +#: src/Model/Item.php:2851 #, php-format msgid "Content warning: %s" msgstr "" -#: src/Model/Item.php:3180 +#: src/Model/Item.php:3210 msgid "bytes" msgstr "" -#: src/Model/Item.php:3214 +#: src/Model/Item.php:3244 #, php-format msgid "%s (%d%s, %d votes)" msgstr "" -#: src/Model/Item.php:3216 +#: src/Model/Item.php:3246 #, php-format msgid "%s (%d votes)" msgstr "" -#: src/Model/Item.php:3221 +#: src/Model/Item.php:3251 #, php-format msgid "%d voters. Poll end: %s" msgstr "" -#: src/Model/Item.php:3223 +#: src/Model/Item.php:3253 #, php-format msgid "%d voters." msgstr "" -#: src/Model/Item.php:3225 +#: src/Model/Item.php:3255 #, php-format msgid "Poll end: %s" msgstr "" -#: src/Model/Item.php:3259 src/Model/Item.php:3260 +#: src/Model/Item.php:3289 src/Model/Item.php:3290 msgid "View on separate page" msgstr "" @@ -3860,147 +3861,147 @@ msgstr "" msgid "[no subject]" msgstr "" -#: src/Model/Profile.php:358 src/Module/Profile/Profile.php:256 +#: src/Model/Profile.php:359 src/Module/Profile/Profile.php:256 #: src/Module/Profile/Profile.php:258 msgid "Edit profile" msgstr "" -#: src/Model/Profile.php:360 +#: src/Model/Profile.php:361 msgid "Change profile photo" msgstr "" -#: src/Model/Profile.php:373 src/Module/Directory.php:153 +#: src/Model/Profile.php:374 src/Module/Directory.php:153 #: src/Module/Profile/Profile.php:184 msgid "Homepage:" msgstr "" -#: src/Model/Profile.php:374 src/Module/Contact/Profile.php:375 +#: src/Model/Profile.php:375 src/Module/Contact/Profile.php:375 #: src/Module/Notifications/Introductions.php:187 msgid "About:" msgstr "" -#: src/Model/Profile.php:460 +#: src/Model/Profile.php:461 msgid "Atom feed" msgstr "" -#: src/Model/Profile.php:504 +#: src/Model/Profile.php:505 msgid "F d" msgstr "" -#: src/Model/Profile.php:568 src/Model/Profile.php:652 +#: src/Model/Profile.php:569 src/Model/Profile.php:653 msgid "[today]" msgstr "" -#: src/Model/Profile.php:577 +#: src/Model/Profile.php:578 msgid "Birthday Reminders" msgstr "" -#: src/Model/Profile.php:578 +#: src/Model/Profile.php:579 msgid "Birthdays this week:" msgstr "" -#: src/Model/Profile.php:601 +#: src/Model/Profile.php:602 msgid "g A l F d" msgstr "" -#: src/Model/Profile.php:639 +#: src/Model/Profile.php:640 msgid "[No description]" msgstr "" -#: src/Model/Profile.php:665 +#: src/Model/Profile.php:666 msgid "Event Reminders" msgstr "" -#: src/Model/Profile.php:666 +#: src/Model/Profile.php:667 msgid "Upcoming events the next 7 days:" msgstr "" -#: src/Model/Profile.php:854 +#: src/Model/Profile.php:855 #, php-format msgid "OpenWebAuth: %1$s welcomes %2$s" msgstr "" -#: src/Model/Profile.php:980 +#: src/Model/Profile.php:981 msgid "Hometown:" msgstr "" -#: src/Model/Profile.php:981 +#: src/Model/Profile.php:982 msgid "Marital Status:" msgstr "" -#: src/Model/Profile.php:982 +#: src/Model/Profile.php:983 msgid "With:" msgstr "" -#: src/Model/Profile.php:983 +#: src/Model/Profile.php:984 msgid "Since:" msgstr "" -#: src/Model/Profile.php:984 +#: src/Model/Profile.php:985 msgid "Sexual Preference:" msgstr "" -#: src/Model/Profile.php:985 +#: src/Model/Profile.php:986 msgid "Political Views:" msgstr "" -#: src/Model/Profile.php:986 +#: src/Model/Profile.php:987 msgid "Religious Views:" msgstr "" -#: src/Model/Profile.php:987 +#: src/Model/Profile.php:988 msgid "Likes:" msgstr "" -#: src/Model/Profile.php:988 +#: src/Model/Profile.php:989 msgid "Dislikes:" msgstr "" -#: src/Model/Profile.php:989 +#: src/Model/Profile.php:990 msgid "Title/Description:" msgstr "" -#: src/Model/Profile.php:990 src/Module/Admin/Summary.php:234 +#: src/Model/Profile.php:991 src/Module/Admin/Summary.php:234 msgid "Summary" msgstr "" -#: src/Model/Profile.php:991 +#: src/Model/Profile.php:992 msgid "Musical interests" msgstr "" -#: src/Model/Profile.php:992 +#: src/Model/Profile.php:993 msgid "Books, literature" msgstr "" -#: src/Model/Profile.php:993 +#: src/Model/Profile.php:994 msgid "Television" msgstr "" -#: src/Model/Profile.php:994 +#: src/Model/Profile.php:995 msgid "Film/dance/culture/entertainment" msgstr "" -#: src/Model/Profile.php:995 +#: src/Model/Profile.php:996 msgid "Hobbies/Interests" msgstr "" -#: src/Model/Profile.php:996 +#: src/Model/Profile.php:997 msgid "Love/romance" msgstr "" -#: src/Model/Profile.php:997 +#: src/Model/Profile.php:998 msgid "Work/employment" msgstr "" -#: src/Model/Profile.php:998 +#: src/Model/Profile.php:999 msgid "School/education" msgstr "" -#: src/Model/Profile.php:999 +#: src/Model/Profile.php:1000 msgid "Contact information and Social Networks" msgstr "" -#: src/Model/User.php:210 src/Model/User.php:1058 +#: src/Model/User.php:212 src/Model/User.php:1058 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "" @@ -4047,13 +4048,13 @@ msgstr "" msgid "Invalid OpenID url" msgstr "" -#: src/Model/User.php:970 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 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:970 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 msgid "The error message was:" msgstr "" @@ -4135,7 +4136,7 @@ msgstr "" msgid "Profile Photos" msgstr "" -#: src/Model/User.php:1368 +#: src/Model/User.php:1367 #, php-format msgid "" "\n" @@ -4143,7 +4144,7 @@ msgid "" "\t\t\tthe administrator of %2$s has set up an account for you." msgstr "" -#: src/Model/User.php:1371 +#: src/Model/User.php:1370 #, php-format msgid "" "\n" @@ -4180,12 +4181,12 @@ msgid "" "\t\tThank you and welcome to %4$s." msgstr "" -#: src/Model/User.php:1404 src/Model/User.php:1511 +#: src/Model/User.php:1403 src/Model/User.php:1510 #, php-format msgid "Registration details for %s" msgstr "" -#: src/Model/User.php:1424 +#: src/Model/User.php:1423 #, php-format msgid "" "\n" @@ -4201,12 +4202,12 @@ msgid "" "\t\t" msgstr "" -#: src/Model/User.php:1443 +#: src/Model/User.php:1442 #, php-format msgid "Registration at %s" msgstr "" -#: src/Model/User.php:1467 +#: src/Model/User.php:1466 #, php-format msgid "" "\n" @@ -4215,7 +4216,7 @@ msgid "" "\t\t\t" msgstr "" -#: src/Model/User.php:1475 +#: src/Model/User.php:1474 #, php-format msgid "" "\n" @@ -4295,7 +4296,7 @@ msgid "Administration" msgstr "" #: src/Module/Admin/Addons/Details.php:112 src/Module/Admin/Addons/Index.php:68 -#: src/Module/BaseAdmin.php:93 src/Module/BaseSettings.php:85 +#: src/Module/BaseAdmin.php:96 src/Module/BaseSettings.php:85 msgid "Addons" msgstr "" @@ -4774,7 +4775,7 @@ msgid "" "only reflect the part of the network your node is aware of." msgstr "" -#: src/Module/Admin/Federation.php:197 src/Module/BaseAdmin.php:87 +#: src/Module/Admin/Federation.php:197 src/Module/BaseAdmin.php:90 msgid "Federation Statistics" msgstr "" @@ -4790,7 +4791,7 @@ msgstr "" msgid "Item marked for deletion." msgstr "" -#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:106 +#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:109 msgid "Delete Item" msgstr "" @@ -4819,7 +4820,7 @@ msgstr "" msgid "The GUID of the item you want to delete." msgstr "" -#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:116 +#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:119 msgid "Item Source" msgstr "" @@ -4882,8 +4883,8 @@ msgstr "" msgid "PHP log currently disabled." msgstr "" -#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:108 -#: src/Module/BaseAdmin.php:109 +#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:111 +#: src/Module/BaseAdmin.php:112 msgid "Logs" msgstr "" @@ -4936,7 +4937,7 @@ msgid "" "is readable." msgstr "" -#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:110 +#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:113 msgid "View Logs" msgstr "" @@ -5118,7 +5119,7 @@ msgstr "" msgid "Interactors" msgstr "" -#: src/Module/Admin/Site.php:432 src/Module/BaseAdmin.php:90 +#: src/Module/Admin/Site.php:432 src/Module/BaseAdmin.php:93 msgid "Site" msgstr "" @@ -5865,87 +5866,97 @@ msgstr "" msgid "On large systems the text search can slow down the system extremely." msgstr "" -#: src/Module/Admin/Site.php:538 +#: src/Module/Admin/Site.php:537 +msgid "Generate counts per contact group when calculating network count" +msgstr "" + +#: src/Module/Admin/Site.php:537 +msgid "" +"On systems with users that heavily use contact groups the query can be very " +"expensive." +msgstr "" + +#: src/Module/Admin/Site.php:539 msgid "Maximum number of parallel workers" msgstr "" -#: src/Module/Admin/Site.php:538 +#: src/Module/Admin/Site.php:539 #, 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:539 +#: src/Module/Admin/Site.php:540 msgid "Enable fastlane" msgstr "" -#: src/Module/Admin/Site.php:539 +#: src/Module/Admin/Site.php:540 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:541 +#: src/Module/Admin/Site.php:542 msgid "Direct relay transfer" msgstr "" -#: src/Module/Admin/Site.php:541 +#: src/Module/Admin/Site.php:542 msgid "" "Enables the direct transfer to other servers without using the relay servers" msgstr "" -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:543 msgid "Relay scope" msgstr "" -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:543 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:542 src/Module/Contact/Profile.php:273 -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Admin/Site.php:543 src/Module/Contact/Profile.php:273 +#: src/Module/Settings/TwoFactor/Index.php:126 msgid "Disabled" msgstr "" -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:543 msgid "all" msgstr "" -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:543 msgid "tags" msgstr "" -#: src/Module/Admin/Site.php:543 +#: src/Module/Admin/Site.php:544 msgid "Server tags" msgstr "" -#: src/Module/Admin/Site.php:543 +#: src/Module/Admin/Site.php:544 msgid "Comma separated list of tags for the \"tags\" subscription." msgstr "" -#: src/Module/Admin/Site.php:544 +#: src/Module/Admin/Site.php:545 msgid "Deny Server tags" msgstr "" -#: src/Module/Admin/Site.php:544 +#: src/Module/Admin/Site.php:545 msgid "Comma separated list of tags that are rejected." msgstr "" -#: src/Module/Admin/Site.php:545 +#: src/Module/Admin/Site.php:546 msgid "Allow user tags" msgstr "" -#: src/Module/Admin/Site.php:545 +#: src/Module/Admin/Site.php:546 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:548 +#: src/Module/Admin/Site.php:549 msgid "Start Relocation" msgstr "" @@ -5971,7 +5982,7 @@ msgstr "" msgid "Storage Configuration" msgstr "" -#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:91 +#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:94 msgid "Storage" msgstr "" @@ -6187,7 +6198,7 @@ msgid "Screenshot" msgstr "" #: src/Module/Admin/Themes/Details.php:91 src/Module/Admin/Themes/Index.php:112 -#: src/Module/BaseAdmin.php:94 +#: src/Module/BaseAdmin.php:97 msgid "Themes" msgstr "" @@ -6388,7 +6399,7 @@ msgid "Permanent deletion" msgstr "" #: src/Module/Admin/Users/Index.php:150 src/Module/Admin/Users/Index.php:160 -#: src/Module/BaseAdmin.php:92 +#: src/Module/BaseAdmin.php:95 msgid "Users" msgstr "" @@ -6494,89 +6505,89 @@ msgstr "" msgid "Item was not found." msgstr "" -#: src/Module/BaseAdmin.php:54 src/Module/BaseAdmin.php:58 +#: src/Module/BaseAdmin.php:57 src/Module/BaseAdmin.php:61 msgid "Please login to continue." msgstr "" -#: src/Module/BaseAdmin.php:63 +#: src/Module/BaseAdmin.php:66 msgid "You don't have access to administration pages." msgstr "" -#: src/Module/BaseAdmin.php:67 +#: src/Module/BaseAdmin.php:70 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/BaseAdmin.php:89 msgid "Overview" msgstr "" -#: src/Module/BaseAdmin.php:89 +#: src/Module/BaseAdmin.php:92 msgid "Configuration" msgstr "" -#: src/Module/BaseAdmin.php:95 src/Module/BaseSettings.php:63 +#: src/Module/BaseAdmin.php:98 src/Module/BaseSettings.php:63 msgid "Additional features" msgstr "" -#: src/Module/BaseAdmin.php:98 +#: src/Module/BaseAdmin.php:101 msgid "Database" msgstr "" -#: src/Module/BaseAdmin.php:99 +#: src/Module/BaseAdmin.php:102 msgid "DB updates" msgstr "" -#: src/Module/BaseAdmin.php:100 +#: src/Module/BaseAdmin.php:103 msgid "Inspect Deferred Workers" msgstr "" -#: src/Module/BaseAdmin.php:101 +#: src/Module/BaseAdmin.php:104 msgid "Inspect worker Queue" msgstr "" -#: src/Module/BaseAdmin.php:103 +#: src/Module/BaseAdmin.php:106 msgid "Tools" msgstr "" -#: src/Module/BaseAdmin.php:104 +#: src/Module/BaseAdmin.php:107 msgid "Contact Blocklist" msgstr "" -#: src/Module/BaseAdmin.php:105 +#: src/Module/BaseAdmin.php:108 msgid "Server Blocklist" msgstr "" -#: src/Module/BaseAdmin.php:112 +#: src/Module/BaseAdmin.php:115 msgid "Diagnostics" msgstr "" -#: src/Module/BaseAdmin.php:113 +#: src/Module/BaseAdmin.php:116 msgid "PHP Info" msgstr "" -#: src/Module/BaseAdmin.php:114 +#: src/Module/BaseAdmin.php:117 msgid "probe address" msgstr "" -#: src/Module/BaseAdmin.php:115 +#: src/Module/BaseAdmin.php:118 msgid "check webfinger" msgstr "" -#: src/Module/BaseAdmin.php:117 +#: src/Module/BaseAdmin.php:120 msgid "Babel" msgstr "" -#: src/Module/BaseAdmin.php:118 src/Module/Debug/ActivityPubConversion.php:142 +#: src/Module/BaseAdmin.php:121 src/Module/Debug/ActivityPubConversion.php:142 msgid "ActivityPub Conversion" msgstr "" -#: src/Module/BaseAdmin.php:127 +#: src/Module/BaseAdmin.php:130 msgid "Addon Features" msgstr "" -#: src/Module/BaseAdmin.php:128 +#: src/Module/BaseAdmin.php:131 msgid "User registrations waiting for confirmation" msgstr "" @@ -6638,8 +6649,8 @@ msgstr "" msgid "Account" msgstr "" -#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:95 -#: src/Module/Settings/TwoFactor/Index.php:110 +#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:96 +#: src/Module/Settings/TwoFactor/Index.php:118 msgid "Two-factor authentication" msgstr "" @@ -6691,7 +6702,7 @@ msgid "Only show blocked contacts" msgstr "" #: src/Module/Contact.php:330 src/Module/Contact.php:377 -#: src/Object/Post.php:329 +#: src/Object/Post.php:339 msgid "Ignored" msgstr "" @@ -6723,7 +6734,7 @@ msgstr "" msgid "Search your contacts" msgstr "" -#: src/Module/Contact.php:390 src/Module/Search/Index.php:192 +#: src/Module/Contact.php:390 src/Module/Search/Index.php:207 #, php-format msgid "Results for: %s" msgstr "" @@ -7088,7 +7099,7 @@ msgid "" msgstr "" #: src/Module/Contact/Profile.php:378 -#: src/Module/Settings/TwoFactor/Index.php:132 +#: src/Module/Settings/TwoFactor/Index.php:140 msgid "Actions" msgstr "" @@ -7147,6 +7158,7 @@ msgstr "" #: src/Module/Contact/Revoke.php:107 #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:53 src/Module/Register.php:130 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "Yes" msgstr "" @@ -7178,8 +7190,8 @@ msgstr "" msgid "Hide" msgstr "" -#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:137 -#: src/Module/Search/Index.php:179 +#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:152 +#: src/Module/Search/Index.php:194 msgid "No results." msgstr "" @@ -7239,7 +7251,7 @@ msgstr "" msgid "Posts that mention or involve you" msgstr "" -#: src/Module/Conversation/Network.php:287 src/Object/Post.php:341 +#: src/Module/Conversation/Network.php:287 src/Object/Post.php:351 msgid "Starred" msgstr "" @@ -8060,6 +8072,7 @@ msgstr "" #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:54 src/Module/Register.php:131 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "No" msgstr "" @@ -8293,19 +8306,19 @@ msgstr "" #: src/Module/Profile/Profile.php:326 src/Module/Profile/Profile.php:329 #: src/Module/Profile/Status.php:66 src/Module/Profile/Status.php:69 -#: src/Protocol/Feed.php:1017 src/Protocol/OStatus.php:1245 +#: src/Protocol/Feed.php:1018 src/Protocol/OStatus.php:1276 #, php-format msgid "%s's timeline" msgstr "" #: src/Module/Profile/Profile.php:327 src/Module/Profile/Status.php:67 -#: src/Protocol/Feed.php:1021 src/Protocol/OStatus.php:1249 +#: src/Protocol/Feed.php:1022 src/Protocol/OStatus.php:1281 #, php-format msgid "%s's posts" msgstr "" #: src/Module/Profile/Profile.php:328 src/Module/Profile/Status.php:68 -#: src/Protocol/Feed.php:1024 src/Protocol/OStatus.php:1252 +#: src/Protocol/Feed.php:1025 src/Protocol/OStatus.php:1285 #, php-format msgid "%s's comments" msgstr "" @@ -8505,15 +8518,15 @@ msgstr "" msgid "Your Webfinger address or profile URL:" msgstr "" -#: src/Module/Search/Index.php:54 +#: src/Module/Search/Index.php:69 msgid "Only logged in users are permitted to perform a search." msgstr "" -#: src/Module/Search/Index.php:74 +#: 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:190 +#: src/Module/Search/Index.php:205 #, php-format msgid "Items tagged with: %s" msgstr "" @@ -8576,7 +8589,11 @@ msgstr "" msgid "privacy policy" msgstr "" -#: src/Module/Security/Logout.php:87 +#: src/Module/Security/Logout.php:83 +#: 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 "" @@ -8602,7 +8619,7 @@ msgid "Remaining recovery codes: %d" msgstr "" #: src/Module/Security/TwoFactor/Recovery.php:77 -#: src/Module/Security/TwoFactor/Verify.php:76 +#: src/Module/Security/TwoFactor/Verify.php:77 #: src/Module/Settings/TwoFactor/Verify.php:94 msgid "Invalid code, please retry." msgstr "" @@ -8618,7 +8635,6 @@ msgid "" msgstr "" #: src/Module/Security/TwoFactor/Recovery.php:98 -#: src/Module/Security/TwoFactor/Verify.php:99 #, php-format msgid "" "Don’t have your phone? Enter a two-factor recovery code" @@ -8632,19 +8648,66 @@ msgstr "" msgid "Submit recovery code and complete login" msgstr "" -#: src/Module/Security/TwoFactor/Verify.php:96 +#: 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:89 +msgid "Couldn't save browser to Cookie." +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:119 +msgid "Trust this browser?" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:120 +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:121 +msgid "Not now" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:122 +msgid "Don't trust" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:123 +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 -#: src/Module/Settings/TwoFactor/Verify.php:154 -msgid "Please enter a code from your authentication app" +#, 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 -msgid "This is my two-factor authenticator app device" +#: src/Module/Settings/TwoFactor/Verify.php:154 +msgid "Please enter a code from your authentication app" msgstr "" #: src/Module/Security/TwoFactor/Verify.php:102 @@ -9651,99 +9714,95 @@ msgstr "" msgid "Generate" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:67 +#: src/Module/Settings/TwoFactor/Index.php:69 msgid "Two-factor authentication successfully disabled." msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:93 -msgid "Wrong Password" -msgstr "" - -#: src/Module/Settings/TwoFactor/Index.php:113 +#: src/Module/Settings/TwoFactor/Index.php:121 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:117 +#: src/Module/Settings/TwoFactor/Index.php:125 msgid "Authenticator app" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:126 msgid "Configured" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:126 msgid "Not Configured" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:119 +#: src/Module/Settings/TwoFactor/Index.php:127 msgid "

You haven't finished configuring your authenticator app.

" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:120 +#: src/Module/Settings/TwoFactor/Index.php:128 msgid "

Your authenticator app is correctly configured.

" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:122 +#: src/Module/Settings/TwoFactor/Index.php:130 msgid "Recovery codes" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:123 +#: src/Module/Settings/TwoFactor/Index.php:131 msgid "Remaining valid codes" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:125 +#: src/Module/Settings/TwoFactor/Index.php:133 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:127 +#: src/Module/Settings/TwoFactor/Index.php:135 msgid "App-specific passwords" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:128 +#: src/Module/Settings/TwoFactor/Index.php:136 msgid "Generated app-specific passwords" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:130 +#: src/Module/Settings/TwoFactor/Index.php:138 msgid "" "

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

" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:141 msgid "Current password:" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:141 msgid "" "You need to provide your current password to change two-factor " "authentication settings." msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:134 +#: src/Module/Settings/TwoFactor/Index.php:142 msgid "Enable two-factor authentication" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:135 +#: src/Module/Settings/TwoFactor/Index.php:143 msgid "Disable two-factor authentication" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:136 +#: src/Module/Settings/TwoFactor/Index.php:144 msgid "Show recovery codes" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:137 +#: src/Module/Settings/TwoFactor/Index.php:145 msgid "Manage app-specific passwords" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:138 +#: src/Module/Settings/TwoFactor/Index.php:146 msgid "Manage trusted browsers" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:139 +#: src/Module/Settings/TwoFactor/Index.php:147 msgid "Finish app configuration" msgstr "" @@ -9785,34 +9844,38 @@ msgstr "" msgid "Trusted browser successfully removed." msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:133 +#: src/Module/Settings/TwoFactor/Trusted.php:134 msgid "Two-factor Trusted Browsers" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:134 +#: src/Module/Settings/TwoFactor/Trusted.php:135 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:135 +#: src/Module/Settings/TwoFactor/Trusted.php:136 msgid "Device" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:136 +#: src/Module/Settings/TwoFactor/Trusted.php:137 msgid "OS" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:138 +#: src/Module/Settings/TwoFactor/Trusted.php:139 msgid "Trusted" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:139 -msgid "Last Use" +#: src/Module/Settings/TwoFactor/Trusted.php:140 +msgid "Created At" msgstr "" #: src/Module/Settings/TwoFactor/Trusted.php:141 +msgid "Last Use" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:143 msgid "Remove All" msgstr "" @@ -10285,205 +10348,205 @@ msgstr "" msgid "%1$s commented on your thread %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:221 -#: src/Navigation/Notifications/Repository/Notify.php:735 +#: src/Navigation/Notifications/Repository/Notify.php:222 +#: src/Navigation/Notifications/Repository/Notify.php:736 msgid "[Friendica:Notify]" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:285 +#: src/Navigation/Notifications/Repository/Notify.php:286 #, php-format msgid "%s New mail received at %s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:287 +#: src/Navigation/Notifications/Repository/Notify.php:288 #, php-format msgid "%1$s sent you a new private message at %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:288 +#: src/Navigation/Notifications/Repository/Notify.php:289 msgid "a private message" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:288 +#: src/Navigation/Notifications/Repository/Notify.php:289 #, php-format msgid "%1$s sent you %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:290 +#: src/Navigation/Notifications/Repository/Notify.php:291 #, php-format msgid "Please visit %s to view and/or reply to your private messages." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:320 +#: src/Navigation/Notifications/Repository/Notify.php:321 #, php-format msgid "%1$s commented on %2$s's %3$s %4$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:325 +#: src/Navigation/Notifications/Repository/Notify.php:326 #, php-format msgid "%1$s commented on your %2$s %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:329 +#: src/Navigation/Notifications/Repository/Notify.php:330 #, php-format msgid "%1$s commented on their %2$s %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:333 -#: src/Navigation/Notifications/Repository/Notify.php:769 +#: src/Navigation/Notifications/Repository/Notify.php:334 +#: src/Navigation/Notifications/Repository/Notify.php:770 #, php-format msgid "%1$s Comment to conversation #%2$d by %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:335 +#: src/Navigation/Notifications/Repository/Notify.php:336 #, php-format msgid "%s commented on an item/conversation you have been following." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:339 -#: src/Navigation/Notifications/Repository/Notify.php:354 -#: src/Navigation/Notifications/Repository/Notify.php:373 -#: src/Navigation/Notifications/Repository/Notify.php:784 +#: src/Navigation/Notifications/Repository/Notify.php:340 +#: src/Navigation/Notifications/Repository/Notify.php:355 +#: src/Navigation/Notifications/Repository/Notify.php:374 +#: src/Navigation/Notifications/Repository/Notify.php:785 #, php-format msgid "Please visit %s to view and/or reply to the conversation." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:346 +#: src/Navigation/Notifications/Repository/Notify.php:347 #, php-format msgid "%s %s posted to your profile wall" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:348 +#: src/Navigation/Notifications/Repository/Notify.php:349 #, php-format msgid "%1$s posted to your profile wall at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:349 +#: src/Navigation/Notifications/Repository/Notify.php:350 #, php-format msgid "%1$s posted to [url=%2$s]your wall[/url]" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:361 +#: src/Navigation/Notifications/Repository/Notify.php:362 #, php-format msgid "%1$s %2$s poked you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:363 +#: src/Navigation/Notifications/Repository/Notify.php:364 #, php-format msgid "%1$s poked you at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:364 +#: src/Navigation/Notifications/Repository/Notify.php:365 #, php-format msgid "%1$s [url=%2$s]poked you[/url]." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:381 +#: src/Navigation/Notifications/Repository/Notify.php:382 #, php-format msgid "%s Introduction received" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:383 +#: src/Navigation/Notifications/Repository/Notify.php:384 #, php-format msgid "You've received an introduction from '%1$s' at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:384 +#: src/Navigation/Notifications/Repository/Notify.php:385 #, php-format msgid "You've received [url=%1$s]an introduction[/url] from %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:389 -#: src/Navigation/Notifications/Repository/Notify.php:435 +#: src/Navigation/Notifications/Repository/Notify.php:390 +#: src/Navigation/Notifications/Repository/Notify.php:436 #, php-format msgid "You may visit their profile at %s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:391 +#: src/Navigation/Notifications/Repository/Notify.php:392 #, php-format msgid "Please visit %s to approve or reject the introduction." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:398 +#: src/Navigation/Notifications/Repository/Notify.php:399 #, php-format msgid "%s A new person is sharing with you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:400 #: src/Navigation/Notifications/Repository/Notify.php:401 +#: src/Navigation/Notifications/Repository/Notify.php:402 #, php-format msgid "%1$s is sharing with you at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:408 +#: src/Navigation/Notifications/Repository/Notify.php:409 #, php-format msgid "%s You have a new follower" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:410 #: src/Navigation/Notifications/Repository/Notify.php:411 +#: src/Navigation/Notifications/Repository/Notify.php:412 #, php-format msgid "You have a new follower at %2$s : %1$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:424 +#: src/Navigation/Notifications/Repository/Notify.php:425 #, php-format msgid "%s Friend suggestion received" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:426 +#: src/Navigation/Notifications/Repository/Notify.php:427 #, php-format msgid "You've received a friend suggestion from '%1$s' at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:427 +#: src/Navigation/Notifications/Repository/Notify.php:428 #, php-format msgid "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:433 +#: src/Navigation/Notifications/Repository/Notify.php:434 msgid "Name:" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:434 +#: src/Navigation/Notifications/Repository/Notify.php:435 msgid "Photo:" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:437 +#: src/Navigation/Notifications/Repository/Notify.php:438 #, php-format msgid "Please visit %s to approve or reject the suggestion." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:445 -#: src/Navigation/Notifications/Repository/Notify.php:460 +#: src/Navigation/Notifications/Repository/Notify.php:446 +#: src/Navigation/Notifications/Repository/Notify.php:461 #, php-format msgid "%s Connection accepted" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:447 -#: src/Navigation/Notifications/Repository/Notify.php:462 -#, php-format -msgid "'%1$s' has accepted your connection request at %2$s" -msgstr "" - #: src/Navigation/Notifications/Repository/Notify.php:448 #: src/Navigation/Notifications/Repository/Notify.php:463 #, php-format +msgid "'%1$s' has accepted your connection request at %2$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:449 +#: src/Navigation/Notifications/Repository/Notify.php:464 +#, php-format msgid "%2$s has accepted your [url=%1$s]connection request[/url]." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:453 +#: src/Navigation/Notifications/Repository/Notify.php:454 msgid "" "You are now mutual friends and may exchange status updates, photos, and " "email without restriction." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:455 +#: src/Navigation/Notifications/Repository/Notify.php:456 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:468 +#: src/Navigation/Notifications/Repository/Notify.php:469 #, php-format msgid "" "'%1$s' has chosen to accept you a fan, which restricts some forms of " @@ -10492,33 +10555,33 @@ msgid "" "automatically." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:470 +#: src/Navigation/Notifications/Repository/Notify.php:471 #, php-format msgid "" "'%1$s' may choose to extend this into a two-way or more permissive " "relationship in the future." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:472 +#: src/Navigation/Notifications/Repository/Notify.php:473 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:482 +#: src/Navigation/Notifications/Repository/Notify.php:483 msgid "registration request" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:484 -#, php-format -msgid "You've received a registration request from '%1$s' at %2$s" -msgstr "" - #: src/Navigation/Notifications/Repository/Notify.php:485 #, php-format +msgid "You've received a registration request from '%1$s' at %2$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:486 +#, php-format msgid "You've received a [url=%1$s]registration request[/url] from %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:490 +#: src/Navigation/Notifications/Repository/Notify.php:491 #, php-format msgid "" "Full Name:\t%s\n" @@ -10526,17 +10589,17 @@ msgid "" "Login Name:\t%s (%s)" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:496 +#: src/Navigation/Notifications/Repository/Notify.php:497 #, php-format msgid "Please visit %s to approve or reject the request." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:763 +#: src/Navigation/Notifications/Repository/Notify.php:764 #, php-format msgid "%s %s tagged you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:766 +#: src/Navigation/Notifications/Repository/Notify.php:767 #, php-format msgid "%s %s shared a new post" msgstr "" @@ -10563,244 +10626,244 @@ msgstr "" msgid "%s posted an update." msgstr "" -#: src/Object/Post.php:134 +#: src/Object/Post.php:136 msgid "Private Message" msgstr "" -#: src/Object/Post.php:137 +#: src/Object/Post.php:140 msgid "Public Message" msgstr "" -#: src/Object/Post.php:140 +#: src/Object/Post.php:144 msgid "Unlisted Message" msgstr "" -#: src/Object/Post.php:170 +#: src/Object/Post.php:179 msgid "This entry was edited" msgstr "" -#: src/Object/Post.php:198 +#: src/Object/Post.php:207 msgid "Connector Message" msgstr "" -#: src/Object/Post.php:213 src/Object/Post.php:215 +#: src/Object/Post.php:222 src/Object/Post.php:224 msgid "Edit" msgstr "" -#: src/Object/Post.php:239 +#: src/Object/Post.php:248 msgid "Delete globally" msgstr "" -#: src/Object/Post.php:239 +#: src/Object/Post.php:248 msgid "Remove locally" msgstr "" -#: src/Object/Post.php:255 +#: src/Object/Post.php:264 #, php-format msgid "Block %s" msgstr "" -#: src/Object/Post.php:260 +#: src/Object/Post.php:269 msgid "Save to folder" msgstr "" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I will attend" msgstr "" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I will not attend" msgstr "" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I might attend" msgstr "" -#: src/Object/Post.php:324 +#: src/Object/Post.php:334 msgid "Ignore thread" msgstr "" -#: src/Object/Post.php:325 +#: src/Object/Post.php:335 msgid "Unignore thread" msgstr "" -#: src/Object/Post.php:326 +#: src/Object/Post.php:336 msgid "Toggle ignore status" msgstr "" -#: src/Object/Post.php:336 +#: src/Object/Post.php:346 msgid "Add star" msgstr "" -#: src/Object/Post.php:337 +#: src/Object/Post.php:347 msgid "Remove star" msgstr "" -#: src/Object/Post.php:338 +#: src/Object/Post.php:348 msgid "Toggle star status" msgstr "" -#: src/Object/Post.php:349 +#: src/Object/Post.php:359 msgid "Pin" msgstr "" -#: src/Object/Post.php:350 +#: src/Object/Post.php:360 msgid "Unpin" msgstr "" -#: src/Object/Post.php:351 +#: src/Object/Post.php:361 msgid "Toggle pin status" msgstr "" -#: src/Object/Post.php:354 +#: src/Object/Post.php:364 msgid "Pinned" msgstr "" -#: src/Object/Post.php:359 +#: src/Object/Post.php:369 msgid "Add tag" msgstr "" -#: src/Object/Post.php:372 +#: src/Object/Post.php:382 msgid "Quote share this" msgstr "" -#: src/Object/Post.php:372 +#: src/Object/Post.php:382 msgid "Quote Share" msgstr "" -#: src/Object/Post.php:375 +#: src/Object/Post.php:385 msgid "Reshare this" msgstr "" -#: src/Object/Post.php:375 +#: src/Object/Post.php:385 msgid "Reshare" msgstr "" -#: src/Object/Post.php:376 +#: src/Object/Post.php:386 msgid "Cancel your Reshare" msgstr "" -#: src/Object/Post.php:376 +#: src/Object/Post.php:386 msgid "Unshare" msgstr "" -#: src/Object/Post.php:423 +#: src/Object/Post.php:433 #, php-format msgid "%s (Received %s)" msgstr "" -#: src/Object/Post.php:428 +#: src/Object/Post.php:438 msgid "Comment this item on your system" msgstr "" -#: src/Object/Post.php:428 +#: src/Object/Post.php:438 msgid "Remote comment" msgstr "" -#: src/Object/Post.php:449 +#: src/Object/Post.php:459 msgid "Share via ..." msgstr "" -#: src/Object/Post.php:449 +#: src/Object/Post.php:459 msgid "Share via external services" msgstr "" -#: src/Object/Post.php:478 +#: src/Object/Post.php:488 msgid "to" msgstr "" -#: src/Object/Post.php:479 +#: src/Object/Post.php:489 msgid "via" msgstr "" -#: src/Object/Post.php:480 +#: src/Object/Post.php:490 msgid "Wall-to-Wall" msgstr "" -#: src/Object/Post.php:481 +#: src/Object/Post.php:491 msgid "via Wall-To-Wall:" msgstr "" -#: src/Object/Post.php:523 +#: src/Object/Post.php:533 #, php-format msgid "Reply to %s" msgstr "" -#: src/Object/Post.php:526 +#: src/Object/Post.php:536 msgid "More" msgstr "" -#: src/Object/Post.php:544 +#: src/Object/Post.php:554 msgid "Notifier task is pending" msgstr "" -#: src/Object/Post.php:545 +#: src/Object/Post.php:555 msgid "Delivery to remote servers is pending" msgstr "" -#: src/Object/Post.php:546 +#: src/Object/Post.php:556 msgid "Delivery to remote servers is underway" msgstr "" -#: src/Object/Post.php:547 +#: src/Object/Post.php:557 msgid "Delivery to remote servers is mostly done" msgstr "" -#: src/Object/Post.php:548 +#: src/Object/Post.php:558 msgid "Delivery to remote servers is done" msgstr "" -#: src/Object/Post.php:568 +#: src/Object/Post.php:578 #, php-format msgid "%d comment" msgid_plural "%d comments" msgstr[0] "" msgstr[1] "" -#: src/Object/Post.php:569 +#: src/Object/Post.php:579 msgid "Show more" msgstr "" -#: src/Object/Post.php:570 +#: src/Object/Post.php:580 msgid "Show fewer" msgstr "" -#: src/Protocol/OStatus.php:1648 +#: src/Protocol/OStatus.php:1705 #, php-format msgid "%s is now following %s." msgstr "" -#: src/Protocol/OStatus.php:1649 +#: src/Protocol/OStatus.php:1706 msgid "following" msgstr "" -#: src/Protocol/OStatus.php:1652 +#: src/Protocol/OStatus.php:1709 #, php-format msgid "%s stopped following %s." msgstr "" -#: src/Protocol/OStatus.php:1653 +#: src/Protocol/OStatus.php:1710 msgid "stopped following" msgstr "" -#: src/Render/FriendicaSmartyEngine.php:52 +#: src/Render/FriendicaSmartyEngine.php:65 msgid "The folder view/smarty3/ must be writable by webserver." msgstr "" -#: src/Security/Authentication.php:221 +#: src/Security/Authentication.php:226 msgid "Login failed." msgstr "" -#: src/Security/Authentication.php:262 +#: src/Security/Authentication.php:267 msgid "Login failed. Please check your credentials." msgstr "" -#: src/Security/Authentication.php:360 +#: src/Security/Authentication.php:369 #, php-format msgid "Welcome %s" msgstr "" -#: src/Security/Authentication.php:361 +#: src/Security/Authentication.php:370 msgid "Please upload a profile photo." msgstr "" @@ -10898,15 +10961,15 @@ msgstr "" msgid "%1$d %2$s ago" msgstr "" -#: src/Worker/Delivery.php:524 +#: src/Worker/Delivery.php:525 msgid "(no subject)" msgstr "" -#: src/Worker/PushSubscription.php:103 +#: src/Worker/PushSubscription.php:112 msgid "Notification from Friendica" msgstr "" -#: src/Worker/PushSubscription.php:104 +#: src/Worker/PushSubscription.php:113 msgid "Empty Post" msgstr "" @@ -11052,39 +11115,39 @@ msgstr "" msgid "Leave background image and color empty for theme defaults" msgstr "" -#: view/theme/frio/php/Image.php:40 +#: view/theme/frio/php/Image.php:39 msgid "Top Banner" msgstr "" -#: view/theme/frio/php/Image.php:40 +#: 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:41 +#: view/theme/frio/php/Image.php:40 msgid "Full screen" msgstr "" -#: view/theme/frio/php/Image.php:41 +#: 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:42 +#: view/theme/frio/php/Image.php:41 msgid "Single row mosaic" msgstr "" -#: view/theme/frio/php/Image.php:42 +#: 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:43 +#: view/theme/frio/php/Image.php:42 msgid "Mosaic" msgstr "" -#: view/theme/frio/php/Image.php:43 +#: view/theme/frio/php/Image.php:42 msgid "Repeat image to fill the screen." msgstr "" diff --git a/view/lang/de/messages.po b/view/lang/de/messages.po index 45f0692337..159373875f 100644 --- a/view/lang/de/messages.po +++ b/view/lang/de/messages.po @@ -12,7 +12,7 @@ # David Rabel , 2016 # Erkan Yilmaz , 2011 # Fabian Dost , 2012 -# foss , 2014,2016-2017,2020 +# foss , 2014,2016-2017,2020,2022 # Frank Dieckmann , 2015 # Fabian Dost , 2012 # greeneyedred , 2012 @@ -49,9 +49,9 @@ msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-06-06 07:33+0000\n" +"POT-Creation-Date: 2022-06-25 22:37+0200\n" "PO-Revision-Date: 2011-05-05 10:19+0000\n" -"Last-Translator: Tobias Diekershoff , 2016-2022\n" +"Last-Translator: foss , 2014,2016-2017,2020,2022\n" "Language-Team: German (http://www.transifex.com/Friendica/friendica/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -69,7 +69,7 @@ msgid "Access denied." msgstr "Zugriff verweigert." #: mod/cal.php:63 mod/cal.php:80 mod/photos.php:69 mod/photos.php:140 -#: mod/photos.php:798 src/Model/Profile.php:231 src/Module/Feed.php:72 +#: mod/photos.php:798 src/Model/Profile.php:232 src/Module/Feed.php:72 #: src/Module/HCard.php:52 src/Module/Profile/Common.php:41 #: src/Module/Profile/Common.php:52 src/Module/Profile/Contacts.php:40 #: src/Module/Profile/Contacts.php:50 src/Module/Profile/Media.php:38 @@ -78,7 +78,7 @@ msgstr "Zugriff verweigert." msgid "User not found." msgstr "Benutzer nicht gefunden." -#: mod/cal.php:122 mod/display.php:247 src/Module/Profile/Profile.php:94 +#: mod/cal.php:122 mod/display.php:262 src/Module/Profile/Profile.php:94 #: src/Module/Profile/Profile.php:109 src/Module/Profile/Status.php:110 #: src/Module/Update/Profile.php:56 msgid "Access to this profile has been restricted." @@ -103,21 +103,21 @@ msgstr "Vorherige" msgid "Next" msgstr "Nächste" -#: mod/cal.php:249 mod/events.php:383 src/Model/Event.php:457 +#: mod/cal.php:249 mod/events.php:383 src/Model/Event.php:456 msgid "today" msgstr "Heute" -#: mod/cal.php:250 mod/events.php:384 src/Model/Event.php:458 +#: mod/cal.php:250 mod/events.php:384 src/Model/Event.php:457 #: src/Util/Temporal.php:334 msgid "month" msgstr "Monat" -#: mod/cal.php:251 mod/events.php:385 src/Model/Event.php:459 +#: mod/cal.php:251 mod/events.php:385 src/Model/Event.php:458 #: src/Util/Temporal.php:335 msgid "week" msgstr "Woche" -#: mod/cal.php:252 mod/events.php:386 src/Model/Event.php:460 +#: mod/cal.php:252 mod/events.php:386 src/Model/Event.php:459 #: src/Util/Temporal.php:336 msgid "day" msgstr "Tag" @@ -145,17 +145,17 @@ msgstr "Keine exportierbaren Daten gefunden" msgid "calendar" msgstr "Kalender" -#: mod/display.php:142 mod/photos.php:802 +#: mod/display.php:143 mod/photos.php:802 #: src/Module/Conversation/Community.php:175 src/Module/Directory.php:49 -#: src/Module/Search/Index.php:50 +#: src/Module/Search/Index.php:65 msgid "Public access denied." msgstr "Öffentlicher Zugriff verweigert." -#: mod/display.php:198 mod/display.php:272 +#: mod/display.php:213 mod/display.php:287 msgid "The requested item doesn't exist or has been deleted." msgstr "Der angeforderte Beitrag existiert nicht oder wurde gelöscht." -#: mod/display.php:352 +#: mod/display.php:367 msgid "The feed for this item is unavailable." msgstr "Der Feed für diesen Beitrag ist nicht verfügbar." @@ -200,13 +200,13 @@ msgstr "Beitrag nicht gefunden" msgid "Edit post" msgstr "Beitrag bearbeiten" -#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:875 +#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:882 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:73 msgid "Save" msgstr "Speichern" #: mod/editpost.php:92 mod/photos.php:1338 src/Content/Conversation.php:338 -#: src/Module/Contact/Poke.php:176 src/Object/Post.php:989 +#: src/Module/Contact/Poke.php:176 src/Object/Post.php:993 msgid "Loading..." msgstr "lädt..." @@ -271,8 +271,8 @@ msgstr "Ort löschen" #: mod/editpost.php:107 mod/message.php:200 mod/message.php:358 #: mod/photos.php:1489 mod/wallmessage.php:142 -#: src/Content/Conversation.php:368 src/Content/Conversation.php:712 -#: src/Module/Item/Compose.php:177 src/Object/Post.php:528 +#: src/Content/Conversation.php:368 src/Content/Conversation.php:713 +#: src/Module/Item/Compose.php:177 src/Object/Post.php:538 msgid "Please wait" msgstr "Bitte warten" @@ -304,7 +304,7 @@ msgstr "Z.B.: bob@example.com, mary@example.com" #: mod/editpost.php:128 mod/events.php:513 mod/photos.php:1337 #: mod/photos.php:1393 mod/photos.php:1467 src/Content/Conversation.php:383 -#: src/Module/Item/Compose.php:172 src/Object/Post.php:999 +#: src/Module/Item/Compose.php:172 src/Object/Post.php:1003 msgid "Preview" msgstr "Vorschau" @@ -312,52 +312,53 @@ msgstr "Vorschau" #: mod/follow.php:144 mod/photos.php:1004 mod/photos.php:1105 mod/tagrm.php:35 #: mod/tagrm.php:127 mod/unfollow.php:97 src/Content/Conversation.php:386 #: src/Module/Contact/Revoke.php:108 src/Module/RemoteFollow.php:127 +#: src/Module/Security/TwoFactor/Signout.php:125 msgid "Cancel" msgstr "Abbrechen" #: mod/editpost.php:134 src/Content/Conversation.php:343 -#: src/Module/Item/Compose.php:163 src/Object/Post.php:990 +#: src/Module/Item/Compose.php:163 src/Object/Post.php:994 msgid "Bold" msgstr "Fett" #: mod/editpost.php:135 src/Content/Conversation.php:344 -#: src/Module/Item/Compose.php:164 src/Object/Post.php:991 +#: src/Module/Item/Compose.php:164 src/Object/Post.php:995 msgid "Italic" msgstr "Kursiv" #: mod/editpost.php:136 src/Content/Conversation.php:345 -#: src/Module/Item/Compose.php:165 src/Object/Post.php:992 +#: src/Module/Item/Compose.php:165 src/Object/Post.php:996 msgid "Underline" msgstr "Unterstrichen" #: mod/editpost.php:137 src/Content/Conversation.php:346 -#: src/Module/Item/Compose.php:166 src/Object/Post.php:993 +#: src/Module/Item/Compose.php:166 src/Object/Post.php:997 msgid "Quote" msgstr "Zitat" #: mod/editpost.php:138 src/Content/Conversation.php:347 -#: src/Module/Item/Compose.php:167 src/Object/Post.php:994 +#: src/Module/Item/Compose.php:167 src/Object/Post.php:998 msgid "Code" msgstr "Code" #: mod/editpost.php:139 src/Content/Conversation.php:349 -#: src/Module/Item/Compose.php:169 src/Object/Post.php:996 +#: src/Module/Item/Compose.php:169 src/Object/Post.php:1000 msgid "Link" msgstr "Link" #: mod/editpost.php:140 src/Content/Conversation.php:350 -#: src/Module/Item/Compose.php:170 src/Object/Post.php:997 +#: src/Module/Item/Compose.php:170 src/Object/Post.php:1001 msgid "Link or Media" msgstr "Link oder Mediendatei" #: mod/editpost.php:143 src/Content/Conversation.php:393 -#: src/Content/Widget/VCard.php:113 src/Model/Profile.php:462 +#: src/Content/Widget/VCard.php:113 src/Model/Profile.php:463 #: src/Module/Admin/Logs/View.php:93 msgid "Message" msgstr "Nachricht" #: mod/editpost.php:144 src/Content/Conversation.php:394 -#: src/Module/Settings/TwoFactor/Trusted.php:137 +#: src/Module/Settings/TwoFactor/Trusted.php:138 msgid "Browser" msgstr "Browser" @@ -407,8 +408,8 @@ msgstr "Veranstaltungsbeginn:" #: src/Module/Install.php:286 src/Module/Install.php:291 #: src/Module/Install.php:305 src/Module/Install.php:320 #: src/Module/Install.php:347 src/Module/Register.php:148 -#: src/Module/Security/TwoFactor/Verify.php:100 -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Security/TwoFactor/Verify.php:101 +#: src/Module/Settings/TwoFactor/Index.php:136 #: src/Module/Settings/TwoFactor/Verify.php:154 msgid "Required" msgstr "Benötigt" @@ -427,8 +428,8 @@ msgid "Description:" msgstr "Beschreibung" #: mod/events.php:504 src/Content/Widget/VCard.php:104 src/Model/Event.php:80 -#: src/Model/Event.php:107 src/Model/Event.php:466 src/Model/Event.php:915 -#: src/Model/Profile.php:370 src/Module/Contact/Profile.php:369 +#: src/Model/Event.php:107 src/Model/Event.php:465 src/Model/Event.php:915 +#: src/Model/Profile.php:371 src/Module/Contact/Profile.php:369 #: src/Module/Directory.php:148 src/Module/Notifications/Introductions.php:185 #: src/Module/Profile/Profile.php:194 msgid "Location:" @@ -454,7 +455,7 @@ msgstr "Veranstaltung teilen" #: src/Module/Install.php:252 src/Module/Install.php:294 #: src/Module/Install.php:331 src/Module/Invite.php:178 #: src/Module/Item/Compose.php:162 src/Module/Profile/Profile.php:247 -#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:988 +#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:992 #: view/theme/duepuntozero/config.php:69 view/theme/frio/config.php:160 #: view/theme/quattro/config.php:71 view/theme/vier/config.php:119 msgid "Submit" @@ -507,8 +508,8 @@ msgstr "Diaspora-Unterstützung ist nicht aktiviert. Der Kontakt kann nicht zuge msgid "OStatus support is disabled. Contact can't be added." msgstr "OStatus-Unterstützung ist nicht aktiviert. Der Kontakt kann nicht zugefügt werden." -#: mod/follow.php:138 src/Content/Item.php:443 src/Content/Widget.php:78 -#: src/Model/Contact.php:1102 src/Model/Contact.php:1114 +#: mod/follow.php:138 src/Content/Item.php:443 src/Content/Widget.php:80 +#: src/Model/Contact.php:1103 src/Model/Contact.php:1115 #: view/theme/vier/theme.php:172 msgid "Connect/Follow" msgstr "Verbinden/Folgen" @@ -1106,39 +1107,39 @@ msgstr "Drehen EUS (links)" #: mod/photos.php:1333 mod/photos.php:1389 mod/photos.php:1463 #: src/Module/Contact.php:544 src/Module/Item/Compose.php:160 -#: src/Object/Post.php:985 +#: src/Object/Post.php:989 msgid "This is you" msgstr "Das bist du" #: mod/photos.php:1335 mod/photos.php:1391 mod/photos.php:1465 -#: src/Object/Post.php:522 src/Object/Post.php:987 +#: src/Object/Post.php:532 src/Object/Post.php:991 msgid "Comment" msgstr "Kommentar" -#: mod/photos.php:1424 src/Content/Conversation.php:628 -#: src/Object/Post.php:247 +#: mod/photos.php:1424 src/Content/Conversation.php:629 +#: src/Object/Post.php:256 msgid "Select" msgstr "Auswählen" -#: mod/photos.php:1425 mod/settings.php:350 src/Content/Conversation.php:629 +#: mod/photos.php:1425 mod/settings.php:350 src/Content/Conversation.php:630 #: src/Module/Admin/Users/Active.php:139 #: src/Module/Admin/Users/Blocked.php:140 src/Module/Admin/Users/Index.php:153 msgid "Delete" msgstr "Löschen" -#: mod/photos.php:1486 src/Object/Post.php:369 +#: mod/photos.php:1486 src/Object/Post.php:379 msgid "Like" msgstr "Mag ich" -#: mod/photos.php:1487 src/Object/Post.php:369 +#: mod/photos.php:1487 src/Object/Post.php:379 msgid "I like this (toggle)" msgstr "Ich mag das (toggle)" -#: mod/photos.php:1488 src/Object/Post.php:370 +#: mod/photos.php:1488 src/Object/Post.php:380 msgid "Dislike" msgstr "Mag ich nicht" -#: mod/photos.php:1490 src/Object/Post.php:370 +#: mod/photos.php:1490 src/Object/Post.php:380 msgid "I don't like this (toggle)" msgstr "Ich mag das nicht (toggle)" @@ -1167,7 +1168,7 @@ msgstr "Ungültige Anfrage." msgid "Contact not found." msgstr "Kontakt nicht gefunden." -#: mod/removeme.php:65 src/Navigation/Notifications/Repository/Notify.php:482 +#: mod/removeme.php:65 src/Navigation/Notifications/Repository/Notify.php:483 msgid "[Friendica System Notify]" msgstr "[Friendica-Systembenachrichtigung]" @@ -1205,7 +1206,7 @@ msgid "Resubscribing to OStatus contacts" msgstr "Erneuern der OStatus-Abonements" #: mod/repair_ostatus.php:46 src/Module/Debug/ActivityPubConversion.php:134 -#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:97 +#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:98 msgid "Error" msgid_plural "Errors" msgstr[0] "Fehler" @@ -1445,11 +1446,11 @@ msgid "" "hours." msgstr "Keine Vorschläge verfügbar. Falls der Server frisch aufgesetzt wurde, versuche es bitte in 24 Stunden noch einmal." -#: mod/suggest.php:55 src/Content/Widget.php:81 view/theme/vier/theme.php:175 +#: mod/suggest.php:55 src/Content/Widget.php:83 view/theme/vier/theme.php:175 msgid "Friend Suggestions" msgstr "Kontaktvorschläge" -#: mod/tagger.php:78 src/Content/Item.php:342 src/Model/Item.php:2699 +#: mod/tagger.php:78 src/Content/Item.php:342 src/Model/Item.php:2728 msgid "photo" msgstr "Foto" @@ -1471,7 +1472,7 @@ msgid "Select a tag to remove: " msgstr "Wähle ein Tag zum Entfernen aus: " #: mod/tagrm.php:126 src/Module/Settings/Delegation.php:179 -#: src/Module/Settings/TwoFactor/Trusted.php:140 +#: src/Module/Settings/TwoFactor/Trusted.php:142 msgid "Remove" msgstr "Entfernen" @@ -1563,7 +1564,7 @@ msgstr "Die Datei ist größer als das erlaubte Limit von %s" msgid "File upload failed." msgstr "Hochladen der Datei fehlgeschlagen." -#: mod/wall_upload.php:218 src/Model/Photo.php:1061 +#: mod/wall_upload.php:218 src/Model/Photo.php:1085 msgid "Wall Photos" msgstr "Pinnwand-Bilder" @@ -1587,11 +1588,11 @@ msgid "" "your site allow private mail from unknown senders." msgstr "Wenn du möchtest, dass %s dir antworten kann, überprüfe deine Privatsphären-Einstellungen und erlaube private Nachrichten von unbekannten Absendern." -#: src/App.php:463 +#: 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:584 +#: src/App.php:594 msgid "Apologies but the website is unavailable at the moment." msgstr "Entschuldigung, aber die Webseite ist derzeit nicht erreichbar." @@ -1609,58 +1610,58 @@ msgstr "Soll dieser Autor geblockt werden? Sie werden nicht in der Lage sein, di msgid "toggle mobile" msgstr "mobile Ansicht umschalten" -#: src/App/Router.php:275 +#: src/App/Router.php:282 #, php-format msgid "Method not allowed for this module. Allowed method(s): %s" msgstr "Diese Methode ist in diesem Modul nicht erlaubt. Erlaubte Methoden sind: %s" -#: src/App/Router.php:277 src/Module/HTTPException/PageNotFound.php:34 +#: src/App/Router.php:284 src/Module/HTTPException/PageNotFound.php:49 msgid "Page not found." msgstr "Seite nicht gefunden." -#: src/App/Router.php:305 +#: src/App/Router.php:312 msgid "You must be logged in to use addons. " msgstr "Du musst angemeldet sein, um Addons benutzen zu können." -#: src/BaseModule.php:377 +#: src/BaseModule.php:392 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 "Das Sicherheitsmerkmal war nicht korrekt. Das passiert meistens, wenn das Formular vor dem Absenden zu lange geöffnet war (länger als 3 Stunden)." -#: src/BaseModule.php:404 +#: src/BaseModule.php:419 msgid "All contacts" msgstr "Alle Kontakte" -#: src/BaseModule.php:409 src/Content/Widget.php:233 src/Core/ACL.php:194 +#: src/BaseModule.php:424 src/Content/Widget.php:235 src/Core/ACL.php:194 #: src/Module/Contact.php:367 src/Module/PermissionTooltip.php:122 #: src/Module/PermissionTooltip.php:144 msgid "Followers" msgstr "Folgende" -#: src/BaseModule.php:414 src/Content/Widget.php:234 +#: src/BaseModule.php:429 src/Content/Widget.php:236 #: src/Module/Contact.php:368 msgid "Following" msgstr "Gefolgte" -#: src/BaseModule.php:419 src/Content/Widget.php:235 +#: src/BaseModule.php:434 src/Content/Widget.php:237 #: src/Module/Contact.php:369 msgid "Mutual friends" msgstr "Beidseitige Freundschaft" -#: src/BaseModule.php:427 +#: src/BaseModule.php:442 msgid "Common" msgstr "Gemeinsam" -#: src/Console/Addon.php:177 src/Console/Addon.php:202 +#: src/Console/Addon.php:175 src/Console/Addon.php:199 msgid "Addon not found" msgstr "Addon nicht gefunden" -#: src/Console/Addon.php:181 +#: src/Console/Addon.php:179 msgid "Addon already enabled" msgstr "Addon bereits aktiviert" -#: src/Console/Addon.php:206 +#: src/Console/Addon.php:203 msgid "Addon already disabled" msgstr "Addon bereits deaktiviert" @@ -1883,78 +1884,78 @@ msgstr "Wöchentlich" msgid "Monthly" msgstr "Monatlich" -#: src/Content/ContactSelector.php:123 +#: src/Content/ContactSelector.php:126 msgid "DFRN" msgstr "DFRN" -#: src/Content/ContactSelector.php:124 +#: src/Content/ContactSelector.php:127 msgid "OStatus" msgstr "OStatus" -#: src/Content/ContactSelector.php:125 +#: src/Content/ContactSelector.php:128 msgid "RSS/Atom" msgstr "RSS/Atom" -#: src/Content/ContactSelector.php:126 src/Module/Admin/Users/Active.php:129 +#: src/Content/ContactSelector.php:129 src/Module/Admin/Users/Active.php:129 #: src/Module/Admin/Users/Blocked.php:130 src/Module/Admin/Users/Create.php:73 #: src/Module/Admin/Users/Deleted.php:88 src/Module/Admin/Users/Index.php:142 #: src/Module/Admin/Users/Index.php:162 src/Module/Admin/Users/Pending.php:104 msgid "Email" msgstr "E-Mail" -#: src/Content/ContactSelector.php:127 src/Module/Debug/Babel.php:307 +#: src/Content/ContactSelector.php:130 src/Module/Debug/Babel.php:307 msgid "Diaspora" msgstr "Diaspora" -#: src/Content/ContactSelector.php:128 +#: src/Content/ContactSelector.php:131 msgid "Zot!" msgstr "Zott" -#: src/Content/ContactSelector.php:129 +#: src/Content/ContactSelector.php:132 msgid "LinkedIn" msgstr "LinkedIn" -#: src/Content/ContactSelector.php:130 +#: src/Content/ContactSelector.php:133 msgid "XMPP/IM" msgstr "XMPP/Chat" -#: src/Content/ContactSelector.php:131 +#: src/Content/ContactSelector.php:134 msgid "MySpace" msgstr "MySpace" -#: src/Content/ContactSelector.php:132 +#: src/Content/ContactSelector.php:135 msgid "Google+" msgstr "Google+" -#: src/Content/ContactSelector.php:133 +#: src/Content/ContactSelector.php:136 msgid "pump.io" msgstr "pump.io" -#: src/Content/ContactSelector.php:134 +#: src/Content/ContactSelector.php:137 msgid "Twitter" msgstr "Twitter" -#: src/Content/ContactSelector.php:135 +#: src/Content/ContactSelector.php:138 msgid "Discourse" msgstr "Discourse" -#: src/Content/ContactSelector.php:136 +#: src/Content/ContactSelector.php:139 msgid "Diaspora Connector" msgstr "Diaspora Connector" -#: src/Content/ContactSelector.php:137 +#: src/Content/ContactSelector.php:140 msgid "GNU Social Connector" msgstr "GNU Social Connector" -#: src/Content/ContactSelector.php:138 +#: src/Content/ContactSelector.php:141 msgid "ActivityPub" msgstr "ActivityPub" -#: src/Content/ContactSelector.php:139 +#: src/Content/ContactSelector.php:142 msgid "pnut" msgstr "pnut" -#: src/Content/ContactSelector.php:175 +#: src/Content/ContactSelector.php:178 #, php-format msgid "%s (via %s)" msgstr "%s (via %s)" @@ -1985,7 +1986,7 @@ msgid "%s attends maybe." msgstr "%s nimmt eventuell teil." #: src/Content/Conversation.php:222 src/Content/Conversation.php:260 -#: src/Content/Conversation.php:872 +#: src/Content/Conversation.php:873 #, php-format msgid "%s reshared this." msgstr "%s hat dies geteilt" @@ -2059,7 +2060,7 @@ msgid "Visible to everybody" msgstr "Für jedermann sichtbar" #: src/Content/Conversation.php:308 src/Module/Item/Compose.php:171 -#: src/Object/Post.php:998 +#: src/Object/Post.php:1002 msgid "Please enter a image/video/audio/webpage URL:" msgstr "Bitte gib eine Bild/Video/Audio/Webseiten-URL ein:" @@ -2092,7 +2093,7 @@ msgid "Share" msgstr "Teilen" #: src/Content/Conversation.php:348 src/Module/Item/Compose.php:168 -#: src/Object/Post.php:995 +#: src/Object/Post.php:999 msgid "Image" msgstr "Bild" @@ -2104,92 +2105,92 @@ msgstr "Video" msgid "Scheduled at" msgstr "Geplant für" -#: src/Content/Conversation.php:656 src/Object/Post.php:235 +#: src/Content/Conversation.php:657 src/Object/Post.php:244 msgid "Pinned item" msgstr "Angehefteter Beitrag" -#: src/Content/Conversation.php:672 src/Object/Post.php:476 -#: src/Object/Post.php:477 +#: src/Content/Conversation.php:673 src/Object/Post.php:486 +#: src/Object/Post.php:487 #, php-format msgid "View %s's profile @ %s" msgstr "Das Profil von %s auf %s betrachten." -#: src/Content/Conversation.php:685 src/Object/Post.php:464 +#: src/Content/Conversation.php:686 src/Object/Post.php:474 msgid "Categories:" msgstr "Kategorien:" -#: src/Content/Conversation.php:686 src/Object/Post.php:465 +#: src/Content/Conversation.php:687 src/Object/Post.php:475 msgid "Filed under:" msgstr "Abgelegt unter:" -#: src/Content/Conversation.php:694 src/Object/Post.php:490 +#: src/Content/Conversation.php:695 src/Object/Post.php:500 #, php-format msgid "%s from %s" msgstr "%s von %s" -#: src/Content/Conversation.php:710 +#: src/Content/Conversation.php:711 msgid "View in context" msgstr "Im Zusammenhang betrachten" -#: src/Content/Conversation.php:775 +#: src/Content/Conversation.php:776 msgid "remove" msgstr "löschen" -#: src/Content/Conversation.php:779 +#: src/Content/Conversation.php:780 msgid "Delete Selected Items" msgstr "Lösche die markierten Beiträge" -#: src/Content/Conversation.php:844 src/Content/Conversation.php:847 -#: src/Content/Conversation.php:850 src/Content/Conversation.php:853 +#: src/Content/Conversation.php:845 src/Content/Conversation.php:848 +#: src/Content/Conversation.php:851 src/Content/Conversation.php:854 #, php-format msgid "You had been addressed (%s)." msgstr "Du wurdest angeschrieben (%s)." -#: src/Content/Conversation.php:856 +#: src/Content/Conversation.php:857 #, php-format msgid "You are following %s." msgstr "Du folgst %s." -#: src/Content/Conversation.php:859 +#: src/Content/Conversation.php:860 msgid "Tagged" msgstr "Verschlagwortet" -#: src/Content/Conversation.php:874 +#: src/Content/Conversation.php:875 msgid "Reshared" msgstr "Geteilt" -#: src/Content/Conversation.php:874 +#: src/Content/Conversation.php:875 #, php-format msgid "Reshared by %s <%s>" msgstr "Geteilt von %s <%s>" -#: src/Content/Conversation.php:877 +#: src/Content/Conversation.php:878 #, php-format msgid "%s is participating in this thread." msgstr "%s ist an der Unterhaltung beteiligt." -#: src/Content/Conversation.php:880 +#: src/Content/Conversation.php:881 msgid "Stored" msgstr "Gespeichert" -#: src/Content/Conversation.php:883 +#: src/Content/Conversation.php:884 msgid "Global" msgstr "Global" -#: src/Content/Conversation.php:886 +#: src/Content/Conversation.php:887 msgid "Relayed" msgstr "Übermittelt" -#: src/Content/Conversation.php:886 +#: src/Content/Conversation.php:887 #, php-format msgid "Relayed by %s <%s>" msgstr "Weitergeleitet von %s <%s>" -#: src/Content/Conversation.php:889 +#: src/Content/Conversation.php:890 msgid "Fetched" msgstr "Abgerufen" -#: src/Content/Conversation.php:889 +#: src/Content/Conversation.php:890 #, php-format msgid "Fetched because of %s <%s>" msgstr "Wegen %s <%s> abgerufen" @@ -2293,7 +2294,7 @@ msgid "Display membership date in profile" msgstr "Das Datum der Registrierung deines Accounts im Profil anzeigen" #: src/Content/ForumManager.php:151 src/Content/Nav.php:239 -#: src/Content/Text/HTML.php:896 src/Content/Widget.php:522 +#: src/Content/Text/HTML.php:903 src/Content/Widget.php:524 msgid "Forums" msgstr "Foren" @@ -2301,12 +2302,12 @@ msgstr "Foren" msgid "External link to forum" msgstr "Externer Link zum Forum" -#: src/Content/ForumManager.php:156 src/Content/Widget.php:501 +#: src/Content/ForumManager.php:156 src/Content/Widget.php:503 msgid "show less" msgstr "weniger anzeigen" -#: src/Content/ForumManager.php:157 src/Content/Widget.php:403 -#: src/Content/Widget.php:502 +#: src/Content/ForumManager.php:157 src/Content/Widget.php:405 +#: src/Content/Widget.php:504 msgid "show more" msgstr "mehr anzeigen" @@ -2315,7 +2316,7 @@ msgstr "mehr anzeigen" msgid "%1$s poked %2$s" msgstr "%1$s stupste %2$s" -#: src/Content/Item.php:334 src/Model/Item.php:2697 +#: src/Content/Item.php:334 src/Model/Item.php:2726 msgid "event" msgstr "Veranstaltung" @@ -2323,32 +2324,32 @@ msgstr "Veranstaltung" msgid "Follow Thread" msgstr "Folge der Unterhaltung" -#: src/Content/Item.php:423 src/Model/Contact.php:1107 +#: src/Content/Item.php:423 src/Model/Contact.php:1108 msgid "View Status" msgstr "Status anschauen" #: src/Content/Item.php:424 src/Content/Item.php:446 -#: src/Model/Contact.php:1041 src/Model/Contact.php:1099 -#: src/Model/Contact.php:1108 src/Module/Directory.php:158 +#: src/Model/Contact.php:1042 src/Model/Contact.php:1100 +#: src/Model/Contact.php:1109 src/Module/Directory.php:158 #: src/Module/Settings/Profile/Index.php:225 msgid "View Profile" msgstr "Profil anschauen" -#: src/Content/Item.php:425 src/Model/Contact.php:1109 +#: src/Content/Item.php:425 src/Model/Contact.php:1110 msgid "View Photos" msgstr "Bilder anschauen" -#: src/Content/Item.php:426 src/Model/Contact.php:1100 -#: src/Model/Contact.php:1110 +#: src/Content/Item.php:426 src/Model/Contact.php:1101 +#: src/Model/Contact.php:1111 msgid "Network Posts" msgstr "Netzwerkbeiträge" -#: src/Content/Item.php:427 src/Model/Contact.php:1101 -#: src/Model/Contact.php:1111 +#: src/Content/Item.php:427 src/Model/Contact.php:1102 +#: src/Model/Contact.php:1112 msgid "View Contact" msgstr "Kontakt anzeigen" -#: src/Content/Item.php:428 src/Model/Contact.php:1112 +#: src/Content/Item.php:428 src/Model/Contact.php:1113 msgid "Send PM" msgstr "Private Nachricht senden" @@ -2367,11 +2368,11 @@ msgstr "Sperren" msgid "Ignore" msgstr "Ignorieren" -#: src/Content/Item.php:434 src/Object/Post.php:445 +#: src/Content/Item.php:434 src/Object/Post.php:455 msgid "Languages" msgstr "Sprachen" -#: src/Content/Item.php:438 src/Model/Contact.php:1113 +#: src/Content/Item.php:438 src/Model/Contact.php:1114 msgid "Poke" msgstr "Anstupsen" @@ -2387,7 +2388,7 @@ msgstr "Geh zurück" msgid "Clear notifications" msgstr "Bereinige Benachrichtigungen" -#: src/Content/Nav.php:96 src/Content/Text/HTML.php:883 +#: src/Content/Nav.php:96 src/Content/Text/HTML.php:890 msgid "@name, !forum, #tags, content" msgstr "@name, !forum, #tags, content" @@ -2410,7 +2411,7 @@ msgstr "Anmelden" #: src/Content/Nav.php:190 src/Module/BaseProfile.php:56 #: src/Module/Contact.php:433 src/Module/Contact/Profile.php:380 -#: src/Module/Settings/TwoFactor/Index.php:112 view/theme/frio/theme.php:225 +#: src/Module/Settings/TwoFactor/Index.php:115 view/theme/frio/theme.php:225 msgid "Status" msgstr "Status" @@ -2471,7 +2472,7 @@ msgstr "Nutzerkonto erstellen" #: src/Content/Nav.php:222 src/Module/Help.php:67 #: src/Module/Settings/TwoFactor/AppSpecific.php:127 -#: src/Module/Settings/TwoFactor/Index.php:111 +#: src/Module/Settings/TwoFactor/Index.php:114 #: src/Module/Settings/TwoFactor/Recovery.php:105 #: src/Module/Settings/TwoFactor/Verify.php:145 view/theme/vier/theme.php:217 msgid "Help" @@ -2489,8 +2490,8 @@ msgstr "Apps" msgid "Addon applications, utilities, games" msgstr "Zusätzliche Anwendungen, Dienstprogramme, Spiele" -#: src/Content/Nav.php:230 src/Content/Text/HTML.php:881 -#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:97 +#: src/Content/Nav.php:230 src/Content/Text/HTML.php:888 +#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:112 msgid "Search" msgstr "Suche" @@ -2498,17 +2499,17 @@ msgstr "Suche" msgid "Search site content" msgstr "Inhalt der Seite durchsuchen" -#: src/Content/Nav.php:233 src/Content/Text/HTML.php:890 +#: src/Content/Nav.php:233 src/Content/Text/HTML.php:897 msgid "Full Text" msgstr "Volltext" -#: src/Content/Nav.php:234 src/Content/Text/HTML.php:891 +#: src/Content/Nav.php:234 src/Content/Text/HTML.php:898 #: src/Content/Widget/TagCloud.php:68 msgid "Tags" msgstr "Tags" #: src/Content/Nav.php:235 src/Content/Nav.php:294 -#: src/Content/Text/HTML.php:892 src/Module/BaseProfile.php:125 +#: src/Content/Text/HTML.php:899 src/Module/BaseProfile.php:125 #: src/Module/BaseProfile.php:128 src/Module/Contact.php:370 #: src/Module/Contact.php:464 view/theme/frio/theme.php:236 msgid "Contacts" @@ -2535,7 +2536,7 @@ msgstr "Verzeichnis" msgid "People directory" msgstr "Nutzerverzeichnis" -#: src/Content/Nav.php:263 src/Module/BaseAdmin.php:85 +#: src/Content/Nav.php:263 src/Module/BaseAdmin.php:88 msgid "Information" msgstr "Information" @@ -2544,7 +2545,7 @@ msgid "Information about this friendica instance" msgstr "Informationen zu dieser Friendica-Instanz" #: src/Content/Nav.php:266 src/Module/Admin/Tos.php:76 -#: src/Module/BaseAdmin.php:96 src/Module/Register.php:176 +#: src/Module/BaseAdmin.php:99 src/Module/Register.php:176 #: src/Module/Tos.php:87 msgid "Terms of Service" msgstr "Nutzungsbedingungen" @@ -2616,7 +2617,7 @@ msgstr "Kontoeinstellungen" msgid "Manage/edit friends and contacts" msgstr "Freunde und Kontakte verwalten/bearbeiten" -#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:126 +#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:129 msgid "Admin" msgstr "Administration" @@ -2656,8 +2657,8 @@ msgstr "nächste" msgid "last" msgstr "letzte" -#: src/Content/Text/BBCode.php:990 src/Content/Text/BBCode.php:1784 -#: src/Content/Text/BBCode.php:1785 +#: src/Content/Text/BBCode.php:990 src/Content/Text/BBCode.php:1808 +#: src/Content/Text/BBCode.php:1809 msgid "Image/photo" msgstr "Bild/Foto" @@ -2666,41 +2667,41 @@ msgstr "Bild/Foto" msgid "%2$s %3$s" msgstr "%2$s%3$s" -#: src/Content/Text/BBCode.php:1188 src/Model/Item.php:3271 -#: src/Model/Item.php:3277 src/Model/Item.php:3278 +#: src/Content/Text/BBCode.php:1188 src/Model/Item.php:3301 +#: src/Model/Item.php:3307 src/Model/Item.php:3308 msgid "Link to source" msgstr "Link zum Originalbeitrag" -#: src/Content/Text/BBCode.php:1702 src/Content/Text/HTML.php:933 +#: src/Content/Text/BBCode.php:1726 src/Content/Text/HTML.php:940 msgid "Click to open/close" msgstr "Zum Öffnen/Schließen klicken" -#: src/Content/Text/BBCode.php:1733 +#: src/Content/Text/BBCode.php:1757 msgid "$1 wrote:" msgstr "$1 hat geschrieben:" -#: src/Content/Text/BBCode.php:1789 src/Content/Text/BBCode.php:1790 +#: src/Content/Text/BBCode.php:1813 src/Content/Text/BBCode.php:1814 msgid "Encrypted content" msgstr "Verschlüsselter Inhalt" -#: src/Content/Text/BBCode.php:2008 +#: src/Content/Text/BBCode.php:2032 msgid "Invalid source protocol" msgstr "Ungültiges Quell-Protokoll" -#: src/Content/Text/BBCode.php:2023 +#: src/Content/Text/BBCode.php:2047 msgid "Invalid link protocol" msgstr "Ungültiges Link-Protokoll" -#: src/Content/Text/HTML.php:797 +#: src/Content/Text/HTML.php:805 msgid "Loading more entries..." msgstr "lade weitere Einträge..." -#: src/Content/Text/HTML.php:798 +#: src/Content/Text/HTML.php:806 msgid "The end" msgstr "Das Ende" -#: src/Content/Text/HTML.php:875 src/Content/Widget/VCard.php:109 -#: src/Model/Profile.php:456 +#: src/Content/Text/HTML.php:882 src/Content/Widget/VCard.php:109 +#: src/Model/Profile.php:457 msgid "Follow" msgstr "Folge" @@ -2720,117 +2721,117 @@ msgstr "Beispiel: bob@example.com, http://example.com/barbara" msgid "Connect" msgstr "Verbinden" -#: src/Content/Widget.php:70 +#: src/Content/Widget.php:72 #, php-format msgid "%d invitation available" msgid_plural "%d invitations available" msgstr[0] "%d Einladung verfügbar" msgstr[1] "%d Einladungen verfügbar" -#: src/Content/Widget.php:76 view/theme/vier/theme.php:170 +#: src/Content/Widget.php:78 view/theme/vier/theme.php:170 msgid "Find People" msgstr "Leute finden" -#: src/Content/Widget.php:77 view/theme/vier/theme.php:171 +#: src/Content/Widget.php:79 view/theme/vier/theme.php:171 msgid "Enter name or interest" msgstr "Name oder Interessen eingeben" -#: src/Content/Widget.php:79 view/theme/vier/theme.php:173 +#: src/Content/Widget.php:81 view/theme/vier/theme.php:173 msgid "Examples: Robert Morgenstein, Fishing" msgstr "Beispiel: Robert Morgenstein, Angeln" -#: src/Content/Widget.php:80 src/Module/Contact.php:391 +#: src/Content/Widget.php:82 src/Module/Contact.php:391 #: src/Module/Directory.php:97 view/theme/vier/theme.php:174 msgid "Find" msgstr "Finde" -#: src/Content/Widget.php:82 view/theme/vier/theme.php:176 +#: src/Content/Widget.php:84 view/theme/vier/theme.php:176 msgid "Similar Interests" msgstr "Ähnliche Interessen" -#: src/Content/Widget.php:83 view/theme/vier/theme.php:177 +#: src/Content/Widget.php:85 view/theme/vier/theme.php:177 msgid "Random Profile" msgstr "Zufälliges Profil" -#: src/Content/Widget.php:84 view/theme/vier/theme.php:178 +#: src/Content/Widget.php:86 view/theme/vier/theme.php:178 msgid "Invite Friends" msgstr "Freunde einladen" -#: src/Content/Widget.php:85 src/Module/Directory.php:89 +#: src/Content/Widget.php:87 src/Module/Directory.php:89 #: view/theme/vier/theme.php:179 msgid "Global Directory" msgstr "Weltweites Verzeichnis" -#: src/Content/Widget.php:87 view/theme/vier/theme.php:181 +#: src/Content/Widget.php:89 view/theme/vier/theme.php:181 msgid "Local Directory" msgstr "Lokales Verzeichnis" -#: src/Content/Widget.php:209 src/Model/Group.php:570 +#: src/Content/Widget.php:211 src/Model/Group.php:583 #: src/Module/Contact.php:354 src/Module/Welcome.php:76 msgid "Groups" msgstr "Gruppen" -#: src/Content/Widget.php:211 +#: src/Content/Widget.php:213 msgid "Everyone" msgstr "Jeder" -#: src/Content/Widget.php:240 +#: src/Content/Widget.php:242 msgid "Relationships" msgstr "Beziehungen" -#: src/Content/Widget.php:242 src/Module/Contact.php:306 +#: src/Content/Widget.php:244 src/Module/Contact.php:306 #: src/Module/Group.php:293 msgid "All Contacts" msgstr "Alle Kontakte" -#: src/Content/Widget.php:281 +#: src/Content/Widget.php:283 msgid "Protocols" msgstr "Protokolle" -#: src/Content/Widget.php:283 +#: src/Content/Widget.php:285 msgid "All Protocols" msgstr "Alle Protokolle" -#: src/Content/Widget.php:311 +#: src/Content/Widget.php:313 msgid "Saved Folders" msgstr "Gespeicherte Ordner" -#: src/Content/Widget.php:313 src/Content/Widget.php:344 +#: src/Content/Widget.php:315 src/Content/Widget.php:346 msgid "Everything" msgstr "Alles" -#: src/Content/Widget.php:342 +#: src/Content/Widget.php:344 msgid "Categories" msgstr "Kategorien" -#: src/Content/Widget.php:399 +#: src/Content/Widget.php:401 #, 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:495 +#: src/Content/Widget.php:497 msgid "Archives" msgstr "Archiv" -#: src/Content/Widget.php:519 +#: src/Content/Widget.php:521 msgid "Persons" msgstr "Personen" -#: src/Content/Widget.php:520 +#: src/Content/Widget.php:522 msgid "Organisations" msgstr "Organisationen" -#: src/Content/Widget.php:521 src/Model/Contact.php:1537 +#: src/Content/Widget.php:523 src/Model/Contact.php:1538 msgid "News" msgstr "Nachrichten" -#: src/Content/Widget.php:525 src/Module/Settings/Account.php:455 +#: src/Content/Widget.php:527 src/Module/Settings/Account.php:455 msgid "Account Types" msgstr "Kontenarten" -#: src/Content/Widget.php:526 src/Module/Admin/BaseUsers.php:51 +#: src/Content/Widget.php:528 src/Module/Admin/BaseUsers.php:51 msgid "All" msgstr "Alle" @@ -2880,22 +2881,22 @@ msgstr[1] "Trending Tags (%d Stunden)" msgid "More Trending Tags" msgstr "mehr Trending Tags" -#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:375 +#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:376 #: src/Module/Contact/Profile.php:371 src/Module/Profile/Profile.php:176 msgid "XMPP:" msgstr "XMPP:" -#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:376 +#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:377 #: src/Module/Contact/Profile.php:373 src/Module/Profile/Profile.php:180 msgid "Matrix:" msgstr "Matrix:" -#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:468 +#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:469 #: src/Module/Notifications/Introductions.php:199 msgid "Network:" msgstr "Netzwerk:" -#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:458 +#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:459 msgid "Unfollow" msgstr "Entfolgen" @@ -3257,207 +3258,207 @@ msgstr "Die Datenbank wird bereits verwendet." msgid "Could not connect to database." msgstr "Verbindung zur Datenbank gescheitert." -#: src/Core/L10n.php:400 src/Model/Event.php:425 +#: src/Core/L10n.php:399 src/Model/Event.php:424 #: src/Module/Settings/Display.php:182 msgid "Monday" msgstr "Montag" -#: src/Core/L10n.php:400 src/Model/Event.php:426 +#: src/Core/L10n.php:399 src/Model/Event.php:425 msgid "Tuesday" msgstr "Dienstag" -#: src/Core/L10n.php:400 src/Model/Event.php:427 +#: src/Core/L10n.php:399 src/Model/Event.php:426 msgid "Wednesday" msgstr "Mittwoch" -#: src/Core/L10n.php:400 src/Model/Event.php:428 +#: src/Core/L10n.php:399 src/Model/Event.php:427 msgid "Thursday" msgstr "Donnerstag" -#: src/Core/L10n.php:400 src/Model/Event.php:429 +#: src/Core/L10n.php:399 src/Model/Event.php:428 msgid "Friday" msgstr "Freitag" -#: src/Core/L10n.php:400 src/Model/Event.php:430 +#: src/Core/L10n.php:399 src/Model/Event.php:429 msgid "Saturday" msgstr "Samstag" -#: src/Core/L10n.php:400 src/Model/Event.php:424 +#: src/Core/L10n.php:399 src/Model/Event.php:423 #: src/Module/Settings/Display.php:182 msgid "Sunday" msgstr "Sonntag" -#: src/Core/L10n.php:404 src/Model/Event.php:445 +#: src/Core/L10n.php:403 src/Model/Event.php:444 msgid "January" msgstr "Januar" -#: src/Core/L10n.php:404 src/Model/Event.php:446 +#: src/Core/L10n.php:403 src/Model/Event.php:445 msgid "February" msgstr "Februar" -#: src/Core/L10n.php:404 src/Model/Event.php:447 +#: src/Core/L10n.php:403 src/Model/Event.php:446 msgid "March" msgstr "März" -#: src/Core/L10n.php:404 src/Model/Event.php:448 +#: src/Core/L10n.php:403 src/Model/Event.php:447 msgid "April" msgstr "April" -#: src/Core/L10n.php:404 src/Core/L10n.php:424 src/Model/Event.php:436 +#: src/Core/L10n.php:403 src/Core/L10n.php:422 src/Model/Event.php:435 msgid "May" msgstr "Mai" -#: src/Core/L10n.php:404 src/Model/Event.php:449 +#: src/Core/L10n.php:403 src/Model/Event.php:448 msgid "June" msgstr "Juni" -#: src/Core/L10n.php:404 src/Model/Event.php:450 +#: src/Core/L10n.php:403 src/Model/Event.php:449 msgid "July" msgstr "Juli" -#: src/Core/L10n.php:404 src/Model/Event.php:451 +#: src/Core/L10n.php:403 src/Model/Event.php:450 msgid "August" msgstr "August" -#: src/Core/L10n.php:404 src/Model/Event.php:452 +#: src/Core/L10n.php:403 src/Model/Event.php:451 msgid "September" msgstr "September" -#: src/Core/L10n.php:404 src/Model/Event.php:453 +#: src/Core/L10n.php:403 src/Model/Event.php:452 msgid "October" msgstr "Oktober" -#: src/Core/L10n.php:404 src/Model/Event.php:454 +#: src/Core/L10n.php:403 src/Model/Event.php:453 msgid "November" msgstr "November" -#: src/Core/L10n.php:404 src/Model/Event.php:455 +#: src/Core/L10n.php:403 src/Model/Event.php:454 msgid "December" msgstr "Dezember" -#: src/Core/L10n.php:420 src/Model/Event.php:417 +#: src/Core/L10n.php:418 src/Model/Event.php:416 msgid "Mon" msgstr "Mo" -#: src/Core/L10n.php:420 src/Model/Event.php:418 +#: src/Core/L10n.php:418 src/Model/Event.php:417 msgid "Tue" msgstr "Di" -#: src/Core/L10n.php:420 src/Model/Event.php:419 +#: src/Core/L10n.php:418 src/Model/Event.php:418 msgid "Wed" msgstr "Mi" -#: src/Core/L10n.php:420 src/Model/Event.php:420 +#: src/Core/L10n.php:418 src/Model/Event.php:419 msgid "Thu" msgstr "Do" -#: src/Core/L10n.php:420 src/Model/Event.php:421 +#: src/Core/L10n.php:418 src/Model/Event.php:420 msgid "Fri" msgstr "Fr" -#: src/Core/L10n.php:420 src/Model/Event.php:422 +#: src/Core/L10n.php:418 src/Model/Event.php:421 msgid "Sat" msgstr "Sa" -#: src/Core/L10n.php:420 src/Model/Event.php:416 +#: src/Core/L10n.php:418 src/Model/Event.php:415 msgid "Sun" msgstr "So" -#: src/Core/L10n.php:424 src/Model/Event.php:432 +#: src/Core/L10n.php:422 src/Model/Event.php:431 msgid "Jan" msgstr "Jan" -#: src/Core/L10n.php:424 src/Model/Event.php:433 +#: src/Core/L10n.php:422 src/Model/Event.php:432 msgid "Feb" msgstr "Feb" -#: src/Core/L10n.php:424 src/Model/Event.php:434 +#: src/Core/L10n.php:422 src/Model/Event.php:433 msgid "Mar" msgstr "März" -#: src/Core/L10n.php:424 src/Model/Event.php:435 +#: src/Core/L10n.php:422 src/Model/Event.php:434 msgid "Apr" msgstr "Apr" -#: src/Core/L10n.php:424 src/Model/Event.php:437 +#: src/Core/L10n.php:422 src/Model/Event.php:436 msgid "Jun" msgstr "Jun" -#: src/Core/L10n.php:424 src/Model/Event.php:438 +#: src/Core/L10n.php:422 src/Model/Event.php:437 msgid "Jul" msgstr "Juli" -#: src/Core/L10n.php:424 src/Model/Event.php:439 +#: src/Core/L10n.php:422 src/Model/Event.php:438 msgid "Aug" msgstr "Aug" -#: src/Core/L10n.php:424 +#: src/Core/L10n.php:422 msgid "Sep" msgstr "Sep" -#: src/Core/L10n.php:424 src/Model/Event.php:441 +#: src/Core/L10n.php:422 src/Model/Event.php:440 msgid "Oct" msgstr "Okt" -#: src/Core/L10n.php:424 src/Model/Event.php:442 +#: src/Core/L10n.php:422 src/Model/Event.php:441 msgid "Nov" msgstr "Nov" -#: src/Core/L10n.php:424 src/Model/Event.php:443 +#: src/Core/L10n.php:422 src/Model/Event.php:442 msgid "Dec" msgstr "Dez" -#: src/Core/L10n.php:443 +#: src/Core/L10n.php:441 msgid "poke" msgstr "anstupsen" -#: src/Core/L10n.php:443 +#: src/Core/L10n.php:441 msgid "poked" msgstr "stupste" -#: src/Core/L10n.php:444 +#: src/Core/L10n.php:442 msgid "ping" msgstr "anpingen" -#: src/Core/L10n.php:444 +#: src/Core/L10n.php:442 msgid "pinged" msgstr "pingte" -#: src/Core/L10n.php:445 +#: src/Core/L10n.php:443 msgid "prod" msgstr "knuffen" -#: src/Core/L10n.php:445 +#: src/Core/L10n.php:443 msgid "prodded" msgstr "knuffte" -#: src/Core/L10n.php:446 +#: src/Core/L10n.php:444 msgid "slap" msgstr "ohrfeigen" -#: src/Core/L10n.php:446 +#: src/Core/L10n.php:444 msgid "slapped" msgstr "ohrfeigte" -#: src/Core/L10n.php:447 +#: src/Core/L10n.php:445 msgid "finger" msgstr "befummeln" -#: src/Core/L10n.php:447 +#: src/Core/L10n.php:445 msgid "fingered" msgstr "befummelte" -#: src/Core/L10n.php:448 +#: src/Core/L10n.php:446 msgid "rebuff" msgstr "eine Abfuhr erteilen" -#: src/Core/L10n.php:448 +#: src/Core/L10n.php:446 msgid "rebuffed" msgstr "abfuhrerteilte" #: src/Core/Renderer.php:89 src/Core/Renderer.php:118 #: src/Core/Renderer.php:145 src/Core/Renderer.php:179 -#: src/Render/FriendicaSmartyEngine.php:56 +#: src/Render/FriendicaSmartyEngine.php:69 msgid "" "Friendica can't display this page at the moment, please contact the " "administrator." @@ -3540,35 +3541,35 @@ msgid "" "\t\t\t\t\tThe friendica database was successfully updated from %s to %s." msgstr "\n \t\t\t\t\tDie Friendica Datenbank wurde erfolgreich von %s auf %s aktualisiert." -#: src/Core/UserImport.php:125 +#: src/Core/UserImport.php:126 msgid "Error decoding account file" msgstr "Fehler beim Verarbeiten der Account-Datei" -#: src/Core/UserImport.php:131 +#: src/Core/UserImport.php:132 msgid "Error! No version data in file! This is not a Friendica account file?" msgstr "Fehler! Keine Versionsdaten in der Datei! Ist das wirklich eine Friendica-Account-Datei?" -#: src/Core/UserImport.php:139 +#: src/Core/UserImport.php:140 #, php-format msgid "User '%s' already exists on this server!" msgstr "Nutzer '%s' existiert bereits auf diesem Server!" -#: src/Core/UserImport.php:175 +#: src/Core/UserImport.php:176 msgid "User creation error" msgstr "Fehler beim Anlegen des Nutzer-Accounts aufgetreten" -#: src/Core/UserImport.php:220 +#: src/Core/UserImport.php:221 #, 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/Core/UserImport.php:273 +#: src/Core/UserImport.php:274 msgid "User profile creation error" msgstr "Fehler beim Anlegen des Nutzer-Profils" -#: src/Core/UserImport.php:326 +#: src/Core/UserImport.php:327 msgid "Done. You can now login with your username and password" msgstr "Erledigt. Du kannst dich jetzt mit deinem Nutzernamen und Passwort anmelden" @@ -3598,7 +3599,7 @@ msgstr "Diese Tabellen werden nicht von Friendica verwendet. Sie werden gelösch 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:158 +#: src/Database/DBStructure.php:157 #, php-format msgid "" "\n" @@ -3606,20 +3607,20 @@ msgid "" "%s\n" msgstr "\nFehler %d beim Update der Datenbank aufgetreten\n%s\n" -#: src/Database/DBStructure.php:161 +#: src/Database/DBStructure.php:160 msgid "Errors encountered performing database changes: " msgstr "Fehler beim Ändern der Datenbank aufgetreten" -#: src/Database/DBStructure.php:549 +#: src/Database/DBStructure.php:563 msgid "Another database update is currently running." msgstr "Es läuft bereits ein anderes Datenbank Update" -#: src/Database/DBStructure.php:553 +#: src/Database/DBStructure.php:567 #, php-format msgid "%s: Database update" msgstr "%s: Datenbank Aktualisierung" -#: src/Database/DBStructure.php:803 +#: src/Database/DBStructure.php:817 #, php-format msgid "%s: updating %s table." msgstr "%s: aktualisiere Tabelle %s" @@ -3650,81 +3651,81 @@ msgstr "Interner Serverfehler" msgid "Legacy module file not found: %s" msgstr "Legacy-Moduldatei nicht gefunden: %s" -#: src/Model/Contact.php:1103 src/Model/Contact.php:1115 +#: src/Model/Contact.php:1104 src/Model/Contact.php:1116 msgid "UnFollow" msgstr "Entfolgen" -#: src/Model/Contact.php:1121 src/Module/Admin/Users/Pending.php:107 +#: src/Model/Contact.php:1122 src/Module/Admin/Users/Pending.php:107 #: src/Module/Notifications/Introductions.php:130 #: src/Module/Notifications/Introductions.php:202 msgid "Approve" msgstr "Genehmigen" -#: src/Model/Contact.php:1533 +#: src/Model/Contact.php:1534 msgid "Organisation" msgstr "Organisation" -#: src/Model/Contact.php:1541 +#: src/Model/Contact.php:1542 msgid "Forum" msgstr "Forum" -#: src/Model/Contact.php:2517 +#: src/Model/Contact.php:2625 msgid "Disallowed profile URL." msgstr "Nicht erlaubte Profil-URL." -#: src/Model/Contact.php:2522 src/Module/Friendica.php:81 +#: src/Model/Contact.php:2630 src/Module/Friendica.php:81 msgid "Blocked domain" msgstr "Blockierte Domain" -#: src/Model/Contact.php:2527 +#: src/Model/Contact.php:2635 msgid "Connect URL missing." msgstr "Connect-URL fehlt" -#: src/Model/Contact.php:2536 +#: src/Model/Contact.php:2644 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:2578 +#: src/Model/Contact.php:2686 msgid "The profile address specified does not provide adequate information." msgstr "Die angegebene Profiladresse liefert unzureichende Informationen." -#: src/Model/Contact.php:2580 +#: src/Model/Contact.php:2688 msgid "No compatible communication protocols or feeds were discovered." msgstr "Es wurden keine kompatiblen Kommunikationsprotokolle oder Feeds gefunden." -#: src/Model/Contact.php:2583 +#: src/Model/Contact.php:2691 msgid "An author or name was not found." msgstr "Es wurde kein Autor oder Name gefunden." -#: src/Model/Contact.php:2586 +#: src/Model/Contact.php:2694 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:2589 +#: src/Model/Contact.php:2697 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:2590 +#: src/Model/Contact.php:2698 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:2596 +#: src/Model/Contact.php:2704 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:2601 +#: src/Model/Contact.php:2709 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:2660 +#: src/Model/Contact.php:2768 msgid "Unable to retrieve contact information." msgstr "Konnte die Kontaktinformationen nicht empfangen." @@ -3732,41 +3733,41 @@ msgstr "Konnte die Kontaktinformationen nicht empfangen." msgid "l F d, Y \\@ g:i A \\G\\M\\TP (e)" msgstr "l F d, Y \\@ g:i A \\G\\M\\TP (e)" -#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:464 +#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:463 #: src/Model/Event.php:897 msgid "Starts:" msgstr "Beginnt:" -#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:465 +#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:464 #: src/Model/Event.php:901 msgid "Finishes:" msgstr "Endet:" -#: src/Model/Event.php:414 +#: src/Model/Event.php:413 msgid "all-day" msgstr "ganztägig" -#: src/Model/Event.php:440 +#: src/Model/Event.php:439 msgid "Sept" msgstr "Sep" -#: src/Model/Event.php:462 +#: src/Model/Event.php:461 msgid "No events to display" msgstr "Keine Veranstaltung zum Anzeigen" -#: src/Model/Event.php:578 +#: src/Model/Event.php:577 msgid "l, F j" msgstr "l, F j" -#: src/Model/Event.php:609 +#: src/Model/Event.php:608 msgid "Edit event" msgstr "Veranstaltung bearbeiten" -#: src/Model/Event.php:610 +#: src/Model/Event.php:609 msgid "Duplicate event" msgstr "Veranstaltung kopieren" -#: src/Model/Event.php:611 +#: src/Model/Event.php:610 msgid "Delete event" msgstr "Veranstaltung löschen" @@ -3790,112 +3791,112 @@ msgstr "Karte anzeigen" msgid "Hide map" msgstr "Karte verbergen" -#: src/Model/Event.php:1009 +#: src/Model/Event.php:1010 #, php-format msgid "%s's birthday" msgstr "%ss Geburtstag" -#: src/Model/Event.php:1010 +#: src/Model/Event.php:1011 #, php-format msgid "Happy Birthday %s" msgstr "Herzlichen Glückwunsch, %s" -#: src/Model/Group.php:95 +#: 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:486 +#: src/Model/Group.php:499 msgid "Default privacy group for new contacts" msgstr "Voreingestellte Gruppe für neue Kontakte" -#: src/Model/Group.php:518 +#: src/Model/Group.php:531 msgid "Everybody" msgstr "Alle Kontakte" -#: src/Model/Group.php:537 +#: src/Model/Group.php:550 msgid "edit" msgstr "bearbeiten" -#: src/Model/Group.php:569 +#: src/Model/Group.php:582 msgid "add" msgstr "hinzufügen" -#: src/Model/Group.php:574 +#: src/Model/Group.php:587 msgid "Edit group" msgstr "Gruppe bearbeiten" -#: src/Model/Group.php:575 src/Module/Group.php:194 +#: src/Model/Group.php:588 src/Module/Group.php:194 msgid "Contacts not in any group" msgstr "Kontakte in keiner Gruppe" -#: src/Model/Group.php:577 +#: src/Model/Group.php:590 msgid "Create a new group" msgstr "Neue Gruppe erstellen" -#: src/Model/Group.php:578 src/Module/Group.php:179 src/Module/Group.php:202 +#: src/Model/Group.php:591 src/Module/Group.php:179 src/Module/Group.php:202 #: src/Module/Group.php:277 msgid "Group Name: " msgstr "Gruppenname:" -#: src/Model/Group.php:579 +#: src/Model/Group.php:592 msgid "Edit groups" msgstr "Gruppen bearbeiten" -#: src/Model/Item.php:1795 +#: src/Model/Item.php:1823 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "Erkannte Sprachen in diesem Beitrag:\\n%s" -#: src/Model/Item.php:2701 +#: src/Model/Item.php:2730 msgid "activity" msgstr "Aktivität" -#: src/Model/Item.php:2703 +#: src/Model/Item.php:2732 msgid "comment" msgstr "Kommentar" -#: src/Model/Item.php:2706 +#: src/Model/Item.php:2735 msgid "post" msgstr "Beitrag" -#: src/Model/Item.php:2821 +#: src/Model/Item.php:2851 #, php-format msgid "Content warning: %s" msgstr "Inhaltswarnung: %s" -#: src/Model/Item.php:3180 +#: src/Model/Item.php:3210 msgid "bytes" msgstr "Byte" -#: src/Model/Item.php:3214 +#: src/Model/Item.php:3244 #, php-format msgid "%s (%d%s, %d votes)" msgstr "%s (%d%s, %d Stimmen)" -#: src/Model/Item.php:3216 +#: src/Model/Item.php:3246 #, php-format msgid "%s (%d votes)" msgstr "%s (%d Stimmen)" -#: src/Model/Item.php:3221 +#: src/Model/Item.php:3251 #, php-format msgid "%d voters. Poll end: %s" msgstr "%d Stimmen, Abstimmung endet: %s" -#: src/Model/Item.php:3223 +#: src/Model/Item.php:3253 #, php-format msgid "%d voters." msgstr "%d Stimmen." -#: src/Model/Item.php:3225 +#: src/Model/Item.php:3255 #, php-format msgid "Poll end: %s" msgstr "Abstimmung endet: %s" -#: src/Model/Item.php:3259 src/Model/Item.php:3260 +#: src/Model/Item.php:3289 src/Model/Item.php:3290 msgid "View on separate page" msgstr "Auf separater Seite ansehen" @@ -3903,147 +3904,147 @@ msgstr "Auf separater Seite ansehen" msgid "[no subject]" msgstr "[kein Betreff]" -#: src/Model/Profile.php:358 src/Module/Profile/Profile.php:256 +#: src/Model/Profile.php:359 src/Module/Profile/Profile.php:256 #: src/Module/Profile/Profile.php:258 msgid "Edit profile" msgstr "Profil bearbeiten" -#: src/Model/Profile.php:360 +#: src/Model/Profile.php:361 msgid "Change profile photo" msgstr "Profilbild ändern" -#: src/Model/Profile.php:373 src/Module/Directory.php:153 +#: src/Model/Profile.php:374 src/Module/Directory.php:153 #: src/Module/Profile/Profile.php:184 msgid "Homepage:" msgstr "Homepage:" -#: src/Model/Profile.php:374 src/Module/Contact/Profile.php:375 +#: src/Model/Profile.php:375 src/Module/Contact/Profile.php:375 #: src/Module/Notifications/Introductions.php:187 msgid "About:" msgstr "Über:" -#: src/Model/Profile.php:460 +#: src/Model/Profile.php:461 msgid "Atom feed" msgstr "Atom-Feed" -#: src/Model/Profile.php:504 +#: src/Model/Profile.php:505 msgid "F d" msgstr "d. F" -#: src/Model/Profile.php:568 src/Model/Profile.php:652 +#: src/Model/Profile.php:569 src/Model/Profile.php:653 msgid "[today]" msgstr "[heute]" -#: src/Model/Profile.php:577 +#: src/Model/Profile.php:578 msgid "Birthday Reminders" msgstr "Geburtstagserinnerungen" -#: src/Model/Profile.php:578 +#: src/Model/Profile.php:579 msgid "Birthdays this week:" msgstr "Geburtstage diese Woche:" -#: src/Model/Profile.php:601 +#: src/Model/Profile.php:602 msgid "g A l F d" msgstr "l, d. F G \\U\\h\\r" -#: src/Model/Profile.php:639 +#: src/Model/Profile.php:640 msgid "[No description]" msgstr "[keine Beschreibung]" -#: src/Model/Profile.php:665 +#: src/Model/Profile.php:666 msgid "Event Reminders" msgstr "Veranstaltungserinnerungen" -#: src/Model/Profile.php:666 +#: src/Model/Profile.php:667 msgid "Upcoming events the next 7 days:" msgstr "Veranstaltungen der nächsten 7 Tage:" -#: src/Model/Profile.php:854 +#: src/Model/Profile.php:855 #, php-format msgid "OpenWebAuth: %1$s welcomes %2$s" msgstr "OpenWebAuth: %1$s heißt %2$s herzlich willkommen" -#: src/Model/Profile.php:980 +#: src/Model/Profile.php:981 msgid "Hometown:" msgstr "Heimatort:" -#: src/Model/Profile.php:981 +#: src/Model/Profile.php:982 msgid "Marital Status:" msgstr "Familienstand:" -#: src/Model/Profile.php:982 +#: src/Model/Profile.php:983 msgid "With:" msgstr "Mit:" -#: src/Model/Profile.php:983 +#: src/Model/Profile.php:984 msgid "Since:" msgstr "Seit:" -#: src/Model/Profile.php:984 +#: src/Model/Profile.php:985 msgid "Sexual Preference:" msgstr "Sexuelle Vorlieben:" -#: src/Model/Profile.php:985 +#: src/Model/Profile.php:986 msgid "Political Views:" msgstr "Politische Ansichten:" -#: src/Model/Profile.php:986 +#: src/Model/Profile.php:987 msgid "Religious Views:" msgstr "Religiöse Ansichten:" -#: src/Model/Profile.php:987 +#: src/Model/Profile.php:988 msgid "Likes:" msgstr "Likes:" -#: src/Model/Profile.php:988 +#: src/Model/Profile.php:989 msgid "Dislikes:" msgstr "Dislikes:" -#: src/Model/Profile.php:989 +#: src/Model/Profile.php:990 msgid "Title/Description:" msgstr "Titel/Beschreibung:" -#: src/Model/Profile.php:990 src/Module/Admin/Summary.php:234 +#: src/Model/Profile.php:991 src/Module/Admin/Summary.php:234 msgid "Summary" msgstr "Zusammenfassung" -#: src/Model/Profile.php:991 +#: src/Model/Profile.php:992 msgid "Musical interests" msgstr "Musikalische Interessen" -#: src/Model/Profile.php:992 +#: src/Model/Profile.php:993 msgid "Books, literature" msgstr "Bücher, Literatur" -#: src/Model/Profile.php:993 +#: src/Model/Profile.php:994 msgid "Television" msgstr "Fernsehen" -#: src/Model/Profile.php:994 +#: src/Model/Profile.php:995 msgid "Film/dance/culture/entertainment" msgstr "Filme/Tänze/Kultur/Unterhaltung" -#: src/Model/Profile.php:995 +#: src/Model/Profile.php:996 msgid "Hobbies/Interests" msgstr "Hobbies/Interessen" -#: src/Model/Profile.php:996 +#: src/Model/Profile.php:997 msgid "Love/romance" msgstr "Liebe/Romantik" -#: src/Model/Profile.php:997 +#: src/Model/Profile.php:998 msgid "Work/employment" msgstr "Arbeit/Anstellung" -#: src/Model/Profile.php:998 +#: src/Model/Profile.php:999 msgid "School/education" msgstr "Schule/Ausbildung" -#: src/Model/Profile.php:999 +#: src/Model/Profile.php:1000 msgid "Contact information and Social Networks" msgstr "Kontaktinformationen und Soziale Netzwerke" -#: src/Model/User.php:210 src/Model/User.php:1058 +#: src/Model/User.php:212 src/Model/User.php:1058 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "FATALER FEHLER: Sicherheitsschlüssel konnten nicht erzeugt werden." @@ -4090,13 +4091,13 @@ msgstr "Die Einladung konnte nicht überprüft werden." msgid "Invalid OpenID url" msgstr "Ungültige OpenID URL" -#: src/Model/User.php:970 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 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:970 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 msgid "The error message was:" msgstr "Die Fehlermeldung lautete:" @@ -4178,7 +4179,7 @@ msgstr "Bei der Erstellung deiner Standardgruppe für Kontakte ist ein Fehler au msgid "Profile Photos" msgstr "Profilbilder" -#: src/Model/User.php:1368 +#: src/Model/User.php:1367 #, php-format msgid "" "\n" @@ -4186,7 +4187,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:1371 +#: src/Model/User.php:1370 #, php-format msgid "" "\n" @@ -4218,12 +4219,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/removeme wieder löschen.\n\nDanke und willkommen auf %4$s." -#: src/Model/User.php:1404 src/Model/User.php:1511 +#: src/Model/User.php:1403 src/Model/User.php:1510 #, php-format msgid "Registration details for %s" msgstr "Details der Registration von %s" -#: src/Model/User.php:1424 +#: src/Model/User.php:1423 #, php-format msgid "" "\n" @@ -4238,12 +4239,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:1443 +#: src/Model/User.php:1442 #, php-format msgid "Registration at %s" msgstr "Registrierung als %s" -#: src/Model/User.php:1467 +#: src/Model/User.php:1466 #, php-format msgid "" "\n" @@ -4252,7 +4253,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:1475 +#: src/Model/User.php:1474 #, php-format msgid "" "\n" @@ -4327,7 +4328,7 @@ msgid "Administration" msgstr "Administration" #: src/Module/Admin/Addons/Details.php:112 -#: src/Module/Admin/Addons/Index.php:68 src/Module/BaseAdmin.php:93 +#: src/Module/Admin/Addons/Index.php:68 src/Module/BaseAdmin.php:96 #: src/Module/BaseSettings.php:85 msgid "Addons" msgstr "Addons" @@ -4807,7 +4808,7 @@ msgid "" "only reflect the part of the network your node is aware of." msgstr "Diese Seite präsentiert einige Zahlen zu dem bekannten Teil des föderalen sozialen Netzwerks, von dem deine Friendica Installation ein Teil ist. Diese Zahlen sind nicht absolut und reflektieren nur den Teil des Netzwerks, den dein Knoten kennt." -#: src/Module/Admin/Federation.php:197 src/Module/BaseAdmin.php:87 +#: src/Module/Admin/Federation.php:197 src/Module/BaseAdmin.php:90 msgid "Federation Statistics" msgstr "Föderation Statistik" @@ -4823,7 +4824,7 @@ msgstr "Derzeit kennt dieser Knoten %s andere Knoten (mit %s aktiven Accounts im msgid "Item marked for deletion." msgstr "Eintrag wurden zur Löschung markiert" -#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:106 +#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:109 msgid "Delete Item" msgstr "Eintrag löschen" @@ -4852,7 +4853,7 @@ msgstr "GUID" msgid "The GUID of the item you want to delete." msgstr "Die GUID des zu löschenden Eintrags" -#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:116 +#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:119 msgid "Item Source" msgstr "Beitrags Quelle" @@ -4915,8 +4916,8 @@ msgstr "PHP Protokollierung ist derzeit aktiviert." msgid "PHP log currently disabled." msgstr "PHP Protokollierung ist derzeit nicht aktiviert." -#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:108 -#: src/Module/BaseAdmin.php:109 +#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:111 +#: src/Module/BaseAdmin.php:112 msgid "Logs" msgstr "Protokolle" @@ -4969,7 +4970,7 @@ msgid "" "is readable." msgstr "Konnte die Logdatei %1$s nicht öffnen.
Bitte stelle sicher, dass die Datei %1$s lesbar ist." -#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:110 +#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:113 msgid "View Logs" msgstr "Protokolle anzeigen" @@ -5151,7 +5152,7 @@ msgstr "Lokale Kontakte" msgid "Interactors" msgstr "Interaktionen" -#: src/Module/Admin/Site.php:432 src/Module/BaseAdmin.php:90 +#: src/Module/Admin/Site.php:432 src/Module/BaseAdmin.php:93 msgid "Site" msgstr "Seite" @@ -5941,7 +5942,7 @@ msgid "" msgstr "Der Wert kann entweder 'Alle' oder 'Schlagwörter' sein. 'Alle' bedeutet, dass alle öffentliche Beiträge empfangen werden sollen. 'Schlagwörter' schränkt dem Empfang auf Beiträge ein, die bestimmte Schlagwörter beinhalten." #: src/Module/Admin/Site.php:542 src/Module/Contact/Profile.php:273 -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Disabled" msgstr "Deaktiviert" @@ -6005,7 +6006,7 @@ msgstr "Aktuelles Speicher-Backend" msgid "Storage Configuration" msgstr "Speicher Konfiguration" -#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:91 +#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:94 msgid "Storage" msgstr "Speicher" @@ -6222,7 +6223,7 @@ msgid "Screenshot" msgstr "Bildschirmfoto" #: src/Module/Admin/Themes/Details.php:91 -#: src/Module/Admin/Themes/Index.php:112 src/Module/BaseAdmin.php:94 +#: src/Module/Admin/Themes/Index.php:112 src/Module/BaseAdmin.php:97 msgid "Themes" msgstr "Themen" @@ -6426,7 +6427,7 @@ msgid "Permanent deletion" msgstr "Permanent löschen" #: src/Module/Admin/Users/Index.php:150 src/Module/Admin/Users/Index.php:160 -#: src/Module/BaseAdmin.php:92 +#: src/Module/BaseAdmin.php:95 msgid "Users" msgstr "Nutzer" @@ -6532,89 +6533,89 @@ msgstr "Anwendungen" msgid "Item was not found." msgstr "Beitrag konnte nicht gefunden werden." -#: src/Module/BaseAdmin.php:54 src/Module/BaseAdmin.php:58 +#: src/Module/BaseAdmin.php:57 src/Module/BaseAdmin.php:61 msgid "Please login to continue." msgstr "Bitte melde dich an, um fortzufahren." -#: src/Module/BaseAdmin.php:63 +#: src/Module/BaseAdmin.php:66 msgid "You don't have access to administration pages." msgstr "Du hast keinen Zugriff auf die Administrationsseiten." -#: src/Module/BaseAdmin.php:67 +#: src/Module/BaseAdmin.php:70 msgid "" "Submanaged account can't access the administration pages. Please log back in" " as the main account." msgstr "Verwaltete Benutzerkonten haben keinen Zugriff auf die Administrationsseiten. Bitte wechsle wieder zurück auf das Administrator Konto." -#: src/Module/BaseAdmin.php:86 +#: src/Module/BaseAdmin.php:89 msgid "Overview" msgstr "Übersicht" -#: src/Module/BaseAdmin.php:89 +#: src/Module/BaseAdmin.php:92 msgid "Configuration" msgstr "Konfiguration" -#: src/Module/BaseAdmin.php:95 src/Module/BaseSettings.php:63 +#: src/Module/BaseAdmin.php:98 src/Module/BaseSettings.php:63 msgid "Additional features" msgstr "Zusätzliche Features" -#: src/Module/BaseAdmin.php:98 +#: src/Module/BaseAdmin.php:101 msgid "Database" msgstr "Datenbank" -#: src/Module/BaseAdmin.php:99 +#: src/Module/BaseAdmin.php:102 msgid "DB updates" msgstr "DB Updates" -#: src/Module/BaseAdmin.php:100 +#: src/Module/BaseAdmin.php:103 msgid "Inspect Deferred Workers" msgstr "Verzögerte Worker inspizieren" -#: src/Module/BaseAdmin.php:101 +#: src/Module/BaseAdmin.php:104 msgid "Inspect worker Queue" msgstr "Worker Warteschlange inspizieren" -#: src/Module/BaseAdmin.php:103 +#: src/Module/BaseAdmin.php:106 msgid "Tools" msgstr "Werkzeuge" -#: src/Module/BaseAdmin.php:104 +#: src/Module/BaseAdmin.php:107 msgid "Contact Blocklist" msgstr "Kontakt Blockliste" -#: src/Module/BaseAdmin.php:105 +#: src/Module/BaseAdmin.php:108 msgid "Server Blocklist" msgstr "Server Blockliste" -#: src/Module/BaseAdmin.php:112 +#: src/Module/BaseAdmin.php:115 msgid "Diagnostics" msgstr "Diagnostik" -#: src/Module/BaseAdmin.php:113 +#: src/Module/BaseAdmin.php:116 msgid "PHP Info" msgstr "PHP-Info" -#: src/Module/BaseAdmin.php:114 +#: src/Module/BaseAdmin.php:117 msgid "probe address" msgstr "Adresse untersuchen" -#: src/Module/BaseAdmin.php:115 +#: src/Module/BaseAdmin.php:118 msgid "check webfinger" msgstr "Webfinger überprüfen" -#: src/Module/BaseAdmin.php:117 +#: src/Module/BaseAdmin.php:120 msgid "Babel" msgstr "Babel" -#: src/Module/BaseAdmin.php:118 src/Module/Debug/ActivityPubConversion.php:142 +#: src/Module/BaseAdmin.php:121 src/Module/Debug/ActivityPubConversion.php:142 msgid "ActivityPub Conversion" msgstr "Umwandlung nach ActivityPub" -#: src/Module/BaseAdmin.php:127 +#: src/Module/BaseAdmin.php:130 msgid "Addon Features" msgstr "Addon Features" -#: src/Module/BaseAdmin.php:128 +#: src/Module/BaseAdmin.php:131 msgid "User registrations waiting for confirmation" msgstr "Nutzeranmeldungen, die auf Bestätigung warten" @@ -6677,8 +6678,8 @@ msgstr "Forensuche - %s" msgid "Account" msgstr "Nutzerkonto" -#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:95 -#: src/Module/Settings/TwoFactor/Index.php:110 +#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:96 +#: src/Module/Settings/TwoFactor/Index.php:113 msgid "Two-factor authentication" msgstr "Zwei-Faktor Authentifizierung" @@ -6730,7 +6731,7 @@ msgid "Only show blocked contacts" msgstr "Nur blockierte Kontakte anzeigen" #: src/Module/Contact.php:330 src/Module/Contact.php:377 -#: src/Object/Post.php:329 +#: src/Object/Post.php:339 msgid "Ignored" msgstr "Ignoriert" @@ -6762,7 +6763,7 @@ msgstr "Verwalte deine Kontaktgruppen" msgid "Search your contacts" msgstr "Suche in deinen Kontakten" -#: src/Module/Contact.php:390 src/Module/Search/Index.php:192 +#: src/Module/Contact.php:390 src/Module/Search/Index.php:207 #, php-format msgid "Results for: %s" msgstr "Ergebnisse für: %s" @@ -7127,7 +7128,7 @@ msgid "" msgstr "Komma-Separierte Liste mit Schlüsselworten, die nicht in Hashtags konvertiert werden, wenn \"Beziehe Information und Schlüsselworte\" aktiviert wurde" #: src/Module/Contact/Profile.php:378 -#: src/Module/Settings/TwoFactor/Index.php:132 +#: src/Module/Settings/TwoFactor/Index.php:135 msgid "Actions" msgstr "Aktionen" @@ -7186,6 +7187,7 @@ msgstr "Willst du das Folgen dieses Kontakt wirklich widerrufen? Dies kann nicht #: src/Module/Contact/Revoke.php:107 #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:53 src/Module/Register.php:130 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "Yes" msgstr "Ja" @@ -7217,8 +7219,8 @@ msgstr "Einschließen" msgid "Hide" msgstr "Verbergen" -#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:137 -#: src/Module/Search/Index.php:179 +#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:152 +#: src/Module/Search/Index.php:194 msgid "No results." msgstr "Keine Ergebnisse." @@ -7278,7 +7280,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:287 src/Object/Post.php:341 +#: src/Module/Conversation/Network.php:287 src/Object/Post.php:351 msgid "Starred" msgstr "Markierte" @@ -8099,6 +8101,7 @@ msgstr "Behauptet, dich zu kennen: " #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:54 src/Module/Register.php:131 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "No" msgstr "Nein" @@ -8332,19 +8335,19 @@ msgstr "Betrachten als" #: src/Module/Profile/Profile.php:326 src/Module/Profile/Profile.php:329 #: src/Module/Profile/Status.php:66 src/Module/Profile/Status.php:69 -#: src/Protocol/Feed.php:1017 src/Protocol/OStatus.php:1245 +#: src/Protocol/Feed.php:1018 src/Protocol/OStatus.php:1276 #, php-format msgid "%s's timeline" msgstr "Timeline von %s" #: src/Module/Profile/Profile.php:327 src/Module/Profile/Status.php:67 -#: src/Protocol/Feed.php:1021 src/Protocol/OStatus.php:1249 +#: src/Protocol/Feed.php:1022 src/Protocol/OStatus.php:1281 #, php-format msgid "%s's posts" msgstr "Beiträge von %s" #: src/Module/Profile/Profile.php:328 src/Module/Profile/Status.php:68 -#: src/Protocol/Feed.php:1024 src/Protocol/OStatus.php:1252 +#: src/Protocol/Feed.php:1025 src/Protocol/OStatus.php:1285 #, php-format msgid "%s's comments" msgstr "Kommentare von %s" @@ -8544,15 +8547,15 @@ msgstr "Solltest du das freie Soziale Netzwerk noch nicht benutzen, kannst du " #: src/Module/Security/TwoFactor/Recovery.php:98 -#: src/Module/Security/TwoFactor/Verify.php:99 #, php-format msgid "Don’t have your phone? Enter a two-factor recovery code" msgstr "Hast du dein Handy nicht? Gib einen Zwei-Faktor-Wiederherstellungscode ein" @@ -8670,21 +8676,68 @@ msgstr "Bitte gib einen Wiederherstellungscode ein" msgid "Submit recovery code and complete login" msgstr "Sende den Wiederherstellungscode und schließe die Anmeldung ab" -#: src/Module/Security/TwoFactor/Verify.php:96 +#: src/Module/Security/TwoFactor/Signout.php:122 +msgid "Sign out of this browser?" +msgstr "Von diesem Browser abmelden?" + +#: 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 "

Wenn du diesem Browser vertraust, wirst du bei zukünftigen Anmeldungen nicht nach dem Verifikationscode gefragt.

" + +#: src/Module/Security/TwoFactor/Signout.php:124 +msgid "Sign out" +msgstr "Abmelden" + +#: src/Module/Security/TwoFactor/Signout.php:126 +msgid "Trust and sign out" +msgstr "Vertrauen und Abmelden" + +#: src/Module/Security/TwoFactor/Trust.php:89 +msgid "Couldn't save browser to Cookie." +msgstr "Konnte keine Cookies speichern." + +#: src/Module/Security/TwoFactor/Trust.php:119 +msgid "Trust this browser?" +msgstr "Vertraust du diesen Browser?" + +#: src/Module/Security/TwoFactor/Trust.php:120 +msgid "" +"

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

" +msgstr "

Wenn du diesem Browser vertraust, wirst du bei zukünftigen Anmeldungen nicht nach dem Verifikationscode gefragt.

" + +#: src/Module/Security/TwoFactor/Trust.php:121 +msgid "Not now" +msgstr "Nicht jetzt" + +#: src/Module/Security/TwoFactor/Trust.php:122 +msgid "Don't trust" +msgstr "Nicht vertrauen" + +#: src/Module/Security/TwoFactor/Trust.php:123 +msgid "Trust" +msgstr "Vertrauen" + +#: 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 "

Öffne die Zwei-Faktor-Authentifizierungs-App auf deinem Gerät, um einen Authentifizierungscode abzurufen und deine Identität zu überprüfen.

" #: 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 "Wenn du keinen Zugriff auf deinen Authentifikationscode hast, kannst du einen Zwei-Faktor Wiederherstellungsschlüssel verwenden." + +#: src/Module/Security/TwoFactor/Verify.php:101 #: src/Module/Settings/TwoFactor/Verify.php:154 msgid "Please enter a code from your authentication app" msgstr "Bitte gebe einen Code aus Ihrer Authentifizierungs-App ein" -#: src/Module/Security/TwoFactor/Verify.php:101 -msgid "This is my two-factor authenticator app device" -msgstr "Dies ist das Gerät auf dem meine 2FA Authentifizierungs-App läuft." - #: src/Module/Security/TwoFactor/Verify.php:102 msgid "Verify code and complete login" msgstr "Code überprüfen und Anmeldung abschließen" @@ -9691,99 +9744,95 @@ msgstr "Friendiqa auf meinem Fairphone 2" msgid "Generate" msgstr "Erstellen" -#: src/Module/Settings/TwoFactor/Index.php:67 +#: src/Module/Settings/TwoFactor/Index.php:68 msgid "Two-factor authentication successfully disabled." msgstr "Zwei-Faktor Authentifizierung erfolgreich deaktiviert." -#: src/Module/Settings/TwoFactor/Index.php:93 -msgid "Wrong Password" -msgstr "Falsches Passwort" - -#: src/Module/Settings/TwoFactor/Index.php:113 +#: src/Module/Settings/TwoFactor/Index.php:116 msgid "" "

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

" msgstr "

Benutze eine App auf deinem Smartphone um einen Zwei-Faktor Identifikationscode zu bekommen wenn beim Anmelden das verlangt wird.

" -#: src/Module/Settings/TwoFactor/Index.php:117 +#: src/Module/Settings/TwoFactor/Index.php:120 msgid "Authenticator app" msgstr "Zwei-Faktor Authentifizierungsapp" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Configured" msgstr "Konfiguriert" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Not Configured" msgstr "Nicht konfiguriert" -#: src/Module/Settings/TwoFactor/Index.php:119 +#: src/Module/Settings/TwoFactor/Index.php:122 msgid "

You haven't finished configuring your authenticator app.

" msgstr "

Die Konfiguration deiner Zwei-Faktor Authentifizierungsapp ist nicht abgeschlossen.

" -#: src/Module/Settings/TwoFactor/Index.php:120 +#: src/Module/Settings/TwoFactor/Index.php:123 msgid "

Your authenticator app is correctly configured.

" msgstr "

Deine Zwei-Faktor Authentifizierungsapp ist korrekt konfiguriert.

" -#: src/Module/Settings/TwoFactor/Index.php:122 +#: src/Module/Settings/TwoFactor/Index.php:125 msgid "Recovery codes" msgstr "Wiederherstellungsschlüssel" -#: src/Module/Settings/TwoFactor/Index.php:123 +#: src/Module/Settings/TwoFactor/Index.php:126 msgid "Remaining valid codes" msgstr "Verbleibende Wiederherstellungsschlüssel" -#: src/Module/Settings/TwoFactor/Index.php:125 +#: src/Module/Settings/TwoFactor/Index.php:128 msgid "" "

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

" msgstr "

Diese Einmalcodes können einen Authentifikator-App-Code ersetzen, falls du den Zugriff darauf verloren hast.

" -#: src/Module/Settings/TwoFactor/Index.php:127 +#: src/Module/Settings/TwoFactor/Index.php:130 msgid "App-specific passwords" msgstr "App spezifische Passwörter" -#: src/Module/Settings/TwoFactor/Index.php:128 +#: src/Module/Settings/TwoFactor/Index.php:131 msgid "Generated app-specific passwords" msgstr "App spezifische Passwörter erstellen" -#: src/Module/Settings/TwoFactor/Index.php:130 +#: src/Module/Settings/TwoFactor/Index.php:133 msgid "" "

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

" msgstr "

Diese zufällig erzeugten Passwörter erlauben es dir dich mit Apps anzumelden, die keine Zwei-Faktor-Authentifizierung unterstützen.

" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:136 msgid "Current password:" msgstr "Aktuelles Passwort:" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:136 msgid "" "You need to provide your current password to change two-factor " "authentication settings." msgstr "Du musst dein aktuelles Passwort eingeben um die Einstellungen der Zwei-Faktor-Authentifizierung zu ändern" -#: src/Module/Settings/TwoFactor/Index.php:134 +#: src/Module/Settings/TwoFactor/Index.php:137 msgid "Enable two-factor authentication" msgstr "Aktiviere die Zwei-Faktor-Authentifizierung" -#: src/Module/Settings/TwoFactor/Index.php:135 +#: src/Module/Settings/TwoFactor/Index.php:138 msgid "Disable two-factor authentication" msgstr "Deaktiviere die Zwei-Faktor-Authentifizierung" -#: src/Module/Settings/TwoFactor/Index.php:136 +#: src/Module/Settings/TwoFactor/Index.php:139 msgid "Show recovery codes" msgstr "Wiederherstellungscodes anzeigen" -#: src/Module/Settings/TwoFactor/Index.php:137 +#: src/Module/Settings/TwoFactor/Index.php:140 msgid "Manage app-specific passwords" msgstr "App spezifische Passwörter verwalten" -#: src/Module/Settings/TwoFactor/Index.php:138 +#: src/Module/Settings/TwoFactor/Index.php:141 msgid "Manage trusted browsers" msgstr "Vertrauenswürdige Browser verwalten" -#: src/Module/Settings/TwoFactor/Index.php:139 +#: src/Module/Settings/TwoFactor/Index.php:142 msgid "Finish app configuration" msgstr "Beende die App-Konfiguration" @@ -9826,34 +9875,38 @@ msgstr "Die vertrauenswürdigen Browser wurden erfolgreich entfernt." msgid "Trusted browser successfully removed." msgstr "Der vertrauenswürdige Browser erfolgreich entfernt." -#: src/Module/Settings/TwoFactor/Trusted.php:133 +#: src/Module/Settings/TwoFactor/Trusted.php:134 msgid "Two-factor Trusted Browsers" msgstr "Zwei-Faktor vertrauenswürdige Browser" -#: src/Module/Settings/TwoFactor/Trusted.php:134 +#: src/Module/Settings/TwoFactor/Trusted.php:135 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 "Vertrauenswürdige Browser sind spezielle Browser für die du entscheidest, dass die Zwei-Faktor Authentifikation übersprungen werden soll. Bitte verwende diese Option sparsam, da sie die Vorteile der 2FA aufhebt." -#: src/Module/Settings/TwoFactor/Trusted.php:135 +#: src/Module/Settings/TwoFactor/Trusted.php:136 msgid "Device" msgstr "Gerät" -#: src/Module/Settings/TwoFactor/Trusted.php:136 +#: src/Module/Settings/TwoFactor/Trusted.php:137 msgid "OS" msgstr "OS" -#: src/Module/Settings/TwoFactor/Trusted.php:138 +#: src/Module/Settings/TwoFactor/Trusted.php:139 msgid "Trusted" msgstr "Vertrauenswürdig" -#: src/Module/Settings/TwoFactor/Trusted.php:139 +#: src/Module/Settings/TwoFactor/Trusted.php:140 +msgid "Created At" +msgstr "Erstellt am" + +#: src/Module/Settings/TwoFactor/Trusted.php:141 msgid "Last Use" msgstr "Zuletzt verwendet" -#: src/Module/Settings/TwoFactor/Trusted.php:141 +#: src/Module/Settings/TwoFactor/Trusted.php:143 msgid "Remove All" msgstr "Alle entfernen" @@ -10327,206 +10380,206 @@ msgstr "%1$s hat in der Unterhaltung von %3$s kommentiert" msgid "%1$s commented on your thread %2$s" msgstr "%1$s hat in deiner Unterhaltung %2$s kommentiert" -#: src/Navigation/Notifications/Repository/Notify.php:221 -#: src/Navigation/Notifications/Repository/Notify.php:735 +#: src/Navigation/Notifications/Repository/Notify.php:222 +#: src/Navigation/Notifications/Repository/Notify.php:736 msgid "[Friendica:Notify]" msgstr "[Friendica Meldung]" -#: src/Navigation/Notifications/Repository/Notify.php:285 +#: src/Navigation/Notifications/Repository/Notify.php:286 #, php-format msgid "%s New mail received at %s" msgstr "%sNeue Nachricht auf %s empfangen" -#: src/Navigation/Notifications/Repository/Notify.php:287 +#: src/Navigation/Notifications/Repository/Notify.php:288 #, php-format msgid "%1$s sent you a new private message at %2$s." msgstr "%1$s hat dir eine neue, private Nachricht auf %2$s geschickt." -#: src/Navigation/Notifications/Repository/Notify.php:288 +#: src/Navigation/Notifications/Repository/Notify.php:289 msgid "a private message" msgstr "eine private Nachricht" -#: src/Navigation/Notifications/Repository/Notify.php:288 +#: src/Navigation/Notifications/Repository/Notify.php:289 #, php-format msgid "%1$s sent you %2$s." msgstr "%1$s schickte dir %2$s." -#: src/Navigation/Notifications/Repository/Notify.php:290 +#: src/Navigation/Notifications/Repository/Notify.php:291 #, php-format msgid "Please visit %s to view and/or reply to your private messages." msgstr "Bitte besuche %s, um Deine privaten Nachrichten anzusehen und/oder zu beantworten." -#: src/Navigation/Notifications/Repository/Notify.php:320 +#: src/Navigation/Notifications/Repository/Notify.php:321 #, php-format msgid "%1$s commented on %2$s's %3$s %4$s" msgstr "%1$s kommentierte %2$s's %3$s%4$s" -#: src/Navigation/Notifications/Repository/Notify.php:325 +#: src/Navigation/Notifications/Repository/Notify.php:326 #, php-format msgid "%1$s commented on your %2$s %3$s" msgstr "%1$s kommentierte auf (%2$s) %3$s" -#: src/Navigation/Notifications/Repository/Notify.php:329 +#: src/Navigation/Notifications/Repository/Notify.php:330 #, php-format msgid "%1$s commented on their %2$s %3$s" msgstr "%1$s hat den eigenen %2$s %3$s kommentiert" -#: src/Navigation/Notifications/Repository/Notify.php:333 -#: src/Navigation/Notifications/Repository/Notify.php:769 +#: src/Navigation/Notifications/Repository/Notify.php:334 +#: src/Navigation/Notifications/Repository/Notify.php:770 #, php-format msgid "%1$s Comment to conversation #%2$d by %3$s" msgstr "%1$sKommentar von %3$s auf Unterhaltung %2$d" -#: src/Navigation/Notifications/Repository/Notify.php:335 +#: src/Navigation/Notifications/Repository/Notify.php:336 #, php-format msgid "%s commented on an item/conversation you have been following." msgstr "%s hat einen Beitrag kommentiert, dem du folgst." -#: src/Navigation/Notifications/Repository/Notify.php:339 -#: src/Navigation/Notifications/Repository/Notify.php:354 -#: src/Navigation/Notifications/Repository/Notify.php:373 -#: src/Navigation/Notifications/Repository/Notify.php:784 +#: src/Navigation/Notifications/Repository/Notify.php:340 +#: src/Navigation/Notifications/Repository/Notify.php:355 +#: src/Navigation/Notifications/Repository/Notify.php:374 +#: src/Navigation/Notifications/Repository/Notify.php:785 #, php-format msgid "Please visit %s to view and/or reply to the conversation." msgstr "Bitte besuche %s, um die Konversation anzusehen und/oder zu kommentieren." -#: src/Navigation/Notifications/Repository/Notify.php:346 +#: src/Navigation/Notifications/Repository/Notify.php:347 #, php-format msgid "%s %s posted to your profile wall" msgstr "%s%s hat auf deine Pinnwand gepostet" -#: src/Navigation/Notifications/Repository/Notify.php:348 +#: src/Navigation/Notifications/Repository/Notify.php:349 #, php-format msgid "%1$s posted to your profile wall at %2$s" msgstr "%1$s schrieb um %2$s auf Deine Pinnwand" -#: src/Navigation/Notifications/Repository/Notify.php:349 +#: src/Navigation/Notifications/Repository/Notify.php:350 #, php-format msgid "%1$s posted to [url=%2$s]your wall[/url]" msgstr "%1$s hat etwas auf [url=%2$s]Deiner Pinnwand[/url] gepostet" -#: src/Navigation/Notifications/Repository/Notify.php:361 +#: src/Navigation/Notifications/Repository/Notify.php:362 #, php-format msgid "%1$s %2$s poked you" msgstr "%1$s%2$shat dich angestubst" -#: src/Navigation/Notifications/Repository/Notify.php:363 +#: src/Navigation/Notifications/Repository/Notify.php:364 #, php-format msgid "%1$s poked you at %2$s" msgstr "%1$s hat dich auf %2$s angestupst" -#: src/Navigation/Notifications/Repository/Notify.php:364 +#: src/Navigation/Notifications/Repository/Notify.php:365 #, php-format msgid "%1$s [url=%2$s]poked you[/url]." msgstr "%1$s [url=%2$s]hat dich angestupst[/url]." -#: src/Navigation/Notifications/Repository/Notify.php:381 +#: src/Navigation/Notifications/Repository/Notify.php:382 #, php-format msgid "%s Introduction received" msgstr "%sVorstellung erhalten" -#: src/Navigation/Notifications/Repository/Notify.php:383 +#: src/Navigation/Notifications/Repository/Notify.php:384 #, php-format msgid "You've received an introduction from '%1$s' at %2$s" msgstr "Du hast eine Kontaktanfrage von '%1$s' auf %2$s erhalten" -#: src/Navigation/Notifications/Repository/Notify.php:384 +#: src/Navigation/Notifications/Repository/Notify.php:385 #, php-format msgid "You've received [url=%1$s]an introduction[/url] from %2$s." msgstr "Du hast eine [url=%1$s]Kontaktanfrage[/url] von %2$s erhalten." -#: src/Navigation/Notifications/Repository/Notify.php:389 -#: src/Navigation/Notifications/Repository/Notify.php:435 +#: src/Navigation/Notifications/Repository/Notify.php:390 +#: src/Navigation/Notifications/Repository/Notify.php:436 #, php-format msgid "You may visit their profile at %s" msgstr "Hier kannst du das Profil betrachten: %s" -#: src/Navigation/Notifications/Repository/Notify.php:391 +#: src/Navigation/Notifications/Repository/Notify.php:392 #, php-format msgid "Please visit %s to approve or reject the introduction." msgstr "Bitte besuche %s, um die Kontaktanfrage anzunehmen oder abzulehnen." -#: src/Navigation/Notifications/Repository/Notify.php:398 +#: src/Navigation/Notifications/Repository/Notify.php:399 #, php-format msgid "%s A new person is sharing with you" msgstr "%sEine neue Person teilt nun mit dir" -#: src/Navigation/Notifications/Repository/Notify.php:400 #: src/Navigation/Notifications/Repository/Notify.php:401 +#: src/Navigation/Notifications/Repository/Notify.php:402 #, php-format msgid "%1$s is sharing with you at %2$s" msgstr "%1$s teilt mit dir auf %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:408 +#: src/Navigation/Notifications/Repository/Notify.php:409 #, php-format msgid "%s You have a new follower" msgstr "%sDu hast einen neuen Kontakt" -#: src/Navigation/Notifications/Repository/Notify.php:410 #: src/Navigation/Notifications/Repository/Notify.php:411 +#: src/Navigation/Notifications/Repository/Notify.php:412 #, php-format msgid "You have a new follower at %2$s : %1$s" msgstr "Du hast einen neuen Kontakt auf %2$s: %1$s" -#: src/Navigation/Notifications/Repository/Notify.php:424 +#: src/Navigation/Notifications/Repository/Notify.php:425 #, php-format msgid "%s Friend suggestion received" msgstr "%sKontaktvorschlag erhalten" -#: src/Navigation/Notifications/Repository/Notify.php:426 +#: src/Navigation/Notifications/Repository/Notify.php:427 #, php-format msgid "You've received a friend suggestion from '%1$s' at %2$s" msgstr "Du hast einen Kontakt-Vorschlag von '%1$s' auf %2$s erhalten" -#: src/Navigation/Notifications/Repository/Notify.php:427 +#: src/Navigation/Notifications/Repository/Notify.php:428 #, php-format msgid "" "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." msgstr "Du hast einen [url=%1$s]Kontakt-Vorschlag[/url] %2$s von %3$s erhalten." -#: src/Navigation/Notifications/Repository/Notify.php:433 +#: src/Navigation/Notifications/Repository/Notify.php:434 msgid "Name:" msgstr "Name:" -#: src/Navigation/Notifications/Repository/Notify.php:434 +#: src/Navigation/Notifications/Repository/Notify.php:435 msgid "Photo:" msgstr "Foto:" -#: src/Navigation/Notifications/Repository/Notify.php:437 +#: src/Navigation/Notifications/Repository/Notify.php:438 #, php-format msgid "Please visit %s to approve or reject the suggestion." msgstr "Bitte besuche %s, um den Vorschlag zu akzeptieren oder abzulehnen." -#: src/Navigation/Notifications/Repository/Notify.php:445 -#: src/Navigation/Notifications/Repository/Notify.php:460 +#: src/Navigation/Notifications/Repository/Notify.php:446 +#: src/Navigation/Notifications/Repository/Notify.php:461 #, php-format msgid "%s Connection accepted" msgstr "%sKontaktanfrage bestätigt" -#: src/Navigation/Notifications/Repository/Notify.php:447 -#: src/Navigation/Notifications/Repository/Notify.php:462 +#: src/Navigation/Notifications/Repository/Notify.php:448 +#: src/Navigation/Notifications/Repository/Notify.php:463 #, php-format msgid "'%1$s' has accepted your connection request at %2$s" msgstr "'%1$s' hat Deine Kontaktanfrage auf %2$s bestätigt" -#: src/Navigation/Notifications/Repository/Notify.php:448 -#: src/Navigation/Notifications/Repository/Notify.php:463 +#: src/Navigation/Notifications/Repository/Notify.php:449 +#: src/Navigation/Notifications/Repository/Notify.php:464 #, php-format msgid "%2$s has accepted your [url=%1$s]connection request[/url]." msgstr "%2$s hat Deine [url=%1$s]Kontaktanfrage[/url] akzeptiert." -#: src/Navigation/Notifications/Repository/Notify.php:453 +#: src/Navigation/Notifications/Repository/Notify.php:454 msgid "" "You are now mutual friends and may exchange status updates, photos, and " "email without restriction." msgstr "Ihr seid nun beidseitige Kontakte und könnt Statusmitteilungen, Bilder und E-Mails ohne Einschränkungen austauschen." -#: src/Navigation/Notifications/Repository/Notify.php:455 +#: src/Navigation/Notifications/Repository/Notify.php:456 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "Bitte besuche %s, wenn du Änderungen an eurer Beziehung vornehmen willst." -#: src/Navigation/Notifications/Repository/Notify.php:468 +#: src/Navigation/Notifications/Repository/Notify.php:469 #, php-format msgid "" "'%1$s' has chosen to accept you a fan, which restricts some forms of " @@ -10535,33 +10588,33 @@ msgid "" "automatically." msgstr "'%1$s' hat sich entschieden dich als Fan zu akzeptieren, dies schränkt einige Kommunikationswege - wie private Nachrichten und einige Interaktionsmöglichkeiten auf der Profilseite - ein. Wenn dies eine Berühmtheiten- oder Gemeinschaftsseite ist, werden diese Einstellungen automatisch vorgenommen." -#: src/Navigation/Notifications/Repository/Notify.php:470 +#: src/Navigation/Notifications/Repository/Notify.php:471 #, php-format msgid "" "'%1$s' may choose to extend this into a two-way or more permissive " "relationship in the future." msgstr "'%1$s' kann den Kontaktstatus zu einem späteren Zeitpunkt erweitern und diese Einschränkungen aufheben. " -#: src/Navigation/Notifications/Repository/Notify.php:472 +#: src/Navigation/Notifications/Repository/Notify.php:473 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "Bitte besuche %s, wenn du Änderungen an eurer Beziehung vornehmen willst." -#: src/Navigation/Notifications/Repository/Notify.php:482 +#: src/Navigation/Notifications/Repository/Notify.php:483 msgid "registration request" msgstr "Registrierungsanfrage" -#: src/Navigation/Notifications/Repository/Notify.php:484 +#: src/Navigation/Notifications/Repository/Notify.php:485 #, php-format msgid "You've received a registration request from '%1$s' at %2$s" msgstr "Du hast eine Registrierungsanfrage von %2$s auf '%1$s' erhalten" -#: src/Navigation/Notifications/Repository/Notify.php:485 +#: src/Navigation/Notifications/Repository/Notify.php:486 #, php-format msgid "You've received a [url=%1$s]registration request[/url] from %2$s." msgstr "Du hast eine [url=%1$s]Registrierungsanfrage[/url] von %2$s erhalten." -#: src/Navigation/Notifications/Repository/Notify.php:490 +#: src/Navigation/Notifications/Repository/Notify.php:491 #, php-format msgid "" "Full Name:\t%s\n" @@ -10569,17 +10622,17 @@ msgid "" "Login Name:\t%s (%s)" msgstr "Kompletter Name: %s\nURL der Seite: %s\nLogin Name: %s(%s)" -#: src/Navigation/Notifications/Repository/Notify.php:496 +#: src/Navigation/Notifications/Repository/Notify.php:497 #, php-format msgid "Please visit %s to approve or reject the request." msgstr "Bitte besuche %s, um die Anfrage zu bearbeiten." -#: src/Navigation/Notifications/Repository/Notify.php:763 +#: src/Navigation/Notifications/Repository/Notify.php:764 #, php-format msgid "%s %s tagged you" msgstr "%s %s hat dich erwähnt" -#: src/Navigation/Notifications/Repository/Notify.php:766 +#: src/Navigation/Notifications/Repository/Notify.php:767 #, php-format msgid "%s %s shared a new post" msgstr "%s%shat einen Beitrag geteilt" @@ -10607,244 +10660,244 @@ msgstr "Falls du diese Beiträge nicht erhalten möchtest, kontaktiere bitte den msgid "%s posted an update." msgstr "%s hat ein Update veröffentlicht." -#: src/Object/Post.php:134 +#: src/Object/Post.php:136 msgid "Private Message" msgstr "Private Nachricht" -#: src/Object/Post.php:137 +#: src/Object/Post.php:140 msgid "Public Message" msgstr "Öffentlicher Beitrag" -#: src/Object/Post.php:140 +#: src/Object/Post.php:144 msgid "Unlisted Message" msgstr "Nicht gelisteter Beitrag" -#: src/Object/Post.php:170 +#: src/Object/Post.php:179 msgid "This entry was edited" msgstr "Dieser Beitrag wurde bearbeitet." -#: src/Object/Post.php:198 +#: src/Object/Post.php:207 msgid "Connector Message" msgstr "Connector Nachricht" -#: src/Object/Post.php:213 src/Object/Post.php:215 +#: src/Object/Post.php:222 src/Object/Post.php:224 msgid "Edit" msgstr "Bearbeiten" -#: src/Object/Post.php:239 +#: src/Object/Post.php:248 msgid "Delete globally" msgstr "Global löschen" -#: src/Object/Post.php:239 +#: src/Object/Post.php:248 msgid "Remove locally" msgstr "Lokal entfernen" -#: src/Object/Post.php:255 +#: src/Object/Post.php:264 #, php-format msgid "Block %s" msgstr "Blockiere %s" -#: src/Object/Post.php:260 +#: src/Object/Post.php:269 msgid "Save to folder" msgstr "In Ordner speichern" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I will attend" msgstr "Ich werde teilnehmen" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I will not attend" msgstr "Ich werde nicht teilnehmen" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I might attend" msgstr "Ich werde eventuell teilnehmen" -#: src/Object/Post.php:324 +#: src/Object/Post.php:334 msgid "Ignore thread" msgstr "Thread ignorieren" -#: src/Object/Post.php:325 +#: src/Object/Post.php:335 msgid "Unignore thread" msgstr "Thread nicht mehr ignorieren" -#: src/Object/Post.php:326 +#: src/Object/Post.php:336 msgid "Toggle ignore status" msgstr "Ignoriert-Status ein-/ausschalten" -#: src/Object/Post.php:336 +#: src/Object/Post.php:346 msgid "Add star" msgstr "Markieren" -#: src/Object/Post.php:337 +#: src/Object/Post.php:347 msgid "Remove star" msgstr "Markierung entfernen" -#: src/Object/Post.php:338 +#: src/Object/Post.php:348 msgid "Toggle star status" msgstr "Markierung umschalten" -#: src/Object/Post.php:349 +#: src/Object/Post.php:359 msgid "Pin" msgstr "Anheften" -#: src/Object/Post.php:350 +#: src/Object/Post.php:360 msgid "Unpin" msgstr "Losmachen" -#: src/Object/Post.php:351 +#: src/Object/Post.php:361 msgid "Toggle pin status" msgstr "Angeheftet Status ändern" -#: src/Object/Post.php:354 +#: src/Object/Post.php:364 msgid "Pinned" msgstr "Angeheftet" -#: src/Object/Post.php:359 +#: src/Object/Post.php:369 msgid "Add tag" msgstr "Tag hinzufügen" -#: src/Object/Post.php:372 +#: src/Object/Post.php:382 msgid "Quote share this" msgstr "Teile und zitiere dies" -#: src/Object/Post.php:372 +#: src/Object/Post.php:382 msgid "Quote Share" msgstr "Zitat teilen" -#: src/Object/Post.php:375 +#: src/Object/Post.php:385 msgid "Reshare this" msgstr "Teile dies" -#: src/Object/Post.php:375 +#: src/Object/Post.php:385 msgid "Reshare" msgstr "Teilen" -#: src/Object/Post.php:376 +#: src/Object/Post.php:386 msgid "Cancel your Reshare" msgstr "Teilen aufheben" -#: src/Object/Post.php:376 +#: src/Object/Post.php:386 msgid "Unshare" msgstr "Nicht mehr teilen" -#: src/Object/Post.php:423 +#: src/Object/Post.php:433 #, php-format msgid "%s (Received %s)" msgstr "%s (Empfangen %s)" -#: src/Object/Post.php:428 +#: src/Object/Post.php:438 msgid "Comment this item on your system" msgstr "Kommentiere diesen Beitrag von deinem System aus" -#: src/Object/Post.php:428 +#: src/Object/Post.php:438 msgid "Remote comment" msgstr "Entfernter Kommentar" -#: src/Object/Post.php:449 +#: src/Object/Post.php:459 msgid "Share via ..." msgstr "Teile mit..." -#: src/Object/Post.php:449 +#: src/Object/Post.php:459 msgid "Share via external services" msgstr "Teile mit einem externen Dienst" -#: src/Object/Post.php:478 +#: src/Object/Post.php:488 msgid "to" msgstr "zu" -#: src/Object/Post.php:479 +#: src/Object/Post.php:489 msgid "via" msgstr "via" -#: src/Object/Post.php:480 +#: src/Object/Post.php:490 msgid "Wall-to-Wall" msgstr "Wall-to-Wall" -#: src/Object/Post.php:481 +#: src/Object/Post.php:491 msgid "via Wall-To-Wall:" msgstr "via Wall-To-Wall:" -#: src/Object/Post.php:523 +#: src/Object/Post.php:533 #, php-format msgid "Reply to %s" msgstr "Antworte %s" -#: src/Object/Post.php:526 +#: src/Object/Post.php:536 msgid "More" msgstr "Mehr" -#: src/Object/Post.php:544 +#: src/Object/Post.php:554 msgid "Notifier task is pending" msgstr "Die Benachrichtigungsaufgabe ist ausstehend" -#: src/Object/Post.php:545 +#: src/Object/Post.php:555 msgid "Delivery to remote servers is pending" msgstr "Die Auslieferung an Remote-Server steht noch aus" -#: src/Object/Post.php:546 +#: src/Object/Post.php:556 msgid "Delivery to remote servers is underway" msgstr "Die Auslieferung an Remote-Server ist unterwegs" -#: src/Object/Post.php:547 +#: src/Object/Post.php:557 msgid "Delivery to remote servers is mostly done" msgstr "Die Zustellung an Remote-Server ist fast erledigt" -#: src/Object/Post.php:548 +#: src/Object/Post.php:558 msgid "Delivery to remote servers is done" msgstr "Die Zustellung an die Remote-Server ist erledigt" -#: src/Object/Post.php:568 +#: src/Object/Post.php:578 #, php-format msgid "%d comment" msgid_plural "%d comments" msgstr[0] "%d Kommentar" msgstr[1] "%d Kommentare" -#: src/Object/Post.php:569 +#: src/Object/Post.php:579 msgid "Show more" msgstr "Zeige mehr" -#: src/Object/Post.php:570 +#: src/Object/Post.php:580 msgid "Show fewer" msgstr "Zeige weniger" -#: src/Protocol/OStatus.php:1648 +#: src/Protocol/OStatus.php:1705 #, php-format msgid "%s is now following %s." msgstr "%s folgt nun %s" -#: src/Protocol/OStatus.php:1649 +#: src/Protocol/OStatus.php:1706 msgid "following" msgstr "folgen" -#: src/Protocol/OStatus.php:1652 +#: src/Protocol/OStatus.php:1709 #, php-format msgid "%s stopped following %s." msgstr "%s hat aufgehört %s, zu folgen" -#: src/Protocol/OStatus.php:1653 +#: src/Protocol/OStatus.php:1710 msgid "stopped following" msgstr "wird nicht mehr gefolgt" -#: src/Render/FriendicaSmartyEngine.php:52 +#: src/Render/FriendicaSmartyEngine.php:65 msgid "The folder view/smarty3/ must be writable by webserver." msgstr "Das Verzeichnis view/smarty3/ muss für den Web-Server beschreibbar sein." -#: src/Security/Authentication.php:221 +#: src/Security/Authentication.php:226 msgid "Login failed." msgstr "Anmeldung fehlgeschlagen." -#: src/Security/Authentication.php:262 +#: src/Security/Authentication.php:267 msgid "Login failed. Please check your credentials." msgstr "Anmeldung fehlgeschlagen. Bitte überprüfe deine Angaben." -#: src/Security/Authentication.php:360 +#: src/Security/Authentication.php:369 #, php-format msgid "Welcome %s" msgstr "Willkommen %s" -#: src/Security/Authentication.php:361 +#: src/Security/Authentication.php:370 msgid "Please upload a profile photo." msgstr "Bitte lade ein Profilbild hoch." @@ -10942,15 +10995,15 @@ msgstr "in %1$d %2$s" msgid "%1$d %2$s ago" msgstr "%1$d %2$s her" -#: src/Worker/Delivery.php:524 +#: src/Worker/Delivery.php:525 msgid "(no subject)" msgstr "(kein Betreff)" -#: src/Worker/PushSubscription.php:103 +#: src/Worker/PushSubscription.php:112 msgid "Notification from Friendica" msgstr "Benachrichtigung von Friendica" -#: src/Worker/PushSubscription.php:104 +#: src/Worker/PushSubscription.php:113 msgid "Empty Post" msgstr "Leerer Beitrag" @@ -11096,39 +11149,39 @@ msgstr "Hintergrundfarbe der Login-Seite" msgid "Leave background image and color empty for theme defaults" msgstr "Wenn die Theme-Vorgaben verwendet werden sollen, lass bitte die Felder für die Hintergrundfarbe und das Hintergrundbild leer." -#: view/theme/frio/php/Image.php:40 +#: view/theme/frio/php/Image.php:39 msgid "Top Banner" msgstr "Top Banner" -#: view/theme/frio/php/Image.php:40 +#: 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 "Skaliere das Hintergrundbild so, dass es die Breite der Seite einnimmt, und fülle den Rest der Seite mit der Hintergrundfarbe bei langen Seiten." -#: view/theme/frio/php/Image.php:41 +#: view/theme/frio/php/Image.php:40 msgid "Full screen" msgstr "Vollbildmodus" -#: view/theme/frio/php/Image.php:41 +#: view/theme/frio/php/Image.php:40 msgid "" "Resize image to fill entire screen, clipping either the right or the bottom." msgstr "Skaliere das Bild so, dass es den gesamten Bildschirm füllt. Hierfür wird entweder die Breite oder die Höhe des Bildes automatisch abgeschnitten." -#: view/theme/frio/php/Image.php:42 +#: view/theme/frio/php/Image.php:41 msgid "Single row mosaic" msgstr "Mosaik in einer Zeile" -#: view/theme/frio/php/Image.php:42 +#: view/theme/frio/php/Image.php:41 msgid "" "Resize image to repeat it on a single row, either vertical or horizontal." msgstr "Skaliere das Bild so, dass es in einer einzelnen Reihe, entweder horizontal oder vertikal, wiederholt wird." -#: view/theme/frio/php/Image.php:43 +#: view/theme/frio/php/Image.php:42 msgid "Mosaic" msgstr "Mosaik" -#: view/theme/frio/php/Image.php:43 +#: view/theme/frio/php/Image.php:42 msgid "Repeat image to fill the screen." msgstr "Wiederhole das Bild, um den Bildschirm zu füllen." diff --git a/view/lang/de/strings.php b/view/lang/de/strings.php index 4c5f9f520f..7059b5af95 100644 --- a/view/lang/de/strings.php +++ b/view/lang/de/strings.php @@ -2147,9 +2147,19 @@ $a->strings['

You can enter one of your one-time recovery codes in case you lo $a->strings['Don’t have your phone? Enter a two-factor recovery code'] = 'Hast du dein Handy nicht? Gib einen Zwei-Faktor-Wiederherstellungscode ein'; $a->strings['Please enter a recovery code'] = 'Bitte gib einen Wiederherstellungscode ein'; $a->strings['Submit recovery code and complete login'] = 'Sende den Wiederherstellungscode und schließe die Anmeldung ab'; +$a->strings['Sign out of this browser?'] = 'Von diesem Browser abmelden?'; +$a->strings['

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

'] = '

Wenn du diesem Browser vertraust, wirst du bei zukünftigen Anmeldungen nicht nach dem Verifikationscode gefragt.

'; +$a->strings['Sign out'] = 'Abmelden'; +$a->strings['Trust and sign out'] = 'Vertrauen und Abmelden'; +$a->strings['Couldn\'t save browser to Cookie.'] = 'Konnte keine Cookies speichern.'; +$a->strings['Trust this browser?'] = 'Vertraust du diesen Browser?'; +$a->strings['

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

'] = '

Wenn du diesem Browser vertraust, wirst du bei zukünftigen Anmeldungen nicht nach dem Verifikationscode gefragt.

'; +$a->strings['Not now'] = 'Nicht jetzt'; +$a->strings['Don\'t trust'] = 'Nicht vertrauen'; +$a->strings['Trust'] = 'Vertrauen'; $a->strings['

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

'] = '

Öffne die Zwei-Faktor-Authentifizierungs-App auf deinem Gerät, um einen Authentifizierungscode abzurufen und deine Identität zu überprüfen.

'; +$a->strings['If you do not have access to your authentication code you can use a two-factor recovery code.'] = 'Wenn du keinen Zugriff auf deinen Authentifikationscode hast, kannst du einen Zwei-Faktor Wiederherstellungsschlüssel verwenden.'; $a->strings['Please enter a code from your authentication app'] = 'Bitte gebe einen Code aus Ihrer Authentifizierungs-App ein'; -$a->strings['This is my two-factor authenticator app device'] = 'Dies ist das Gerät auf dem meine 2FA Authentifizierungs-App läuft.'; $a->strings['Verify code and complete login'] = 'Code überprüfen und Anmeldung abschließen'; $a->strings['Passwords do not match.'] = 'Die Passwörter stimmen nicht überein.'; $a->strings['Password unchanged.'] = 'Passwort unverändert.'; @@ -2385,7 +2395,6 @@ $a->strings['Generate new app-specific password'] = 'Neues App spezifisches Pass $a->strings['Friendiqa on my Fairphone 2...'] = 'Friendiqa auf meinem Fairphone 2'; $a->strings['Generate'] = 'Erstellen'; $a->strings['Two-factor authentication successfully disabled.'] = 'Zwei-Faktor Authentifizierung erfolgreich deaktiviert.'; -$a->strings['Wrong Password'] = 'Falsches Passwort'; $a->strings['

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

'] = '

Benutze eine App auf deinem Smartphone um einen Zwei-Faktor Identifikationscode zu bekommen wenn beim Anmelden das verlangt wird.

'; $a->strings['Authenticator app'] = 'Zwei-Faktor Authentifizierungsapp'; $a->strings['Configured'] = 'Konfiguriert'; @@ -2419,6 +2428,7 @@ $a->strings['Trusted browsers are individual browsers you chose to skip two-fact $a->strings['Device'] = 'Gerät'; $a->strings['OS'] = 'OS'; $a->strings['Trusted'] = 'Vertrauenswürdig'; +$a->strings['Created At'] = 'Erstellt am'; $a->strings['Last Use'] = 'Zuletzt verwendet'; $a->strings['Remove All'] = 'Alle entfernen'; $a->strings['Two-factor authentication successfully activated.'] = 'Zwei-Faktor-Authentifizierung erfolgreich aktiviert.'; diff --git a/view/lang/fr/messages.po b/view/lang/fr/messages.po index 21ff4dd7f7..2e5dd1b18b 100644 --- a/view/lang/fr/messages.po +++ b/view/lang/fr/messages.po @@ -34,7 +34,7 @@ msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-06-06 07:33+0000\n" +"POT-Creation-Date: 2022-06-13 05:45+0000\n" "PO-Revision-Date: 2011-05-05 10:19+0000\n" "Last-Translator: Nicolas Derive, 2022\n" "Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n" @@ -63,7 +63,7 @@ msgstr "Accès refusé." msgid "User not found." msgstr "Utilisateur introuvable." -#: mod/cal.php:122 mod/display.php:247 src/Module/Profile/Profile.php:94 +#: mod/cal.php:122 mod/display.php:262 src/Module/Profile/Profile.php:94 #: src/Module/Profile/Profile.php:109 src/Module/Profile/Status.php:110 #: src/Module/Update/Profile.php:56 msgid "Access to this profile has been restricted." @@ -130,17 +130,17 @@ msgstr "Rien à exporter" msgid "calendar" msgstr "calendrier" -#: mod/display.php:142 mod/photos.php:802 +#: mod/display.php:143 mod/photos.php:802 #: src/Module/Conversation/Community.php:175 src/Module/Directory.php:49 #: src/Module/Search/Index.php:50 msgid "Public access denied." msgstr "Accès public refusé." -#: mod/display.php:198 mod/display.php:272 +#: mod/display.php:213 mod/display.php:287 msgid "The requested item doesn't exist or has been deleted." msgstr "L'objet recherché n'existe pas ou a été supprimé." -#: mod/display.php:352 +#: mod/display.php:367 msgid "The feed for this item is unavailable." msgstr "Le flux pour cet objet n'est pas disponible." @@ -256,7 +256,7 @@ msgstr "supp. localisation" #: mod/editpost.php:107 mod/message.php:200 mod/message.php:358 #: mod/photos.php:1489 mod/wallmessage.php:142 -#: src/Content/Conversation.php:368 src/Content/Conversation.php:712 +#: src/Content/Conversation.php:368 src/Content/Conversation.php:713 #: src/Module/Item/Compose.php:177 src/Object/Post.php:528 msgid "Please wait" msgstr "Patientez" @@ -1101,12 +1101,12 @@ msgstr "C'est vous" msgid "Comment" msgstr "Commenter" -#: mod/photos.php:1424 src/Content/Conversation.php:628 +#: mod/photos.php:1424 src/Content/Conversation.php:629 #: src/Object/Post.php:247 msgid "Select" msgstr "Sélectionner" -#: mod/photos.php:1425 mod/settings.php:350 src/Content/Conversation.php:629 +#: mod/photos.php:1425 mod/settings.php:350 src/Content/Conversation.php:630 #: src/Module/Admin/Users/Active.php:139 #: src/Module/Admin/Users/Blocked.php:140 src/Module/Admin/Users/Index.php:153 msgid "Delete" @@ -1972,7 +1972,7 @@ msgid "%s attends maybe." msgstr "%s participe peut-être" #: src/Content/Conversation.php:222 src/Content/Conversation.php:260 -#: src/Content/Conversation.php:872 +#: src/Content/Conversation.php:873 #, php-format msgid "%s reshared this." msgstr "%s a partagé ceci." @@ -2091,92 +2091,92 @@ msgstr "Vidéo" msgid "Scheduled at" msgstr "Prévu pour" -#: src/Content/Conversation.php:656 src/Object/Post.php:235 +#: src/Content/Conversation.php:657 src/Object/Post.php:235 msgid "Pinned item" msgstr "Élément épinglé" -#: src/Content/Conversation.php:672 src/Object/Post.php:476 +#: src/Content/Conversation.php:673 src/Object/Post.php:476 #: src/Object/Post.php:477 #, php-format msgid "View %s's profile @ %s" msgstr "Voir le profil de %s @ %s" -#: src/Content/Conversation.php:685 src/Object/Post.php:464 +#: src/Content/Conversation.php:686 src/Object/Post.php:464 msgid "Categories:" msgstr "Catégories :" -#: src/Content/Conversation.php:686 src/Object/Post.php:465 +#: src/Content/Conversation.php:687 src/Object/Post.php:465 msgid "Filed under:" msgstr "Rangé sous :" -#: src/Content/Conversation.php:694 src/Object/Post.php:490 +#: src/Content/Conversation.php:695 src/Object/Post.php:490 #, php-format msgid "%s from %s" msgstr "%s de %s" -#: src/Content/Conversation.php:710 +#: src/Content/Conversation.php:711 msgid "View in context" msgstr "Voir dans le contexte" -#: src/Content/Conversation.php:775 +#: src/Content/Conversation.php:776 msgid "remove" msgstr "enlever" -#: src/Content/Conversation.php:779 +#: src/Content/Conversation.php:780 msgid "Delete Selected Items" msgstr "Supprimer les éléments sélectionnés" -#: src/Content/Conversation.php:844 src/Content/Conversation.php:847 -#: src/Content/Conversation.php:850 src/Content/Conversation.php:853 +#: src/Content/Conversation.php:845 src/Content/Conversation.php:848 +#: src/Content/Conversation.php:851 src/Content/Conversation.php:854 #, php-format msgid "You had been addressed (%s)." msgstr "Vous avez été mentionné (%s)" -#: src/Content/Conversation.php:856 +#: src/Content/Conversation.php:857 #, php-format msgid "You are following %s." msgstr "Vous suivez %s." -#: src/Content/Conversation.php:859 +#: src/Content/Conversation.php:860 msgid "Tagged" msgstr "Mentionné" -#: src/Content/Conversation.php:874 +#: src/Content/Conversation.php:875 msgid "Reshared" msgstr "Partagé" -#: src/Content/Conversation.php:874 +#: src/Content/Conversation.php:875 #, php-format msgid "Reshared by %s <%s>" msgstr "Partagé par %s <%s>" -#: src/Content/Conversation.php:877 +#: src/Content/Conversation.php:878 #, php-format msgid "%s is participating in this thread." msgstr "%s participe à ce fil de discussion" -#: src/Content/Conversation.php:880 +#: src/Content/Conversation.php:881 msgid "Stored" msgstr "Enregistré" -#: src/Content/Conversation.php:883 +#: src/Content/Conversation.php:884 msgid "Global" msgstr "Global" -#: src/Content/Conversation.php:886 +#: src/Content/Conversation.php:887 msgid "Relayed" msgstr "Relayé" -#: src/Content/Conversation.php:886 +#: src/Content/Conversation.php:887 #, php-format msgid "Relayed by %s <%s>" msgstr "Relayé par %s <%s>" -#: src/Content/Conversation.php:889 +#: src/Content/Conversation.php:890 msgid "Fetched" msgstr "Récupéré" -#: src/Content/Conversation.php:889 +#: src/Content/Conversation.php:890 #, php-format msgid "Fetched because of %s <%s>" msgstr "Récupéré grâce à %s <%s>" @@ -3660,63 +3660,63 @@ msgstr "Organisation" msgid "Forum" msgstr "Forum" -#: src/Model/Contact.php:2517 +#: src/Model/Contact.php:2550 msgid "Disallowed profile URL." msgstr "URL de profil interdite." -#: src/Model/Contact.php:2522 src/Module/Friendica.php:81 +#: src/Model/Contact.php:2555 src/Module/Friendica.php:81 msgid "Blocked domain" msgstr "Domaine bloqué" -#: src/Model/Contact.php:2527 +#: src/Model/Contact.php:2560 msgid "Connect URL missing." msgstr "URL de connexion manquante." -#: src/Model/Contact.php:2536 +#: src/Model/Contact.php:2569 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "Le contact n'a pu être ajouté. Veuillez vérifier les identifiants du réseau concerné dans la page Réglages -> Réseaux Sociaux si pertinent." -#: src/Model/Contact.php:2578 +#: src/Model/Contact.php:2611 msgid "The profile address specified does not provide adequate information." msgstr "L'adresse de profil indiquée ne fournit par les informations adéquates." -#: src/Model/Contact.php:2580 +#: src/Model/Contact.php:2613 msgid "No compatible communication protocols or feeds were discovered." msgstr "Aucun protocole de communication ni aucun flux n'a pu être découvert." -#: src/Model/Contact.php:2583 +#: src/Model/Contact.php:2616 msgid "An author or name was not found." msgstr "Aucun auteur ou nom d'auteur n'a pu être trouvé." -#: src/Model/Contact.php:2586 +#: src/Model/Contact.php:2619 msgid "No browser URL could be matched to this address." msgstr "Aucune URL de navigation ne correspond à cette adresse." -#: src/Model/Contact.php:2589 +#: src/Model/Contact.php:2622 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "Impossible de faire correspondre l'adresse d'identité en \"@\" avec un protocole connu ou un contact courriel." -#: src/Model/Contact.php:2590 +#: src/Model/Contact.php:2623 msgid "Use mailto: in front of address to force email check." msgstr "Utilisez mailto: en face d'une adresse pour l'obliger à être reconnue comme courriel." -#: src/Model/Contact.php:2596 +#: src/Model/Contact.php:2629 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "L'adresse de profil spécifiée correspond à un réseau qui a été désactivé sur ce site." -#: src/Model/Contact.php:2601 +#: src/Model/Contact.php:2634 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "Profil limité. Cette personne ne sera pas capable de recevoir des notifications directes/personnelles de votre part." -#: src/Model/Contact.php:2660 +#: src/Model/Contact.php:2693 msgid "Unable to retrieve contact information." msgstr "Impossible de récupérer les informations du contact." @@ -10319,12 +10319,12 @@ msgstr "%1$s a répondu à votre commentaire %2$s" #: src/Navigation/Notifications/Factory/Notification.php:281 #, php-format msgid "%1$s commented in their thread %2$s" -msgstr "%1$s a commenté dans leur conversation %2$s" +msgstr "%1$s a commenté dans sa conversation %2$s" #: src/Navigation/Notifications/Factory/Notification.php:283 #, php-format msgid "%1$s commented in their thread" -msgstr "%1$s a commenté dans leur conversation" +msgstr "%1$s a commenté dans sa conversation" #: src/Navigation/Notifications/Factory/Notification.php:285 #, php-format diff --git a/view/lang/fr/strings.php b/view/lang/fr/strings.php index e4dbd1ca9d..5d266cc795 100644 --- a/view/lang/fr/strings.php +++ b/view/lang/fr/strings.php @@ -2563,8 +2563,8 @@ $a->strings['%1$s tagged you on %2$s'] = '%1$s vous a mentionné•e dans %2$s'; $a->strings['%1$s replied to you on %2$s'] = '%1$s vous a répondu dans %2$s'; $a->strings['%1$s commented in your thread %2$s'] = '%1$s a commenté dans votre conversation %2$s'; $a->strings['%1$s commented on your comment %2$s'] = '%1$s a répondu à votre commentaire %2$s'; -$a->strings['%1$s commented in their thread %2$s'] = '%1$s a commenté dans leur conversation %2$s'; -$a->strings['%1$s commented in their thread'] = '%1$s a commenté dans leur conversation'; +$a->strings['%1$s commented in their thread %2$s'] = '%1$s a commenté dans sa conversation %2$s'; +$a->strings['%1$s commented in their thread'] = '%1$s a commenté dans sa conversation'; $a->strings['%1$s commented in the thread %2$s from %3$s'] = '%1$s a commenté dans la conversation %2$s de %3$s'; $a->strings['%1$s commented in the thread from %3$s'] = '%1$s a commenté dans la conversation de %3$s'; $a->strings['%1$s commented on your thread %2$s'] = '%1$s a commenté dans votre conversation %2$s'; diff --git a/view/lang/pl/messages.po b/view/lang/pl/messages.po index 0dadfab0f1..b1aaeaf58d 100644 --- a/view/lang/pl/messages.po +++ b/view/lang/pl/messages.po @@ -57,7 +57,7 @@ msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-05-16 06:01+0000\n" +"POT-Creation-Date: 2022-06-25 22:37+0200\n" "PO-Revision-Date: 2011-05-05 10:19+0000\n" "Last-Translator: Piotr Strębski , 2022\n" "Language-Team: Polish (http://www.transifex.com/Friendica/friendica/language/pl/)\n" @@ -69,7 +69,7 @@ msgstr "" #: mod/cal.php:46 mod/cal.php:50 mod/follow.php:39 mod/redir.php:36 #: mod/redir.php:177 src/Module/Conversation/Community.php:181 -#: src/Module/Debug/ItemBody.php:37 src/Module/Diaspora/Receive.php:57 +#: src/Module/Debug/ItemBody.php:38 src/Module/Diaspora/Receive.php:57 #: src/Module/Item/Follow.php:42 src/Module/Item/Ignore.php:41 #: src/Module/Item/Pin.php:42 src/Module/Item/Pin.php:57 #: src/Module/Item/Star.php:43 @@ -77,7 +77,7 @@ msgid "Access denied." msgstr "Brak dostępu." #: mod/cal.php:63 mod/cal.php:80 mod/photos.php:69 mod/photos.php:140 -#: mod/photos.php:804 src/Model/Profile.php:231 src/Module/Feed.php:72 +#: mod/photos.php:798 src/Model/Profile.php:232 src/Module/Feed.php:72 #: src/Module/HCard.php:52 src/Module/Profile/Common.php:41 #: src/Module/Profile/Common.php:52 src/Module/Profile/Contacts.php:40 #: src/Module/Profile/Contacts.php:50 src/Module/Profile/Media.php:38 @@ -86,7 +86,7 @@ msgstr "Brak dostępu." msgid "User not found." msgstr "Użytkownik nie znaleziony." -#: mod/cal.php:122 mod/display.php:240 src/Module/Profile/Profile.php:94 +#: mod/cal.php:122 mod/display.php:262 src/Module/Profile/Profile.php:94 #: src/Module/Profile/Profile.php:109 src/Module/Profile/Status.php:110 #: src/Module/Update/Profile.php:56 msgid "Access to this profile has been restricted." @@ -111,21 +111,21 @@ msgstr "Poprzedni" msgid "Next" msgstr "Następny" -#: mod/cal.php:249 mod/events.php:383 src/Model/Event.php:457 +#: mod/cal.php:249 mod/events.php:383 src/Model/Event.php:456 msgid "today" msgstr "dzisiaj" -#: mod/cal.php:250 mod/events.php:384 src/Model/Event.php:458 +#: mod/cal.php:250 mod/events.php:384 src/Model/Event.php:457 #: src/Util/Temporal.php:334 msgid "month" msgstr "miesiąc" -#: mod/cal.php:251 mod/events.php:385 src/Model/Event.php:459 +#: mod/cal.php:251 mod/events.php:385 src/Model/Event.php:458 #: src/Util/Temporal.php:335 msgid "week" msgstr "tydzień" -#: mod/cal.php:252 mod/events.php:386 src/Model/Event.php:460 +#: mod/cal.php:252 mod/events.php:386 src/Model/Event.php:459 #: src/Util/Temporal.php:336 msgid "day" msgstr "dzień" @@ -153,30 +153,30 @@ msgstr "Nie znaleziono danych do eksportu" msgid "calendar" msgstr "kalendarz" -#: mod/display.php:135 mod/photos.php:808 +#: mod/display.php:143 mod/photos.php:802 #: src/Module/Conversation/Community.php:175 src/Module/Directory.php:49 -#: src/Module/Search/Index.php:50 +#: src/Module/Search/Index.php:65 msgid "Public access denied." msgstr "Publiczny dostęp zabroniony." -#: mod/display.php:191 mod/display.php:265 +#: mod/display.php:213 mod/display.php:287 msgid "The requested item doesn't exist or has been deleted." msgstr "Żądany element nie istnieje lub został usunięty." -#: mod/display.php:345 +#: mod/display.php:367 msgid "The feed for this item is unavailable." msgstr "Kanał dla tego elementu jest niedostępny." #: mod/editpost.php:38 mod/events.php:217 mod/follow.php:56 mod/follow.php:130 -#: mod/item.php:181 mod/item.php:186 mod/item.php:873 mod/message.php:69 +#: mod/item.php:181 mod/item.php:186 mod/item.php:875 mod/message.php:69 #: mod/message.php:111 mod/notes.php:44 mod/ostatus_subscribe.php:33 -#: mod/photos.php:160 mod/photos.php:897 mod/repair_ostatus.php:31 -#: mod/settings.php:49 mod/settings.php:59 mod/settings.php:165 +#: mod/photos.php:160 mod/photos.php:891 mod/repair_ostatus.php:31 +#: mod/settings.php:40 mod/settings.php:50 mod/settings.php:156 #: mod/suggest.php:34 mod/uimport.php:33 mod/unfollow.php:35 #: mod/unfollow.php:50 mod/unfollow.php:82 mod/wall_attach.php:67 #: mod/wall_attach.php:69 mod/wall_upload.php:89 mod/wall_upload.php:91 #: mod/wallmessage.php:37 mod/wallmessage.php:56 mod/wallmessage.php:90 -#: mod/wallmessage.php:110 src/Module/Attach.php:55 src/Module/BaseApi.php:93 +#: mod/wallmessage.php:110 src/Module/Attach.php:56 src/Module/BaseApi.php:93 #: src/Module/BaseNotifications.php:97 src/Module/Contact/Advanced.php:60 #: src/Module/Delegation.php:119 src/Module/FollowConfirm.php:38 #: src/Module/FriendSuggest.php:56 src/Module/Group.php:42 @@ -187,13 +187,13 @@ msgstr "Kanał dla tego elementu jest niedostępny." #: src/Module/Profile/Schedule.php:39 src/Module/Profile/Schedule.php:56 #: 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:48 -#: src/Module/Settings/Account.php:384 src/Module/Settings/Delegation.php:42 +#: src/Module/Search/Directory.php:37 src/Module/Settings/Account.php:49 +#: src/Module/Settings/Account.php:409 src/Module/Settings/Delegation.php:42 #: src/Module/Settings/Delegation.php:70 src/Module/Settings/Display.php:42 #: src/Module/Settings/Display.php:120 #: src/Module/Settings/Profile/Photo/Crop.php:166 #: src/Module/Settings/Profile/Photo/Index.php:112 -#: src/Module/Settings/UserExport.php:57 src/Module/Settings/UserExport.php:91 +#: src/Module/Settings/UserExport.php:58 src/Module/Settings/UserExport.php:92 #: src/Module/Settings/UserExport.php:196 #: src/Module/Settings/UserExport.php:216 #: src/Module/Settings/UserExport.php:281 @@ -208,30 +208,30 @@ msgstr "Nie znaleziono elementu" msgid "Edit post" msgstr "Edytuj wpis" -#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:875 +#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:882 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:73 msgid "Save" msgstr "Zapisz" -#: mod/editpost.php:92 mod/photos.php:1344 src/Content/Conversation.php:340 -#: src/Module/Contact/Poke.php:176 src/Object/Post.php:989 +#: mod/editpost.php:92 mod/photos.php:1338 src/Content/Conversation.php:338 +#: src/Module/Contact/Poke.php:176 src/Object/Post.php:993 msgid "Loading..." msgstr "Wczytywanie..." #: mod/editpost.php:93 mod/message.php:198 mod/message.php:355 -#: mod/wallmessage.php:140 src/Content/Conversation.php:341 +#: mod/wallmessage.php:140 src/Content/Conversation.php:339 msgid "Upload photo" msgstr "Wyślij zdjęcie" -#: mod/editpost.php:94 src/Content/Conversation.php:342 +#: mod/editpost.php:94 src/Content/Conversation.php:340 msgid "upload photo" msgstr "wyślij zdjęcie" -#: mod/editpost.php:95 src/Content/Conversation.php:343 +#: mod/editpost.php:95 src/Content/Conversation.php:341 msgid "Attach file" msgstr "Załącz plik" -#: mod/editpost.php:96 src/Content/Conversation.php:344 +#: mod/editpost.php:96 src/Content/Conversation.php:342 msgid "attach file" msgstr "załącz plik" @@ -260,31 +260,31 @@ msgstr "Wstaw link do audio" msgid "audio link" msgstr "link do audio" -#: mod/editpost.php:103 src/Content/Conversation.php:354 +#: mod/editpost.php:103 src/Content/Conversation.php:352 #: src/Module/Item/Compose.php:173 msgid "Set your location" msgstr "Ustaw swoją lokalizację" -#: mod/editpost.php:104 src/Content/Conversation.php:355 +#: mod/editpost.php:104 src/Content/Conversation.php:353 msgid "set location" msgstr "wybierz lokalizację" -#: mod/editpost.php:105 src/Content/Conversation.php:356 +#: mod/editpost.php:105 src/Content/Conversation.php:354 msgid "Clear browser location" msgstr "Wyczyść lokalizację przeglądarki" -#: mod/editpost.php:106 src/Content/Conversation.php:357 +#: mod/editpost.php:106 src/Content/Conversation.php:355 msgid "clear location" msgstr "wyczyść lokalizację" #: mod/editpost.php:107 mod/message.php:200 mod/message.php:358 -#: mod/photos.php:1495 mod/wallmessage.php:142 -#: src/Content/Conversation.php:370 src/Content/Conversation.php:714 -#: src/Module/Item/Compose.php:177 src/Object/Post.php:528 +#: mod/photos.php:1489 mod/wallmessage.php:142 +#: src/Content/Conversation.php:368 src/Content/Conversation.php:713 +#: src/Module/Item/Compose.php:177 src/Object/Post.php:538 msgid "Please wait" msgstr "Proszę czekać" -#: mod/editpost.php:108 src/Content/Conversation.php:371 +#: mod/editpost.php:108 src/Content/Conversation.php:369 msgid "Permission settings" msgstr "Ustawienia uprawnień" @@ -292,16 +292,16 @@ msgstr "Ustawienia uprawnień" msgid "CC: email addresses" msgstr "DW: adresy e-mail" -#: mod/editpost.php:117 src/Content/Conversation.php:381 +#: mod/editpost.php:117 src/Content/Conversation.php:379 msgid "Public post" msgstr "Publiczny wpis" -#: mod/editpost.php:120 src/Content/Conversation.php:359 +#: mod/editpost.php:120 src/Content/Conversation.php:357 #: src/Module/Item/Compose.php:178 msgid "Set title" msgstr "Podaj tytuł" -#: mod/editpost.php:122 src/Content/Conversation.php:361 +#: mod/editpost.php:122 src/Content/Conversation.php:359 #: src/Module/Item/Compose.php:179 msgid "Categories (comma-separated list)" msgstr "Kategorie (lista słów oddzielonych przecinkiem)" @@ -310,71 +310,72 @@ msgstr "Kategorie (lista słów oddzielonych przecinkiem)" msgid "Example: bob@example.com, mary@example.com" msgstr "Przykład: bob@example.com, mary@example.com" -#: mod/editpost.php:128 mod/events.php:513 mod/photos.php:1343 -#: mod/photos.php:1399 mod/photos.php:1473 src/Content/Conversation.php:385 -#: src/Module/Item/Compose.php:172 src/Object/Post.php:999 +#: mod/editpost.php:128 mod/events.php:513 mod/photos.php:1337 +#: mod/photos.php:1393 mod/photos.php:1467 src/Content/Conversation.php:383 +#: src/Module/Item/Compose.php:172 src/Object/Post.php:1003 msgid "Preview" msgstr "Podgląd" #: mod/editpost.php:130 mod/fbrowser.php:118 mod/fbrowser.php:145 -#: mod/follow.php:144 mod/photos.php:1010 mod/photos.php:1111 mod/tagrm.php:35 -#: mod/tagrm.php:127 mod/unfollow.php:97 src/Content/Conversation.php:388 +#: mod/follow.php:144 mod/photos.php:1004 mod/photos.php:1105 mod/tagrm.php:35 +#: mod/tagrm.php:127 mod/unfollow.php:97 src/Content/Conversation.php:386 #: src/Module/Contact/Revoke.php:108 src/Module/RemoteFollow.php:127 +#: src/Module/Security/TwoFactor/Signout.php:125 msgid "Cancel" msgstr "Anuluj" -#: mod/editpost.php:134 src/Content/Conversation.php:345 -#: src/Module/Item/Compose.php:163 src/Object/Post.php:990 +#: mod/editpost.php:134 src/Content/Conversation.php:343 +#: src/Module/Item/Compose.php:163 src/Object/Post.php:994 msgid "Bold" msgstr "Pogrubienie" -#: mod/editpost.php:135 src/Content/Conversation.php:346 -#: src/Module/Item/Compose.php:164 src/Object/Post.php:991 +#: mod/editpost.php:135 src/Content/Conversation.php:344 +#: src/Module/Item/Compose.php:164 src/Object/Post.php:995 msgid "Italic" msgstr "Kursywa" -#: mod/editpost.php:136 src/Content/Conversation.php:347 -#: src/Module/Item/Compose.php:165 src/Object/Post.php:992 +#: mod/editpost.php:136 src/Content/Conversation.php:345 +#: src/Module/Item/Compose.php:165 src/Object/Post.php:996 msgid "Underline" msgstr "Podkreślenie" -#: mod/editpost.php:137 src/Content/Conversation.php:348 -#: src/Module/Item/Compose.php:166 src/Object/Post.php:993 +#: mod/editpost.php:137 src/Content/Conversation.php:346 +#: src/Module/Item/Compose.php:166 src/Object/Post.php:997 msgid "Quote" msgstr "Cytat" -#: mod/editpost.php:138 src/Content/Conversation.php:349 -#: src/Module/Item/Compose.php:167 src/Object/Post.php:994 +#: mod/editpost.php:138 src/Content/Conversation.php:347 +#: src/Module/Item/Compose.php:167 src/Object/Post.php:998 msgid "Code" msgstr "Kod" -#: mod/editpost.php:139 src/Content/Conversation.php:351 -#: src/Module/Item/Compose.php:169 src/Object/Post.php:996 +#: mod/editpost.php:139 src/Content/Conversation.php:349 +#: src/Module/Item/Compose.php:169 src/Object/Post.php:1000 msgid "Link" msgstr "Odnośnik" -#: mod/editpost.php:140 src/Content/Conversation.php:352 -#: src/Module/Item/Compose.php:170 src/Object/Post.php:997 +#: mod/editpost.php:140 src/Content/Conversation.php:350 +#: src/Module/Item/Compose.php:170 src/Object/Post.php:1001 msgid "Link or Media" msgstr "Odnośnik lub Media" -#: mod/editpost.php:143 src/Content/Conversation.php:395 -#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:462 +#: mod/editpost.php:143 src/Content/Conversation.php:393 +#: src/Content/Widget/VCard.php:113 src/Model/Profile.php:463 #: src/Module/Admin/Logs/View.php:93 msgid "Message" msgstr "Wiadomość" -#: mod/editpost.php:144 src/Content/Conversation.php:396 -#: src/Module/Settings/TwoFactor/Trusted.php:137 +#: mod/editpost.php:144 src/Content/Conversation.php:394 +#: src/Module/Settings/TwoFactor/Trusted.php:138 msgid "Browser" msgstr "Przeglądarka" -#: mod/editpost.php:145 mod/events.php:518 mod/photos.php:945 -#: mod/photos.php:1297 src/Content/Conversation.php:372 +#: mod/editpost.php:145 mod/events.php:518 mod/photos.php:939 +#: mod/photos.php:1291 src/Content/Conversation.php:370 msgid "Permissions" msgstr "Uprawnienia" -#: mod/editpost.php:147 src/Content/Conversation.php:398 +#: mod/editpost.php:147 src/Content/Conversation.php:396 msgid "Open Compose page" msgstr "Otwórz stronę Redagowanie" @@ -415,8 +416,8 @@ msgstr "Rozpoczęcie wydarzenia:" #: src/Module/Install.php:286 src/Module/Install.php:291 #: src/Module/Install.php:305 src/Module/Install.php:320 #: src/Module/Install.php:347 src/Module/Register.php:148 -#: src/Module/Security/TwoFactor/Verify.php:100 -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Security/TwoFactor/Verify.php:101 +#: src/Module/Settings/TwoFactor/Index.php:136 #: src/Module/Settings/TwoFactor/Verify.php:154 msgid "Required" msgstr "Wymagany" @@ -434,9 +435,9 @@ msgstr "Zakończenie wydarzenia:" msgid "Description:" msgstr "Opis:" -#: mod/events.php:504 src/Content/Widget/VCard.php:98 src/Model/Event.php:80 -#: src/Model/Event.php:107 src/Model/Event.php:466 src/Model/Event.php:915 -#: src/Model/Profile.php:370 src/Module/Contact/Profile.php:369 +#: mod/events.php:504 src/Content/Widget/VCard.php:104 src/Model/Event.php:80 +#: src/Model/Event.php:107 src/Model/Event.php:465 src/Model/Event.php:915 +#: src/Model/Profile.php:371 src/Module/Contact/Profile.php:369 #: src/Module/Directory.php:148 src/Module/Notifications/Introductions.php:185 #: src/Module/Profile/Profile.php:194 msgid "Location:" @@ -451,8 +452,8 @@ msgid "Share this event" msgstr "Udostępnij te wydarzenie" #: mod/events.php:515 mod/message.php:201 mod/message.php:357 -#: mod/photos.php:927 mod/photos.php:1031 mod/photos.php:1301 -#: mod/photos.php:1342 mod/photos.php:1398 mod/photos.php:1472 +#: mod/photos.php:921 mod/photos.php:1025 mod/photos.php:1295 +#: mod/photos.php:1336 mod/photos.php:1392 mod/photos.php:1466 #: src/Module/Admin/Item/Source.php:65 src/Module/Contact/Advanced.php:132 #: src/Module/Contact/Poke.php:177 src/Module/Contact/Profile.php:327 #: src/Module/Debug/ActivityPubConversion.php:145 @@ -462,7 +463,7 @@ msgstr "Udostępnij te wydarzenie" #: src/Module/Install.php:252 src/Module/Install.php:294 #: src/Module/Install.php:331 src/Module/Invite.php:178 #: src/Module/Item/Compose.php:162 src/Module/Profile/Profile.php:247 -#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:988 +#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:992 #: view/theme/duepuntozero/config.php:69 view/theme/frio/config.php:160 #: view/theme/quattro/config.php:71 view/theme/vier/config.php:119 msgid "Submit" @@ -472,7 +473,7 @@ msgstr "Potwierdź" msgid "Basic" msgstr "Podstawowy" -#: mod/events.php:517 src/Module/Admin/Site.php:506 src/Module/Contact.php:474 +#: mod/events.php:517 src/Module/Admin/Site.php:439 src/Module/Contact.php:474 #: src/Module/Profile/Profile.php:249 msgid "Advanced" msgstr "Zaawansowany" @@ -515,8 +516,8 @@ msgstr "Obsługa Diaspory nie jest włączona. Kontakt nie może zostać dodany. msgid "OStatus support is disabled. Contact can't be added." msgstr "Obsługa OStatus jest wyłączona. Kontakt nie może zostać dodany." -#: mod/follow.php:138 src/Content/Item.php:443 src/Content/Widget.php:78 -#: src/Model/Contact.php:1088 src/Model/Contact.php:1100 +#: mod/follow.php:138 src/Content/Item.php:443 src/Content/Widget.php:80 +#: src/Model/Contact.php:1103 src/Model/Contact.php:1115 #: view/theme/vier/theme.php:172 msgid "Connect/Follow" msgstr "Połącz/Obserwuj" @@ -569,21 +570,21 @@ msgstr "Nie można zlokalizować oryginalnej wiadomości." msgid "Empty post discarded." msgstr "Pusty wpis został odrzucony." -#: mod/item.php:685 +#: mod/item.php:687 msgid "Post updated." msgstr "Wpis zaktualizowany." -#: mod/item.php:695 mod/item.php:700 +#: mod/item.php:697 mod/item.php:702 msgid "Item wasn't stored." msgstr "Element nie został zapisany. " -#: mod/item.php:711 +#: mod/item.php:713 msgid "Item couldn't be fetched." msgstr "Nie można pobrać elementu." -#: mod/item.php:851 src/Module/Admin/Themes/Details.php:39 -#: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:41 -#: src/Module/Debug/ItemBody.php:56 +#: mod/item.php:853 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 msgid "Item not found." msgstr "Element nie znaleziony." @@ -910,11 +911,11 @@ msgstr "Pozostaw to okno otwarte, dopóki nie będzie gotowe." msgid "Photo Albums" msgstr "Albumy zdjęć" -#: mod/photos.php:109 mod/photos.php:1590 +#: mod/photos.php:109 mod/photos.php:1584 msgid "Recent Photos" msgstr "Ostatnio dodane zdjęcia" -#: mod/photos.php:111 mod/photos.php:1079 mod/photos.php:1592 +#: mod/photos.php:111 mod/photos.php:1073 mod/photos.php:1586 msgid "Upload New Photos" msgstr "Wyślij nowe zdjęcie" @@ -942,221 +943,221 @@ msgstr "Album był pusty." msgid "Failed to delete the photo." msgstr "Błąd usunięcia zdjęcia." -#: mod/photos.php:559 +#: mod/photos.php:553 msgid "a photo" msgstr "zdjęcie" -#: mod/photos.php:559 +#: mod/photos.php:553 #, php-format msgid "%1$s was tagged in %2$s by %3$s" msgstr "%1$szostał oznaczony znacznikiem %2$s przez %3$s" -#: mod/photos.php:642 mod/photos.php:645 mod/photos.php:672 +#: mod/photos.php:636 mod/photos.php:639 mod/photos.php:666 #: mod/wall_upload.php:201 src/Module/Settings/Profile/Photo/Index.php:60 #, php-format msgid "Image exceeds size limit of %s" msgstr "Obraz przekracza limit rozmiaru wynoszący %s" -#: mod/photos.php:648 +#: mod/photos.php:642 msgid "Image upload didn't complete, please try again" msgstr "Przesyłanie zdjęć nie zostało zakończone, spróbuj ponownie" -#: mod/photos.php:651 +#: mod/photos.php:645 msgid "Image file is missing" msgstr "Brak pliku obrazu" -#: mod/photos.php:656 +#: mod/photos.php:650 msgid "" "Server can't accept new file upload at this time, please contact your " "administrator" msgstr "Serwer nie może teraz przyjąć nowego pliku, skontaktuj się z administratorem" -#: mod/photos.php:680 +#: mod/photos.php:674 msgid "Image file is empty." msgstr "Plik obrazka jest pusty." -#: mod/photos.php:695 mod/wall_upload.php:163 +#: mod/photos.php:689 mod/wall_upload.php:163 #: src/Module/Settings/Profile/Photo/Index.php:69 msgid "Unable to process image." msgstr "Przetwarzanie obrazu nie powiodło się." -#: mod/photos.php:721 mod/wall_upload.php:226 +#: mod/photos.php:715 mod/wall_upload.php:226 #: src/Module/Settings/Profile/Photo/Index.php:96 msgid "Image upload failed." msgstr "Przesyłanie obrazu nie powiodło się." -#: mod/photos.php:813 +#: mod/photos.php:807 msgid "No photos selected" msgstr "Nie zaznaczono zdjęć" -#: mod/photos.php:882 +#: mod/photos.php:876 msgid "Access to this item is restricted." msgstr "Dostęp do tego obiektu jest ograniczony." -#: mod/photos.php:937 +#: mod/photos.php:931 msgid "Upload Photos" msgstr "Prześlij zdjęcia" -#: mod/photos.php:941 mod/photos.php:1027 +#: mod/photos.php:935 mod/photos.php:1021 msgid "New album name: " msgstr "Nazwa nowego albumu: " -#: mod/photos.php:942 +#: mod/photos.php:936 msgid "or select existing album:" msgstr "lub wybierz istniejący album:" -#: mod/photos.php:943 +#: mod/photos.php:937 msgid "Do not show a status post for this upload" msgstr "Nie pokazuj stanu wpisów dla tego wysłania" -#: mod/photos.php:1008 +#: mod/photos.php:1002 msgid "Do you really want to delete this photo album and all its photos?" msgstr "Czy na pewno chcesz usunąć ten album i wszystkie zdjęcia z tego albumu?" -#: mod/photos.php:1009 mod/photos.php:1032 +#: mod/photos.php:1003 mod/photos.php:1026 msgid "Delete Album" msgstr "Usuń album" -#: mod/photos.php:1036 +#: mod/photos.php:1030 msgid "Edit Album" msgstr "Edytuj album" -#: mod/photos.php:1037 +#: mod/photos.php:1031 msgid "Drop Album" msgstr "Upuść Album" -#: mod/photos.php:1041 +#: mod/photos.php:1035 msgid "Show Newest First" msgstr "Pokaż najpierw najnowsze" -#: mod/photos.php:1043 +#: mod/photos.php:1037 msgid "Show Oldest First" msgstr "Pokaż najpierw najstarsze" -#: mod/photos.php:1064 mod/photos.php:1575 +#: mod/photos.php:1058 mod/photos.php:1569 msgid "View Photo" msgstr "Zobacz zdjęcie" -#: mod/photos.php:1097 +#: mod/photos.php:1091 msgid "Permission denied. Access to this item may be restricted." msgstr "Odmowa dostępu. Dostęp do tych danych może być ograniczony." -#: mod/photos.php:1099 +#: mod/photos.php:1093 msgid "Photo not available" msgstr "Zdjęcie niedostępne" -#: mod/photos.php:1109 +#: mod/photos.php:1103 msgid "Do you really want to delete this photo?" msgstr "Czy na pewno chcesz usunąć to zdjęcie ?" -#: mod/photos.php:1110 mod/photos.php:1302 +#: mod/photos.php:1104 mod/photos.php:1296 msgid "Delete Photo" msgstr "Usuń zdjęcie" -#: mod/photos.php:1200 +#: mod/photos.php:1196 msgid "View photo" msgstr "Zobacz zdjęcie" -#: mod/photos.php:1202 +#: mod/photos.php:1198 msgid "Edit photo" msgstr "Edytuj zdjęcie" -#: mod/photos.php:1203 +#: mod/photos.php:1199 msgid "Delete photo" msgstr "Usuń zdjęcie" -#: mod/photos.php:1204 +#: mod/photos.php:1200 msgid "Use as profile photo" msgstr "Ustaw jako zdjęcie profilowe" -#: mod/photos.php:1211 +#: mod/photos.php:1207 msgid "Private Photo" msgstr "Prywatne zdjęcie" -#: mod/photos.php:1217 +#: mod/photos.php:1213 msgid "View Full Size" msgstr "Zobacz w pełnym rozmiarze" -#: mod/photos.php:1270 +#: mod/photos.php:1264 msgid "Tags: " msgstr "Znaczniki: " -#: mod/photos.php:1273 +#: mod/photos.php:1267 msgid "[Select tags to remove]" msgstr "[Wybierz znaczniki do usunięcia]" -#: mod/photos.php:1288 +#: mod/photos.php:1282 msgid "New album name" msgstr "Nazwa nowego albumu" -#: mod/photos.php:1289 +#: mod/photos.php:1283 msgid "Caption" msgstr "Zawartość" -#: mod/photos.php:1290 +#: mod/photos.php:1284 msgid "Add a Tag" msgstr "Dodaj znacznik" -#: mod/photos.php:1290 +#: mod/photos.php:1284 msgid "" "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" msgstr "Przykładowo: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" -#: mod/photos.php:1291 +#: mod/photos.php:1285 msgid "Do not rotate" msgstr "Nie obracaj" -#: mod/photos.php:1292 +#: mod/photos.php:1286 msgid "Rotate CW (right)" msgstr "Obróć zgodnie z kierunkiem wskazówek zegara (w prawo)" -#: mod/photos.php:1293 +#: mod/photos.php:1287 msgid "Rotate CCW (left)" msgstr "Obróć w przeciwnym kierunku do ruchu wskazówek zegara (w lewo)" -#: mod/photos.php:1339 mod/photos.php:1395 mod/photos.php:1469 +#: mod/photos.php:1333 mod/photos.php:1389 mod/photos.php:1463 #: src/Module/Contact.php:544 src/Module/Item/Compose.php:160 -#: src/Object/Post.php:985 +#: src/Object/Post.php:989 msgid "This is you" msgstr "To jesteś Ty" -#: mod/photos.php:1341 mod/photos.php:1397 mod/photos.php:1471 -#: src/Object/Post.php:522 src/Object/Post.php:987 +#: mod/photos.php:1335 mod/photos.php:1391 mod/photos.php:1465 +#: src/Object/Post.php:532 src/Object/Post.php:991 msgid "Comment" msgstr "Komentarz" -#: mod/photos.php:1430 src/Content/Conversation.php:630 -#: src/Object/Post.php:247 +#: mod/photos.php:1424 src/Content/Conversation.php:629 +#: src/Object/Post.php:256 msgid "Select" msgstr "Wybierz" -#: mod/photos.php:1431 mod/settings.php:359 src/Content/Conversation.php:631 +#: mod/photos.php:1425 mod/settings.php:350 src/Content/Conversation.php:630 #: src/Module/Admin/Users/Active.php:139 #: src/Module/Admin/Users/Blocked.php:140 src/Module/Admin/Users/Index.php:153 msgid "Delete" msgstr "Usuń" -#: mod/photos.php:1492 src/Object/Post.php:369 +#: mod/photos.php:1486 src/Object/Post.php:379 msgid "Like" msgstr "Lubię" -#: mod/photos.php:1493 src/Object/Post.php:369 +#: mod/photos.php:1487 src/Object/Post.php:379 msgid "I like this (toggle)" msgstr "Lubię to (zmień)" -#: mod/photos.php:1494 src/Object/Post.php:370 +#: mod/photos.php:1488 src/Object/Post.php:380 msgid "Dislike" msgstr "Nie lubię" -#: mod/photos.php:1496 src/Object/Post.php:370 +#: mod/photos.php:1490 src/Object/Post.php:380 msgid "I don't like this (toggle)" msgstr "Nie lubię tego (zmień)" -#: mod/photos.php:1518 +#: mod/photos.php:1512 msgid "Map" msgstr "Mapa" -#: mod/photos.php:1581 +#: mod/photos.php:1575 msgid "View Album" msgstr "Zobacz album" @@ -1177,36 +1178,36 @@ msgstr "Błędne zapytanie." msgid "Contact not found." msgstr "Nie znaleziono kontaktu." -#: mod/removeme.php:63 src/Navigation/Notifications/Repository/Notify.php:476 +#: mod/removeme.php:65 src/Navigation/Notifications/Repository/Notify.php:483 msgid "[Friendica System Notify]" msgstr "[Powiadomienie Systemu Friendica]" -#: mod/removeme.php:63 +#: mod/removeme.php:65 msgid "User deleted their account" msgstr "Użytkownik usunął swoje konto" -#: mod/removeme.php:64 +#: mod/removeme.php:66 msgid "" "On your Friendica node an user deleted their account. Please ensure that " "their data is removed from the backups." msgstr "W twoim węźle Friendica użytkownik usunął swoje konto. Upewnij się, że ich dane zostały usunięte z kopii zapasowych." -#: mod/removeme.php:65 +#: mod/removeme.php:67 #, php-format msgid "The user id is %d" msgstr "Identyfikatorem użytkownika jest %d" -#: mod/removeme.php:99 mod/removeme.php:102 +#: mod/removeme.php:101 mod/removeme.php:104 msgid "Remove My Account" msgstr "Usuń moje konto" -#: mod/removeme.php:100 +#: mod/removeme.php:102 msgid "" "This will completely remove your account. Once this has been done it is not " "recoverable." msgstr "Spowoduje to całkowite usunięcie Twojego konta. Po wykonaniu tej czynności nie można jej cofnąć." -#: mod/removeme.php:101 +#: mod/removeme.php:103 msgid "Please enter your password for verification:" msgstr "Wprowadź hasło w celu weryfikacji:" @@ -1215,7 +1216,7 @@ msgid "Resubscribing to OStatus contacts" msgstr "Ponowne subskrybowanie kontaktów OStatus" #: mod/repair_ostatus.php:46 src/Module/Debug/ActivityPubConversion.php:134 -#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:97 +#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:98 msgid "Error" msgid_plural "Errors" msgstr[0] "Błąd" @@ -1223,15 +1224,15 @@ msgstr[1] "Błędów" msgstr[2] "Błędy" msgstr[3] "Błędów" -#: mod/settings.php:131 +#: mod/settings.php:122 msgid "Failed to connect with email account using the settings provided." msgstr "Połączenie z kontem email używając wybranych ustawień nie powiodło się." -#: mod/settings.php:184 +#: mod/settings.php:175 msgid "Connected Apps" msgstr "Powiązane aplikacje" -#: mod/settings.php:185 src/Module/Admin/Blocklist/Contact.php:106 +#: mod/settings.php:176 src/Module/Admin/Blocklist/Contact.php:106 #: src/Module/Admin/Users/Active.php:129 #: src/Module/Admin/Users/Blocked.php:130 src/Module/Admin/Users/Create.php:71 #: src/Module/Admin/Users/Deleted.php:88 src/Module/Admin/Users/Index.php:142 @@ -1240,104 +1241,104 @@ msgstr "Powiązane aplikacje" msgid "Name" msgstr "Nazwa" -#: mod/settings.php:186 src/Content/Nav.php:212 +#: mod/settings.php:177 src/Content/Nav.php:212 msgid "Home Page" msgstr "Strona startowa" -#: mod/settings.php:187 src/Module/Admin/Queue.php:78 +#: mod/settings.php:178 src/Module/Admin/Queue.php:78 msgid "Created" msgstr "Utwórz" -#: mod/settings.php:188 +#: mod/settings.php:179 msgid "Remove authorization" msgstr "Odwołaj upoważnienie" -#: mod/settings.php:214 mod/settings.php:246 mod/settings.php:277 -#: mod/settings.php:361 src/Module/Admin/Addons/Index.php:69 +#: mod/settings.php:205 mod/settings.php:237 mod/settings.php:268 +#: mod/settings.php:352 src/Module/Admin/Addons/Index.php:69 #: src/Module/Admin/Features.php:87 src/Module/Admin/Logs/Settings.php:81 -#: src/Module/Admin/Site.php:501 src/Module/Admin/Themes/Index.php:113 -#: src/Module/Admin/Tos.php:83 src/Module/Settings/Account.php:532 +#: src/Module/Admin/Site.php:434 src/Module/Admin/Themes/Index.php:113 +#: src/Module/Admin/Tos.php:83 src/Module/Settings/Account.php:559 #: src/Module/Settings/Delegation.php:170 src/Module/Settings/Display.php:193 msgid "Save Settings" msgstr "Zapisz ustawienia" -#: mod/settings.php:222 +#: mod/settings.php:213 msgid "Addon Settings" msgstr "Ustawienia dodatków" -#: mod/settings.php:223 +#: mod/settings.php:214 msgid "No Addon settings configured" msgstr "Brak skonfigurowanych ustawień dodatków" -#: mod/settings.php:244 +#: mod/settings.php:235 msgid "Additional Features" msgstr "Dodatkowe funkcje" -#: mod/settings.php:282 +#: mod/settings.php:273 msgid "Diaspora (Socialhome, Hubzilla)" msgstr "Diaspora (Socialhome, Hubzilla)" -#: mod/settings.php:282 mod/settings.php:283 +#: mod/settings.php:273 mod/settings.php:274 msgid "enabled" msgstr "włączone" -#: mod/settings.php:282 mod/settings.php:283 +#: mod/settings.php:273 mod/settings.php:274 msgid "disabled" msgstr "wyłączone" -#: mod/settings.php:282 mod/settings.php:283 +#: mod/settings.php:273 mod/settings.php:274 #, php-format msgid "Built-in support for %s connectivity is %s" msgstr "Wbudowane wsparcie dla połączenia z %s jest %s" -#: mod/settings.php:283 +#: mod/settings.php:274 msgid "OStatus (GNU Social)" msgstr "OStatus (GNU Social)" -#: mod/settings.php:309 +#: mod/settings.php:300 msgid "Email access is disabled on this site." msgstr "Dostęp do e-maila jest wyłączony na tej stronie." -#: mod/settings.php:314 mod/settings.php:359 +#: mod/settings.php:305 mod/settings.php:350 msgid "None" msgstr "Brak" -#: mod/settings.php:320 src/Module/BaseSettings.php:78 +#: mod/settings.php:311 src/Module/BaseSettings.php:78 msgid "Social Networks" msgstr "Portale społecznościowe" -#: mod/settings.php:325 +#: mod/settings.php:316 msgid "General Social Media Settings" msgstr "Ogólne ustawienia mediów społecznościowych" -#: mod/settings.php:328 +#: mod/settings.php:319 msgid "Followed content scope" msgstr "Obserwowany zakres treści" -#: mod/settings.php:330 +#: mod/settings.php:321 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 "Domyślnie na Twojej osi czasu będą pokazywane wątki, w których uczestniczyli Twoi obserwowani, ale które nie zostały przez nich rozpoczęte. Możesz wyłączyć tę funkcję lub rozszerzyć ją na konwersacje, w których Twoi obserwujący polubili dany wpis." -#: mod/settings.php:332 +#: mod/settings.php:323 msgid "Only conversations my follows started" msgstr "Tylko rozmowy, które rozpoczęli moi obserwowani" -#: mod/settings.php:333 +#: mod/settings.php:324 msgid "Conversations my follows started or commented on (default)" msgstr "Rozmowy, które rozpoczęli moi obserwowani, lub które komentowali (domyślnie)" -#: mod/settings.php:334 +#: mod/settings.php:325 msgid "Any conversation my follows interacted with, including likes" msgstr "Wszelkie rozmowy, z którymi wchodziłem w interakcję, w tym polubienia" -#: mod/settings.php:337 +#: mod/settings.php:328 msgid "Enable Content Warning" msgstr "Włącz ostrzeżenia o treści" -#: mod/settings.php:337 +#: mod/settings.php:328 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 " @@ -1345,109 +1346,109 @@ msgid "" " affect any other content filtering you eventually set up." msgstr "Użytkownicy w sieciach takich jak Mastodon lub Pleroma mogą ustawić pole ostrzeżenia o treści, które domyślnie zwija ich posty. Umożliwia to automatyczne zwijanie zamiast ustawiania ostrzeżenia o treści jako tytułu wpisu. Nie wpływa na żadne inne skonfigurowane filtrowanie treści." -#: mod/settings.php:338 +#: mod/settings.php:329 msgid "Enable intelligent shortening" msgstr "Włącz inteligentne skracanie" -#: mod/settings.php:338 +#: mod/settings.php:329 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 "Zwykle system próbuje znaleźć najlepszy odnośnik do dodania do skróconych postów. Jeśli wyłączone, każdy skrócony wpis będzie zawsze wskazywał na oryginalny wpis friendica." -#: mod/settings.php:339 +#: mod/settings.php:330 msgid "Enable simple text shortening" msgstr "Włącz proste skracanie tekstu" -#: mod/settings.php:339 +#: mod/settings.php:330 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 "Zwykle system skraca wpisy przy następnym wysunięciu wiersza. Jeśli ta opcja jest włączona, system skróci tekst do maksymalnego limitu znaków." -#: mod/settings.php:340 +#: mod/settings.php:331 msgid "Attach the link title" msgstr "Dołącz tytuł linku" -#: mod/settings.php:340 +#: mod/settings.php:331 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 "Po aktywacji tytuł dołączonego linku zostanie dodany jako tytuł postów do Diaspory. Jest to szczególnie pomocne w przypadku kontaktów „zdalnych”, które udostępniają treść kanału." -#: mod/settings.php:341 +#: mod/settings.php:332 msgid "Your legacy ActivityPub/GNU Social account" msgstr "Twoje stare konto ActivityPub/GNU Social" -#: mod/settings.php:341 +#: mod/settings.php:332 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 "Jeśli wprowadzisz tutaj swoją starą nazwę konta z systemu opartego na ActivityPub lub nazwę konta GNU Social/Statusnet (w formacie użytkownik@domena.tld), Twoje kontakty zostaną dodane automatycznie. Po zakończeniu pole zostanie opróżnione." -#: mod/settings.php:344 +#: mod/settings.php:335 msgid "Repair OStatus subscriptions" msgstr "Napraw subskrypcje OStatus" -#: mod/settings.php:348 +#: mod/settings.php:339 msgid "Email/Mailbox Setup" msgstr "Ustawienia emaila/skrzynki mailowej" -#: mod/settings.php:349 +#: mod/settings.php:340 msgid "" "If you wish to communicate with email contacts using this service " "(optional), please specify how to connect to your mailbox." msgstr "Jeśli chcesz komunikować się z kontaktami e-mail za pomocą tej usługi (opcjonalnie), określ sposób łączenia się ze skrzynką pocztową." -#: mod/settings.php:350 +#: mod/settings.php:341 msgid "Last successful email check:" msgstr "Ostatni sprawdzony e-mail:" -#: mod/settings.php:352 +#: mod/settings.php:343 msgid "IMAP server name:" msgstr "Nazwa serwera IMAP:" -#: mod/settings.php:353 +#: mod/settings.php:344 msgid "IMAP port:" msgstr "Port IMAP:" -#: mod/settings.php:354 +#: mod/settings.php:345 msgid "Security:" msgstr "Bezpieczeństwo:" -#: mod/settings.php:355 +#: mod/settings.php:346 msgid "Email login name:" msgstr "Nazwa logowania e-mail:" -#: mod/settings.php:356 +#: mod/settings.php:347 msgid "Email password:" msgstr "Hasło e-mail:" -#: mod/settings.php:357 +#: mod/settings.php:348 msgid "Reply-to address:" msgstr "Adres zwrotny:" -#: mod/settings.php:358 +#: mod/settings.php:349 msgid "Send public posts to all email contacts:" msgstr "Wyślij publiczny wpis do wszystkich kontaktów e-mail:" -#: mod/settings.php:359 +#: mod/settings.php:350 msgid "Action after import:" msgstr "Akcja po zaimportowaniu:" -#: mod/settings.php:359 src/Content/Nav.php:280 +#: mod/settings.php:350 src/Content/Nav.php:280 msgid "Mark as seen" msgstr "Oznacz jako przeczytane" -#: mod/settings.php:359 +#: mod/settings.php:350 msgid "Move to folder" msgstr "Przenieś do katalogu" -#: mod/settings.php:360 +#: mod/settings.php:351 msgid "Move to folder:" msgstr "Przenieś do katalogu:" @@ -1457,11 +1458,11 @@ msgid "" "hours." msgstr "Brak dostępnych sugestii. Jeśli jest to nowa witryna, spróbuj ponownie za 24 godziny." -#: mod/suggest.php:55 src/Content/Widget.php:81 view/theme/vier/theme.php:175 +#: mod/suggest.php:55 src/Content/Widget.php:83 view/theme/vier/theme.php:175 msgid "Friend Suggestions" msgstr "Osoby, które możesz znać" -#: mod/tagger.php:78 src/Content/Item.php:342 src/Model/Item.php:2694 +#: mod/tagger.php:78 src/Content/Item.php:342 src/Model/Item.php:2728 msgid "photo" msgstr "zdjęcie" @@ -1483,7 +1484,7 @@ msgid "Select a tag to remove: " msgstr "Wybierz znacznik do usunięcia: " #: mod/tagrm.php:126 src/Module/Settings/Delegation.php:179 -#: src/Module/Settings/TwoFactor/Trusted.php:140 +#: src/Module/Settings/TwoFactor/Trusted.php:142 msgid "Remove" msgstr "Usuń" @@ -1575,7 +1576,7 @@ msgstr "Plik przekracza limit rozmiaru wynoszący %s" msgid "File upload failed." msgstr "Przesyłanie pliku nie powiodło się." -#: mod/wall_upload.php:218 src/Model/Photo.php:1064 +#: mod/wall_upload.php:218 src/Model/Photo.php:1085 msgid "Wall Photos" msgstr "Tablica zdjęć" @@ -1599,80 +1600,80 @@ msgid "" "your site allow private mail from unknown senders." msgstr "Jeśli chcesz %s odpowiedzieć, sprawdź, czy ustawienia prywatności w Twojej witrynie zezwalają na prywatne wiadomości od nieznanych nadawców." -#: src/App.php:463 +#: src/App.php:473 msgid "No system theme config value set." msgstr "Nie ustawiono wartości konfiguracyjnej zestawu tematycznego." -#: src/App.php:583 +#: src/App.php:594 msgid "Apologies but the website is unavailable at the moment." msgstr "Przepraszamy, ale strona jest w tej chwili niedostępna." -#: src/App/Page.php:252 +#: src/App/Page.php:276 msgid "Delete this item?" msgstr "Usunąć ten element?" -#: src/App/Page.php:253 +#: src/App/Page.php:277 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 "Zablokować tego autora? Nie będą mogli Cię obserwować ani widzieć Twoich publicznych wpisów, a Ty nie będziesz widzieć ich wpisów i powiadomień." -#: src/App/Page.php:323 +#: src/App/Page.php:347 msgid "toggle mobile" msgstr "przełącz na mobilny" -#: src/App/Router.php:275 +#: src/App/Router.php:282 #, php-format msgid "Method not allowed for this module. Allowed method(s): %s" msgstr "Metoda niedozwolona dla tego modułu. Dozwolona metoda(y): %s" -#: src/App/Router.php:277 src/Module/HTTPException/PageNotFound.php:33 +#: src/App/Router.php:284 src/Module/HTTPException/PageNotFound.php:49 msgid "Page not found." msgstr "Strona nie znaleziona." -#: src/App/Router.php:305 +#: src/App/Router.php:312 msgid "You must be logged in to use addons. " msgstr "Musisz być zalogowany(-a), aby korzystać z dodatków. " -#: src/BaseModule.php:377 +#: src/BaseModule.php:392 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 "Znacznik zabezpieczeń formularza nie był poprawny. Prawdopodobnie stało się tak, ponieważ formularz został otwarty zbyt długo (> 3 godziny) przed jego przesłaniem." -#: src/BaseModule.php:404 +#: src/BaseModule.php:419 msgid "All contacts" msgstr "Wszystkie kontakty" -#: src/BaseModule.php:409 src/Content/Widget.php:233 src/Core/ACL.php:194 -#: src/Module/Contact.php:367 src/Module/PermissionTooltip.php:121 -#: src/Module/PermissionTooltip.php:143 +#: src/BaseModule.php:424 src/Content/Widget.php:235 src/Core/ACL.php:194 +#: src/Module/Contact.php:367 src/Module/PermissionTooltip.php:122 +#: src/Module/PermissionTooltip.php:144 msgid "Followers" msgstr "Zwolenników" -#: src/BaseModule.php:414 src/Content/Widget.php:234 +#: src/BaseModule.php:429 src/Content/Widget.php:236 #: src/Module/Contact.php:368 msgid "Following" msgstr "Kolejny" -#: src/BaseModule.php:419 src/Content/Widget.php:235 +#: src/BaseModule.php:434 src/Content/Widget.php:237 #: src/Module/Contact.php:369 msgid "Mutual friends" msgstr "Wspólni znajomi" -#: src/BaseModule.php:427 +#: src/BaseModule.php:442 msgid "Common" msgstr "Wspólne" -#: src/Console/Addon.php:177 src/Console/Addon.php:202 +#: src/Console/Addon.php:175 src/Console/Addon.php:199 msgid "Addon not found" msgstr "Dodatek nie został odnaleziony" -#: src/Console/Addon.php:181 +#: src/Console/Addon.php:179 msgid "Addon already enabled" msgstr "Dodatek już włączony" -#: src/Console/Addon.php:206 +#: src/Console/Addon.php:203 msgid "Addon already disabled" msgstr "Dodatek już wyłączony" @@ -1696,6 +1697,95 @@ msgstr "Nie można znaleźć żadnego kontaktu dla tego adresu URL (%s)" msgid "The contact has been blocked from the node" msgstr "Kontakt został zablokowany w węźle" +#: src/Console/MergeContacts.php:74 +#, php-format +msgid "%d %s, %d duplicates." +msgstr "%d %s, %d duplikaty." + +#: src/Console/MergeContacts.php:77 +#, php-format +msgid "uri-id is empty for contact %s." +msgstr "uri-id jest pusty dla kontaktu%s." + +#: src/Console/MergeContacts.php:90 +#, php-format +msgid "No valid first countact found for uri-id %d." +msgstr "Nie znaleziono prawidłowego pierwszego kontaktu dla identyfikatora uri-id %d." + +#: src/Console/MergeContacts.php:101 +#, php-format +msgid "Wrong duplicate found for uri-id %d in %d (url: %s != %s)." +msgstr "Odnaleziono nieprawidłowy duplikat dla identyfikatora uri %d w %d (url: %s != %s)." + +#: src/Console/MergeContacts.php:105 +#, php-format +msgid "Wrong duplicate found for uri-id %d in %d (nurl: %s != %s)." +msgstr "Odnaleziono nieprawidłowy duplikat dla identyfikatora uri %d w %d (nurl: %s != %s)." + +#: src/Console/MergeContacts.php:141 +#, php-format +msgid "Deletion of id %d failed" +msgstr "Nie udało się usunąć identyfikatora %d" + +#: src/Console/MergeContacts.php:143 +#, php-format +msgid "Deletion of id %d was successful" +msgstr "Usunięcie identyfikatora %d powiodło się" + +#: src/Console/MergeContacts.php:149 +#, php-format +msgid "Updating \"%s\" in \"%s\" from %d to %d" +msgstr "Aktualizowanie \"%s\" w \"%s\" z %d do %d" + +#: src/Console/MergeContacts.php:151 +msgid " - found" +msgstr "- znaleziono" + +#: src/Console/MergeContacts.php:158 +msgid " - failed" +msgstr " - błąd" + +#: src/Console/MergeContacts.php:160 +msgid " - success" +msgstr " - powodzenie" + +#: src/Console/MergeContacts.php:164 +msgid " - deleted" +msgstr " - usunięto" + +#: src/Console/MergeContacts.php:167 +msgid " - done" +msgstr " - zrobiono" + +#: src/Console/MoveToAvatarCache.php:91 +msgid "The avatar cache needs to be enabled to use this command." +msgstr "Aby użyć tego polecenia, pamięć podręczna awatarów musi być włączona." + +#: src/Console/MoveToAvatarCache.php:109 +#, php-format +msgid "no resource in photo %s" +msgstr "brak zasobu na zdjęciu %s" + +#: src/Console/MoveToAvatarCache.php:137 +#, php-format +msgid "no photo with id %s" +msgstr "brak zdjęcia z identyfikatorem %s" + +#: src/Console/MoveToAvatarCache.php:146 +#, php-format +msgid "no image data for photo with id %s" +msgstr "brak danych obrazu dla zdjęcia z identyfikatorem %s" + +#: src/Console/MoveToAvatarCache.php:155 +#, php-format +msgid "invalid image for id %s" +msgstr "nieprawidłowy obraz dla identyfikatora %s" + +#: src/Console/MoveToAvatarCache.php:168 +#, php-format +msgid "Quit on invalid photo %s" +msgstr "Zakończ na nieprawidłowym zdjęciu %s" + #: src/Console/PostUpdate.php:87 #, php-format msgid "Post update version number has been set to %s." @@ -1725,11 +1815,11 @@ msgstr "Wpisz nazwę użytkownika:" msgid "Enter new password: " msgstr "Wprowadź nowe hasło: " -#: src/Console/User.php:210 src/Module/Settings/Account.php:73 +#: src/Console/User.php:210 src/Module/Settings/Account.php:74 msgid "Password update failed. Please try again." msgstr "Aktualizacja hasła nie powiodła się. Proszę spróbować ponownie." -#: src/Console/User.php:213 src/Module/Settings/Account.php:76 +#: src/Console/User.php:213 src/Module/Settings/Account.php:77 msgid "Password changed." msgstr "Hasło zostało zmienione." @@ -1806,313 +1896,313 @@ msgstr "Co tydzień" msgid "Monthly" msgstr "Miesięczne" -#: src/Content/ContactSelector.php:123 +#: src/Content/ContactSelector.php:126 msgid "DFRN" msgstr "DFRN" -#: src/Content/ContactSelector.php:124 +#: src/Content/ContactSelector.php:127 msgid "OStatus" msgstr "OStatus" -#: src/Content/ContactSelector.php:125 +#: src/Content/ContactSelector.php:128 msgid "RSS/Atom" msgstr "RSS/Atom" -#: src/Content/ContactSelector.php:126 src/Module/Admin/Users/Active.php:129 +#: src/Content/ContactSelector.php:129 src/Module/Admin/Users/Active.php:129 #: src/Module/Admin/Users/Blocked.php:130 src/Module/Admin/Users/Create.php:73 #: src/Module/Admin/Users/Deleted.php:88 src/Module/Admin/Users/Index.php:142 #: src/Module/Admin/Users/Index.php:162 src/Module/Admin/Users/Pending.php:104 msgid "Email" msgstr "E-mail" -#: src/Content/ContactSelector.php:127 src/Module/Debug/Babel.php:307 +#: src/Content/ContactSelector.php:130 src/Module/Debug/Babel.php:307 msgid "Diaspora" msgstr "Diaspora" -#: src/Content/ContactSelector.php:128 +#: src/Content/ContactSelector.php:131 msgid "Zot!" msgstr "Zot!" -#: src/Content/ContactSelector.php:129 +#: src/Content/ContactSelector.php:132 msgid "LinkedIn" msgstr "LinkedIn" -#: src/Content/ContactSelector.php:130 +#: src/Content/ContactSelector.php:133 msgid "XMPP/IM" msgstr "XMPP/IM" -#: src/Content/ContactSelector.php:131 +#: src/Content/ContactSelector.php:134 msgid "MySpace" msgstr "MySpace" -#: src/Content/ContactSelector.php:132 +#: src/Content/ContactSelector.php:135 msgid "Google+" msgstr "Google+" -#: src/Content/ContactSelector.php:133 +#: src/Content/ContactSelector.php:136 msgid "pump.io" msgstr "pump.io" -#: src/Content/ContactSelector.php:134 +#: src/Content/ContactSelector.php:137 msgid "Twitter" msgstr "Twitter" -#: src/Content/ContactSelector.php:135 +#: src/Content/ContactSelector.php:138 msgid "Discourse" msgstr "Discourse" -#: src/Content/ContactSelector.php:136 +#: src/Content/ContactSelector.php:139 msgid "Diaspora Connector" msgstr "Łącze Diaspora" -#: src/Content/ContactSelector.php:137 +#: src/Content/ContactSelector.php:140 msgid "GNU Social Connector" msgstr "Łącze GNU Social" -#: src/Content/ContactSelector.php:138 +#: src/Content/ContactSelector.php:141 msgid "ActivityPub" msgstr "ActivityPub" -#: src/Content/ContactSelector.php:139 +#: src/Content/ContactSelector.php:142 msgid "pnut" msgstr "pnut" -#: src/Content/ContactSelector.php:175 +#: src/Content/ContactSelector.php:178 #, php-format msgid "%s (via %s)" msgstr "%s (przez %s)" -#: src/Content/Conversation.php:209 +#: src/Content/Conversation.php:207 #, php-format msgid "%s likes this." msgstr "%s lubi to." -#: src/Content/Conversation.php:212 +#: src/Content/Conversation.php:210 #, php-format msgid "%s doesn't like this." msgstr "%s nie lubi tego." -#: src/Content/Conversation.php:215 +#: src/Content/Conversation.php:213 #, php-format msgid "%s attends." msgstr "%s uczestniczy." -#: src/Content/Conversation.php:218 +#: src/Content/Conversation.php:216 #, php-format msgid "%s doesn't attend." msgstr "%s nie uczestniczy." -#: src/Content/Conversation.php:221 +#: src/Content/Conversation.php:219 #, php-format msgid "%s attends maybe." msgstr "%s może bierze udział." -#: src/Content/Conversation.php:224 src/Content/Conversation.php:262 -#: src/Content/Conversation.php:874 +#: src/Content/Conversation.php:222 src/Content/Conversation.php:260 +#: src/Content/Conversation.php:873 #, php-format msgid "%s reshared this." msgstr "%sudostępnił to. " -#: src/Content/Conversation.php:230 +#: src/Content/Conversation.php:228 msgid "and" msgstr "i" -#: src/Content/Conversation.php:233 +#: src/Content/Conversation.php:231 #, php-format msgid "and %d other people" msgstr "i %d inni ludzie" -#: src/Content/Conversation.php:241 +#: src/Content/Conversation.php:239 #, php-format msgid "%2$d people like this" msgstr "%2$d ludzi lubi to" -#: src/Content/Conversation.php:242 +#: src/Content/Conversation.php:240 #, php-format msgid "%s like this." msgstr "%s lubię to." -#: src/Content/Conversation.php:245 +#: src/Content/Conversation.php:243 #, php-format msgid "%2$d people don't like this" msgstr "%2$d ludzi nie lubi tego" -#: src/Content/Conversation.php:246 +#: src/Content/Conversation.php:244 #, php-format msgid "%s don't like this." msgstr "%s nie lubię tego." -#: src/Content/Conversation.php:249 +#: src/Content/Conversation.php:247 #, php-format msgid "%2$d people attend" msgstr "%2$dosoby uczestniczą" -#: src/Content/Conversation.php:250 +#: src/Content/Conversation.php:248 #, php-format msgid "%s attend." msgstr "%s uczestniczy." -#: src/Content/Conversation.php:253 +#: src/Content/Conversation.php:251 #, php-format msgid "%2$d people don't attend" msgstr "%2$dludzie nie uczestniczą" -#: src/Content/Conversation.php:254 +#: src/Content/Conversation.php:252 #, php-format msgid "%s don't attend." msgstr "%s nie uczestniczy." -#: src/Content/Conversation.php:257 +#: src/Content/Conversation.php:255 #, php-format msgid "%2$d people attend maybe" msgstr "Możliwe, że %2$d osoby będą uczestniczyć" -#: src/Content/Conversation.php:258 +#: src/Content/Conversation.php:256 #, php-format msgid "%s attend maybe." msgstr "%sbyć może uczestniczyć." -#: src/Content/Conversation.php:261 +#: src/Content/Conversation.php:259 #, php-format msgid "%2$d people reshared this" msgstr "%2$d użytkowników udostępniło to dalej" -#: src/Content/Conversation.php:309 +#: src/Content/Conversation.php:307 msgid "Visible to everybody" msgstr "Widoczne dla wszystkich" -#: src/Content/Conversation.php:310 src/Module/Item/Compose.php:171 -#: src/Object/Post.php:998 +#: src/Content/Conversation.php:308 src/Module/Item/Compose.php:171 +#: src/Object/Post.php:1002 msgid "Please enter a image/video/audio/webpage URL:" msgstr "Wprowadź adres URL obrazu/wideo/audio/strony:" -#: src/Content/Conversation.php:311 +#: src/Content/Conversation.php:309 msgid "Tag term:" msgstr "Termin tagu:" -#: src/Content/Conversation.php:312 src/Module/Filer/SaveTag.php:72 +#: src/Content/Conversation.php:310 src/Module/Filer/SaveTag.php:72 msgid "Save to Folder:" msgstr "Zapisz w katalogu:" -#: src/Content/Conversation.php:313 +#: src/Content/Conversation.php:311 msgid "Where are you right now?" msgstr "Gdzie teraz jesteś?" -#: src/Content/Conversation.php:314 +#: src/Content/Conversation.php:312 msgid "Delete item(s)?" msgstr "Usunąć pozycję (pozycje)?" -#: src/Content/Conversation.php:326 src/Module/Item/Compose.php:143 +#: src/Content/Conversation.php:324 src/Module/Item/Compose.php:143 msgid "Created at" msgstr "Utworzono" -#: src/Content/Conversation.php:336 +#: src/Content/Conversation.php:334 msgid "New Post" msgstr "Nowy wpis" -#: src/Content/Conversation.php:339 +#: src/Content/Conversation.php:337 msgid "Share" msgstr "Podziel się" -#: src/Content/Conversation.php:350 src/Module/Item/Compose.php:168 -#: src/Object/Post.php:995 +#: src/Content/Conversation.php:348 src/Module/Item/Compose.php:168 +#: src/Object/Post.php:999 msgid "Image" msgstr "Obraz" -#: src/Content/Conversation.php:353 +#: src/Content/Conversation.php:351 msgid "Video" msgstr "Filmy" -#: src/Content/Conversation.php:366 src/Module/Item/Compose.php:184 +#: src/Content/Conversation.php:364 src/Module/Item/Compose.php:184 msgid "Scheduled at" msgstr "Zaplanowane na" -#: src/Content/Conversation.php:658 src/Object/Post.php:235 +#: src/Content/Conversation.php:657 src/Object/Post.php:244 msgid "Pinned item" msgstr "Przypięty element" -#: src/Content/Conversation.php:674 src/Object/Post.php:476 -#: src/Object/Post.php:477 +#: src/Content/Conversation.php:673 src/Object/Post.php:486 +#: src/Object/Post.php:487 #, php-format msgid "View %s's profile @ %s" msgstr "Pokaż profil %s @ %s" -#: src/Content/Conversation.php:687 src/Object/Post.php:464 +#: src/Content/Conversation.php:686 src/Object/Post.php:474 msgid "Categories:" msgstr "Kategorie:" -#: src/Content/Conversation.php:688 src/Object/Post.php:465 +#: src/Content/Conversation.php:687 src/Object/Post.php:475 msgid "Filed under:" msgstr "Umieszczono w:" -#: src/Content/Conversation.php:696 src/Object/Post.php:490 +#: src/Content/Conversation.php:695 src/Object/Post.php:500 #, php-format msgid "%s from %s" msgstr "%s od %s" -#: src/Content/Conversation.php:712 +#: src/Content/Conversation.php:711 msgid "View in context" msgstr "Zobacz w kontekście" -#: src/Content/Conversation.php:777 +#: src/Content/Conversation.php:776 msgid "remove" msgstr "usuń" -#: src/Content/Conversation.php:781 +#: src/Content/Conversation.php:780 msgid "Delete Selected Items" msgstr "Usuń zaznaczone elementy" -#: src/Content/Conversation.php:846 src/Content/Conversation.php:849 -#: src/Content/Conversation.php:852 src/Content/Conversation.php:855 +#: src/Content/Conversation.php:845 src/Content/Conversation.php:848 +#: src/Content/Conversation.php:851 src/Content/Conversation.php:854 #, php-format msgid "You had been addressed (%s)." msgstr "Zostałeś zaadresowany (%s)." -#: src/Content/Conversation.php:858 +#: src/Content/Conversation.php:857 #, php-format msgid "You are following %s." msgstr "Zacząłeś obserwować %s." -#: src/Content/Conversation.php:861 +#: src/Content/Conversation.php:860 msgid "Tagged" msgstr "Oznaczone" -#: src/Content/Conversation.php:876 +#: src/Content/Conversation.php:875 msgid "Reshared" msgstr "Udostępnione" -#: src/Content/Conversation.php:876 +#: src/Content/Conversation.php:875 #, php-format msgid "Reshared by %s <%s>" msgstr "Udostępnione przez %s <%s>" -#: src/Content/Conversation.php:879 +#: src/Content/Conversation.php:878 #, php-format msgid "%s is participating in this thread." msgstr "%s bierze udział w tym wątku." -#: src/Content/Conversation.php:882 +#: src/Content/Conversation.php:881 msgid "Stored" msgstr "Przechowywane" -#: src/Content/Conversation.php:885 +#: src/Content/Conversation.php:884 msgid "Global" msgstr "Globalne" -#: src/Content/Conversation.php:888 +#: src/Content/Conversation.php:887 msgid "Relayed" msgstr "Przekazany" -#: src/Content/Conversation.php:888 +#: src/Content/Conversation.php:887 #, php-format msgid "Relayed by %s <%s>" msgstr "Przekazany przez %s <%s>" -#: src/Content/Conversation.php:891 +#: src/Content/Conversation.php:890 msgid "Fetched" msgstr "Pobrane" -#: src/Content/Conversation.php:891 +#: src/Content/Conversation.php:890 #, php-format msgid "Fetched because of %s <%s>" msgstr "Pobrano ponieważ %s <%s>" @@ -2216,7 +2306,7 @@ msgid "Display membership date in profile" msgstr "Wyświetla datę członkostwa w profilu" #: src/Content/ForumManager.php:151 src/Content/Nav.php:239 -#: src/Content/Text/HTML.php:896 src/Content/Widget.php:522 +#: src/Content/Text/HTML.php:903 src/Content/Widget.php:524 msgid "Forums" msgstr "Fora" @@ -2224,12 +2314,12 @@ msgstr "Fora" msgid "External link to forum" msgstr "Zewnętrzny link do forum" -#: src/Content/ForumManager.php:156 src/Content/Widget.php:501 +#: src/Content/ForumManager.php:156 src/Content/Widget.php:503 msgid "show less" msgstr "pokaż mniej" -#: src/Content/ForumManager.php:157 src/Content/Widget.php:403 -#: src/Content/Widget.php:502 +#: src/Content/ForumManager.php:157 src/Content/Widget.php:405 +#: src/Content/Widget.php:504 msgid "show more" msgstr "pokaż więcej" @@ -2238,7 +2328,7 @@ msgstr "pokaż więcej" msgid "%1$s poked %2$s" msgstr "%1$s zaczepił Cię %2$s" -#: src/Content/Item.php:334 src/Model/Item.php:2692 +#: src/Content/Item.php:334 src/Model/Item.php:2726 msgid "event" msgstr "wydarzenie" @@ -2246,32 +2336,32 @@ msgstr "wydarzenie" msgid "Follow Thread" msgstr "Śledź wątek" -#: src/Content/Item.php:423 src/Model/Contact.php:1093 +#: src/Content/Item.php:423 src/Model/Contact.php:1108 msgid "View Status" msgstr "Zobacz status" #: src/Content/Item.php:424 src/Content/Item.php:446 -#: src/Model/Contact.php:1027 src/Model/Contact.php:1085 -#: src/Model/Contact.php:1094 src/Module/Directory.php:158 +#: src/Model/Contact.php:1042 src/Model/Contact.php:1100 +#: src/Model/Contact.php:1109 src/Module/Directory.php:158 #: src/Module/Settings/Profile/Index.php:225 msgid "View Profile" msgstr "Zobacz profil" -#: src/Content/Item.php:425 src/Model/Contact.php:1095 +#: src/Content/Item.php:425 src/Model/Contact.php:1110 msgid "View Photos" msgstr "Zobacz zdjęcia" -#: src/Content/Item.php:426 src/Model/Contact.php:1086 -#: src/Model/Contact.php:1096 +#: src/Content/Item.php:426 src/Model/Contact.php:1101 +#: src/Model/Contact.php:1111 msgid "Network Posts" msgstr "Wiadomości sieciowe" -#: src/Content/Item.php:427 src/Model/Contact.php:1087 -#: src/Model/Contact.php:1097 +#: src/Content/Item.php:427 src/Model/Contact.php:1102 +#: src/Model/Contact.php:1112 msgid "View Contact" msgstr "Pokaż kontakt" -#: src/Content/Item.php:428 src/Model/Contact.php:1098 +#: src/Content/Item.php:428 src/Model/Contact.php:1113 msgid "Send PM" msgstr "Wyślij prywatną wiadomość" @@ -2290,11 +2380,11 @@ msgstr "Zablokuj" msgid "Ignore" msgstr "Ignoruj" -#: src/Content/Item.php:434 src/Object/Post.php:445 +#: src/Content/Item.php:434 src/Object/Post.php:455 msgid "Languages" msgstr "Języki" -#: src/Content/Item.php:438 src/Model/Contact.php:1099 +#: src/Content/Item.php:438 src/Model/Contact.php:1114 msgid "Poke" msgstr "Zaczepka" @@ -2310,7 +2400,7 @@ msgstr "Wróć" msgid "Clear notifications" msgstr "Wyczyść powiadomienia" -#: src/Content/Nav.php:96 src/Content/Text/HTML.php:883 +#: src/Content/Nav.php:96 src/Content/Text/HTML.php:890 msgid "@name, !forum, #tags, content" msgstr "@imię, !forum, #znaczniki, treść" @@ -2333,7 +2423,7 @@ msgstr "Zaloguj się" #: src/Content/Nav.php:190 src/Module/BaseProfile.php:56 #: src/Module/Contact.php:433 src/Module/Contact/Profile.php:380 -#: src/Module/Settings/TwoFactor/Index.php:112 view/theme/frio/theme.php:225 +#: src/Module/Settings/TwoFactor/Index.php:115 view/theme/frio/theme.php:225 msgid "Status" msgstr "Stan" @@ -2394,7 +2484,7 @@ msgstr "Załóż konto" #: src/Content/Nav.php:222 src/Module/Help.php:67 #: src/Module/Settings/TwoFactor/AppSpecific.php:127 -#: src/Module/Settings/TwoFactor/Index.php:111 +#: src/Module/Settings/TwoFactor/Index.php:114 #: src/Module/Settings/TwoFactor/Recovery.php:105 #: src/Module/Settings/TwoFactor/Verify.php:145 view/theme/vier/theme.php:217 msgid "Help" @@ -2412,8 +2502,8 @@ msgstr "Aplikacje" msgid "Addon applications, utilities, games" msgstr "Wtyczki, aplikacje, narzędzia, gry" -#: src/Content/Nav.php:230 src/Content/Text/HTML.php:881 -#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:97 +#: src/Content/Nav.php:230 src/Content/Text/HTML.php:888 +#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:112 msgid "Search" msgstr "Szukaj" @@ -2421,17 +2511,17 @@ msgstr "Szukaj" msgid "Search site content" msgstr "Przeszukaj zawartość strony" -#: src/Content/Nav.php:233 src/Content/Text/HTML.php:890 +#: src/Content/Nav.php:233 src/Content/Text/HTML.php:897 msgid "Full Text" msgstr "Pełny tekst" -#: src/Content/Nav.php:234 src/Content/Text/HTML.php:891 +#: src/Content/Nav.php:234 src/Content/Text/HTML.php:898 #: src/Content/Widget/TagCloud.php:68 msgid "Tags" msgstr "Znaczniki" #: src/Content/Nav.php:235 src/Content/Nav.php:294 -#: src/Content/Text/HTML.php:892 src/Module/BaseProfile.php:125 +#: src/Content/Text/HTML.php:899 src/Module/BaseProfile.php:125 #: src/Module/BaseProfile.php:128 src/Module/Contact.php:370 #: src/Module/Contact.php:464 view/theme/frio/theme.php:236 msgid "Contacts" @@ -2458,7 +2548,7 @@ msgstr "Katalog" msgid "People directory" msgstr "Katalog osób" -#: src/Content/Nav.php:263 src/Module/BaseAdmin.php:85 +#: src/Content/Nav.php:263 src/Module/BaseAdmin.php:88 msgid "Information" msgstr "Informacje" @@ -2467,7 +2557,7 @@ msgid "Information about this friendica instance" msgstr "Informacje o tej instancji friendica" #: src/Content/Nav.php:266 src/Module/Admin/Tos.php:76 -#: src/Module/BaseAdmin.php:96 src/Module/Register.php:176 +#: src/Module/BaseAdmin.php:99 src/Module/Register.php:176 #: src/Module/Tos.php:87 msgid "Terms of Service" msgstr "Warunki usługi" @@ -2539,7 +2629,7 @@ msgstr "Ustawienia konta" msgid "Manage/edit friends and contacts" msgstr "Zarządzaj listą przyjaciół i kontaktami" -#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:126 +#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:129 msgid "Admin" msgstr "Administrator" @@ -2579,8 +2669,8 @@ msgstr "następny" msgid "last" msgstr "ostatni" -#: src/Content/Text/BBCode.php:990 src/Content/Text/BBCode.php:1784 -#: src/Content/Text/BBCode.php:1785 +#: src/Content/Text/BBCode.php:990 src/Content/Text/BBCode.php:1808 +#: src/Content/Text/BBCode.php:1809 msgid "Image/photo" msgstr "Obrazek/zdjęcie" @@ -2589,41 +2679,41 @@ msgstr "Obrazek/zdjęcie" msgid "%2$s %3$s" msgstr "%2$s %3$s" -#: src/Content/Text/BBCode.php:1188 src/Model/Item.php:3258 -#: src/Model/Item.php:3264 src/Model/Item.php:3265 +#: src/Content/Text/BBCode.php:1188 src/Model/Item.php:3301 +#: src/Model/Item.php:3307 src/Model/Item.php:3308 msgid "Link to source" msgstr "Odnośnik do źródła" -#: src/Content/Text/BBCode.php:1702 src/Content/Text/HTML.php:933 +#: src/Content/Text/BBCode.php:1726 src/Content/Text/HTML.php:940 msgid "Click to open/close" msgstr "Kliknij aby otworzyć/zamknąć" -#: src/Content/Text/BBCode.php:1733 +#: src/Content/Text/BBCode.php:1757 msgid "$1 wrote:" msgstr "$1 napisał:" -#: src/Content/Text/BBCode.php:1789 src/Content/Text/BBCode.php:1790 +#: src/Content/Text/BBCode.php:1813 src/Content/Text/BBCode.php:1814 msgid "Encrypted content" msgstr "Szyfrowana treść" -#: src/Content/Text/BBCode.php:2005 +#: src/Content/Text/BBCode.php:2032 msgid "Invalid source protocol" msgstr "Nieprawidłowy protokół źródłowy" -#: src/Content/Text/BBCode.php:2020 +#: src/Content/Text/BBCode.php:2047 msgid "Invalid link protocol" msgstr "Niepoprawny link protokołu" -#: src/Content/Text/HTML.php:797 +#: src/Content/Text/HTML.php:805 msgid "Loading more entries..." msgstr "Wczytywanie kolejnych wpisów..." -#: src/Content/Text/HTML.php:798 +#: src/Content/Text/HTML.php:806 msgid "The end" msgstr "Koniec" -#: src/Content/Text/HTML.php:875 src/Content/Widget/VCard.php:103 -#: src/Model/Profile.php:456 +#: src/Content/Text/HTML.php:882 src/Content/Widget/VCard.php:109 +#: src/Model/Profile.php:457 msgid "Follow" msgstr "Śledź" @@ -2643,7 +2733,7 @@ msgstr "Przykład: bob@przykład.com, http://przykład.com/barbara" msgid "Connect" msgstr "Połącz" -#: src/Content/Widget.php:70 +#: src/Content/Widget.php:72 #, php-format msgid "%d invitation available" msgid_plural "%d invitations available" @@ -2652,83 +2742,83 @@ msgstr[1] "%d zaproszeń dostępnych" msgstr[2] "%d zaproszenia dostępne" msgstr[3] "%d zaproszenia dostępne" -#: src/Content/Widget.php:76 view/theme/vier/theme.php:170 +#: src/Content/Widget.php:78 view/theme/vier/theme.php:170 msgid "Find People" msgstr "Znajdź ludzi" -#: src/Content/Widget.php:77 view/theme/vier/theme.php:171 +#: src/Content/Widget.php:79 view/theme/vier/theme.php:171 msgid "Enter name or interest" msgstr "Wpisz nazwę lub zainteresowanie" -#: src/Content/Widget.php:79 view/theme/vier/theme.php:173 +#: src/Content/Widget.php:81 view/theme/vier/theme.php:173 msgid "Examples: Robert Morgenstein, Fishing" msgstr "Przykład: Jan Kowalski, Wędkarstwo" -#: src/Content/Widget.php:80 src/Module/Contact.php:391 +#: src/Content/Widget.php:82 src/Module/Contact.php:391 #: src/Module/Directory.php:97 view/theme/vier/theme.php:174 msgid "Find" msgstr "Znajdź" -#: src/Content/Widget.php:82 view/theme/vier/theme.php:176 +#: src/Content/Widget.php:84 view/theme/vier/theme.php:176 msgid "Similar Interests" msgstr "Podobne zainteresowania" -#: src/Content/Widget.php:83 view/theme/vier/theme.php:177 +#: src/Content/Widget.php:85 view/theme/vier/theme.php:177 msgid "Random Profile" msgstr "Domyślny profil" -#: src/Content/Widget.php:84 view/theme/vier/theme.php:178 +#: src/Content/Widget.php:86 view/theme/vier/theme.php:178 msgid "Invite Friends" msgstr "Zaproś znajomych" -#: src/Content/Widget.php:85 src/Module/Directory.php:89 +#: src/Content/Widget.php:87 src/Module/Directory.php:89 #: view/theme/vier/theme.php:179 msgid "Global Directory" msgstr "Katalog globalny" -#: src/Content/Widget.php:87 view/theme/vier/theme.php:181 +#: src/Content/Widget.php:89 view/theme/vier/theme.php:181 msgid "Local Directory" msgstr "Katalog lokalny" -#: src/Content/Widget.php:209 src/Model/Group.php:570 +#: src/Content/Widget.php:211 src/Model/Group.php:583 #: src/Module/Contact.php:354 src/Module/Welcome.php:76 msgid "Groups" msgstr "Grupy" -#: src/Content/Widget.php:211 +#: src/Content/Widget.php:213 msgid "Everyone" msgstr "Wszyscy" -#: src/Content/Widget.php:240 +#: src/Content/Widget.php:242 msgid "Relationships" msgstr "Relacje" -#: src/Content/Widget.php:242 src/Module/Contact.php:306 +#: src/Content/Widget.php:244 src/Module/Contact.php:306 #: src/Module/Group.php:293 msgid "All Contacts" msgstr "Wszystkie kontakty" -#: src/Content/Widget.php:281 +#: src/Content/Widget.php:283 msgid "Protocols" msgstr "Protokoły" -#: src/Content/Widget.php:283 +#: src/Content/Widget.php:285 msgid "All Protocols" msgstr "Wszystkie protokoły" -#: src/Content/Widget.php:311 +#: src/Content/Widget.php:313 msgid "Saved Folders" msgstr "Zapisane katalogi" -#: src/Content/Widget.php:313 src/Content/Widget.php:344 +#: src/Content/Widget.php:315 src/Content/Widget.php:346 msgid "Everything" msgstr "Wszystko" -#: src/Content/Widget.php:342 +#: src/Content/Widget.php:344 msgid "Categories" msgstr "Kategorie" -#: src/Content/Widget.php:399 +#: src/Content/Widget.php:401 #, php-format msgid "%d contact in common" msgid_plural "%d contacts in common" @@ -2737,27 +2827,27 @@ msgstr[1] "%d wspólne kontakty" msgstr[2] "%d wspólnych kontaktów" msgstr[3] "%d wspólnych kontaktów" -#: src/Content/Widget.php:495 +#: src/Content/Widget.php:497 msgid "Archives" msgstr "Archiwa" -#: src/Content/Widget.php:519 +#: src/Content/Widget.php:521 msgid "Persons" msgstr "Osoby" -#: src/Content/Widget.php:520 +#: src/Content/Widget.php:522 msgid "Organisations" msgstr "Organizacje" -#: src/Content/Widget.php:521 src/Model/Contact.php:1523 +#: src/Content/Widget.php:523 src/Model/Contact.php:1538 msgid "News" msgstr "Aktualności" -#: src/Content/Widget.php:525 src/Module/Settings/Account.php:430 +#: src/Content/Widget.php:527 src/Module/Settings/Account.php:455 msgid "Account Types" msgstr "Rodzaje kont" -#: src/Content/Widget.php:526 src/Module/Admin/BaseUsers.php:51 +#: src/Content/Widget.php:528 src/Module/Admin/BaseUsers.php:51 msgid "All" msgstr "Wszyscy" @@ -2811,22 +2901,22 @@ msgstr[3] "Popularne znaczniki (ostatnie %d godzin)" msgid "More Trending Tags" msgstr "Więcej popularnych znaczników" -#: src/Content/Widget/VCard.php:96 src/Model/Profile.php:375 +#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:376 #: src/Module/Contact/Profile.php:371 src/Module/Profile/Profile.php:176 msgid "XMPP:" msgstr "XMPP:" -#: src/Content/Widget/VCard.php:97 src/Model/Profile.php:376 +#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:377 #: src/Module/Contact/Profile.php:373 src/Module/Profile/Profile.php:180 msgid "Matrix:" msgstr "Matrix:" -#: src/Content/Widget/VCard.php:101 src/Model/Profile.php:468 +#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:469 #: src/Module/Notifications/Introductions.php:199 msgid "Network:" msgstr "Sieć:" -#: src/Content/Widget/VCard.php:105 src/Model/Profile.php:458 +#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:459 msgid "Unfollow" msgstr "Przestań obserwować" @@ -2834,8 +2924,8 @@ msgstr "Przestań obserwować" msgid "Yourself" msgstr "Siebie" -#: src/Core/ACL.php:201 src/Module/PermissionTooltip.php:127 -#: src/Module/PermissionTooltip.php:149 +#: src/Core/ACL.php:201 src/Module/PermissionTooltip.php:128 +#: src/Module/PermissionTooltip.php:150 msgid "Mutuals" msgstr "Wzajemne" @@ -2843,7 +2933,7 @@ msgstr "Wzajemne" msgid "Post to Email" msgstr "Prześlij e-mailem" -#: src/Core/ACL.php:320 src/Module/PermissionTooltip.php:84 +#: src/Core/ACL.php:320 src/Module/PermissionTooltip.php:85 #: src/Module/PermissionTooltip.php:197 msgid "Public" msgstr "Publiczny" @@ -2854,7 +2944,7 @@ msgid "" "community pages and by anyone with its link." msgstr "Ta treść zostanie wyświetlona wszystkim Twoim obserwatorom i będzie widoczna na stronach społeczności oraz przez każdego z jej linkiem." -#: src/Core/ACL.php:322 src/Module/PermissionTooltip.php:92 +#: src/Core/ACL.php:322 src/Module/PermissionTooltip.php:93 msgid "Limited/Private" msgstr "Ograniczony/Prywatny" @@ -3188,207 +3278,207 @@ msgstr "Baza danych jest już w użyciu." msgid "Could not connect to database." msgstr "Nie można połączyć się z bazą danych." -#: src/Core/L10n.php:400 src/Model/Event.php:425 +#: src/Core/L10n.php:399 src/Model/Event.php:424 #: src/Module/Settings/Display.php:182 msgid "Monday" msgstr "Poniedziałek" -#: src/Core/L10n.php:400 src/Model/Event.php:426 +#: src/Core/L10n.php:399 src/Model/Event.php:425 msgid "Tuesday" msgstr "Wtorek" -#: src/Core/L10n.php:400 src/Model/Event.php:427 +#: src/Core/L10n.php:399 src/Model/Event.php:426 msgid "Wednesday" msgstr "Środa" -#: src/Core/L10n.php:400 src/Model/Event.php:428 +#: src/Core/L10n.php:399 src/Model/Event.php:427 msgid "Thursday" msgstr "Czwartek" -#: src/Core/L10n.php:400 src/Model/Event.php:429 +#: src/Core/L10n.php:399 src/Model/Event.php:428 msgid "Friday" msgstr "Piątek" -#: src/Core/L10n.php:400 src/Model/Event.php:430 +#: src/Core/L10n.php:399 src/Model/Event.php:429 msgid "Saturday" msgstr "Sobota" -#: src/Core/L10n.php:400 src/Model/Event.php:424 +#: src/Core/L10n.php:399 src/Model/Event.php:423 #: src/Module/Settings/Display.php:182 msgid "Sunday" msgstr "Niedziela" -#: src/Core/L10n.php:404 src/Model/Event.php:445 +#: src/Core/L10n.php:403 src/Model/Event.php:444 msgid "January" msgstr "Styczeń" -#: src/Core/L10n.php:404 src/Model/Event.php:446 +#: src/Core/L10n.php:403 src/Model/Event.php:445 msgid "February" msgstr "Luty" -#: src/Core/L10n.php:404 src/Model/Event.php:447 +#: src/Core/L10n.php:403 src/Model/Event.php:446 msgid "March" msgstr "Marzec" -#: src/Core/L10n.php:404 src/Model/Event.php:448 +#: src/Core/L10n.php:403 src/Model/Event.php:447 msgid "April" msgstr "Kwiecień" -#: src/Core/L10n.php:404 src/Core/L10n.php:424 src/Model/Event.php:436 +#: src/Core/L10n.php:403 src/Core/L10n.php:422 src/Model/Event.php:435 msgid "May" msgstr "Maj" -#: src/Core/L10n.php:404 src/Model/Event.php:449 +#: src/Core/L10n.php:403 src/Model/Event.php:448 msgid "June" msgstr "Czerwiec" -#: src/Core/L10n.php:404 src/Model/Event.php:450 +#: src/Core/L10n.php:403 src/Model/Event.php:449 msgid "July" msgstr "Lipiec" -#: src/Core/L10n.php:404 src/Model/Event.php:451 +#: src/Core/L10n.php:403 src/Model/Event.php:450 msgid "August" msgstr "Sierpień" -#: src/Core/L10n.php:404 src/Model/Event.php:452 +#: src/Core/L10n.php:403 src/Model/Event.php:451 msgid "September" msgstr "Wrzesień" -#: src/Core/L10n.php:404 src/Model/Event.php:453 +#: src/Core/L10n.php:403 src/Model/Event.php:452 msgid "October" msgstr "Październik" -#: src/Core/L10n.php:404 src/Model/Event.php:454 +#: src/Core/L10n.php:403 src/Model/Event.php:453 msgid "November" msgstr "Listopad" -#: src/Core/L10n.php:404 src/Model/Event.php:455 +#: src/Core/L10n.php:403 src/Model/Event.php:454 msgid "December" msgstr "Grudzień" -#: src/Core/L10n.php:420 src/Model/Event.php:417 +#: src/Core/L10n.php:418 src/Model/Event.php:416 msgid "Mon" msgstr "Pon" -#: src/Core/L10n.php:420 src/Model/Event.php:418 +#: src/Core/L10n.php:418 src/Model/Event.php:417 msgid "Tue" msgstr "Wt" -#: src/Core/L10n.php:420 src/Model/Event.php:419 +#: src/Core/L10n.php:418 src/Model/Event.php:418 msgid "Wed" msgstr "Śr" -#: src/Core/L10n.php:420 src/Model/Event.php:420 +#: src/Core/L10n.php:418 src/Model/Event.php:419 msgid "Thu" msgstr "Czw" -#: src/Core/L10n.php:420 src/Model/Event.php:421 +#: src/Core/L10n.php:418 src/Model/Event.php:420 msgid "Fri" msgstr "Pt" -#: src/Core/L10n.php:420 src/Model/Event.php:422 +#: src/Core/L10n.php:418 src/Model/Event.php:421 msgid "Sat" msgstr "Sob" -#: src/Core/L10n.php:420 src/Model/Event.php:416 +#: src/Core/L10n.php:418 src/Model/Event.php:415 msgid "Sun" msgstr "Niedz" -#: src/Core/L10n.php:424 src/Model/Event.php:432 +#: src/Core/L10n.php:422 src/Model/Event.php:431 msgid "Jan" msgstr "Sty" -#: src/Core/L10n.php:424 src/Model/Event.php:433 +#: src/Core/L10n.php:422 src/Model/Event.php:432 msgid "Feb" msgstr "Lut" -#: src/Core/L10n.php:424 src/Model/Event.php:434 +#: src/Core/L10n.php:422 src/Model/Event.php:433 msgid "Mar" msgstr "Mar" -#: src/Core/L10n.php:424 src/Model/Event.php:435 +#: src/Core/L10n.php:422 src/Model/Event.php:434 msgid "Apr" msgstr "Kwi" -#: src/Core/L10n.php:424 src/Model/Event.php:437 +#: src/Core/L10n.php:422 src/Model/Event.php:436 msgid "Jun" msgstr "Cze" -#: src/Core/L10n.php:424 src/Model/Event.php:438 +#: src/Core/L10n.php:422 src/Model/Event.php:437 msgid "Jul" msgstr "Lip" -#: src/Core/L10n.php:424 src/Model/Event.php:439 +#: src/Core/L10n.php:422 src/Model/Event.php:438 msgid "Aug" msgstr "Sie" -#: src/Core/L10n.php:424 +#: src/Core/L10n.php:422 msgid "Sep" msgstr "Wrz" -#: src/Core/L10n.php:424 src/Model/Event.php:441 +#: src/Core/L10n.php:422 src/Model/Event.php:440 msgid "Oct" msgstr "Paź" -#: src/Core/L10n.php:424 src/Model/Event.php:442 +#: src/Core/L10n.php:422 src/Model/Event.php:441 msgid "Nov" msgstr "Lis" -#: src/Core/L10n.php:424 src/Model/Event.php:443 +#: src/Core/L10n.php:422 src/Model/Event.php:442 msgid "Dec" msgstr "Gru" -#: src/Core/L10n.php:443 +#: src/Core/L10n.php:441 msgid "poke" msgstr "zaczep" -#: src/Core/L10n.php:443 +#: src/Core/L10n.php:441 msgid "poked" msgstr "zaczepił Cię" -#: src/Core/L10n.php:444 +#: src/Core/L10n.php:442 msgid "ping" msgstr "ping" -#: src/Core/L10n.php:444 +#: src/Core/L10n.php:442 msgid "pinged" msgstr "napięcia" -#: src/Core/L10n.php:445 +#: src/Core/L10n.php:443 msgid "prod" msgstr "zaczep" -#: src/Core/L10n.php:445 +#: src/Core/L10n.php:443 msgid "prodded" msgstr "zaczepiać" -#: src/Core/L10n.php:446 +#: src/Core/L10n.php:444 msgid "slap" msgstr "klask" -#: src/Core/L10n.php:446 +#: src/Core/L10n.php:444 msgid "slapped" msgstr "spoliczkowany" -#: src/Core/L10n.php:447 +#: src/Core/L10n.php:445 msgid "finger" msgstr "wskaż" -#: src/Core/L10n.php:447 +#: src/Core/L10n.php:445 msgid "fingered" msgstr "dotknięty" -#: src/Core/L10n.php:448 +#: src/Core/L10n.php:446 msgid "rebuff" msgstr "odrzuć" -#: src/Core/L10n.php:448 +#: src/Core/L10n.php:446 msgid "rebuffed" msgstr "odrzucony" #: src/Core/Renderer.php:89 src/Core/Renderer.php:118 #: src/Core/Renderer.php:145 src/Core/Renderer.php:179 -#: src/Render/FriendicaSmartyEngine.php:56 +#: src/Render/FriendicaSmartyEngine.php:69 msgid "" "Friendica can't display this page at the moment, please contact the " "administrator." @@ -3471,24 +3561,24 @@ msgid "" "\t\t\t\t\tThe friendica database was successfully updated from %s to %s." msgstr "\n\t\t\t\t\tBaza danych Friendica została pomyślnie zaktualizowana z %s do %s." -#: src/Core/UserImport.php:125 +#: src/Core/UserImport.php:126 msgid "Error decoding account file" msgstr "Błąd podczas odczytu pliku konta" -#: src/Core/UserImport.php:131 +#: src/Core/UserImport.php:132 msgid "Error! No version data in file! This is not a Friendica account file?" msgstr "Błąd! Brak danych wersji w pliku! To nie jest plik konta Friendica?" -#: src/Core/UserImport.php:139 +#: src/Core/UserImport.php:140 #, php-format msgid "User '%s' already exists on this server!" msgstr "Użytkownik '%s' już istnieje na tym serwerze!" -#: src/Core/UserImport.php:175 +#: src/Core/UserImport.php:176 msgid "User creation error" msgstr "Błąd tworzenia użytkownika" -#: src/Core/UserImport.php:220 +#: src/Core/UserImport.php:221 #, php-format msgid "%d contact not imported" msgid_plural "%d contacts not imported" @@ -3497,11 +3587,11 @@ msgstr[1] "Nie zaimportowano %d kontaktów" msgstr[2] "Nie zaimportowano %d kontaktów" msgstr[3] "%d kontakty nie zostały zaimportowane " -#: src/Core/UserImport.php:273 +#: src/Core/UserImport.php:274 msgid "User profile creation error" msgstr "Błąd tworzenia profilu użytkownika" -#: src/Core/UserImport.php:326 +#: src/Core/UserImport.php:327 msgid "Done. You can now login with your username and password" msgstr "Gotowe. Możesz teraz zalogować się z użyciem nazwy użytkownika i hasła" @@ -3531,7 +3621,7 @@ msgstr "Te tabele nie są używane we friendice i zostaną usunięte po wykonani msgid "There are no tables on MyISAM or InnoDB with the Antelope file format." msgstr "Brak tabel w MyISAM lub InnoDB z formatem pliku Antelope." -#: src/Database/DBStructure.php:158 +#: src/Database/DBStructure.php:157 #, php-format msgid "" "\n" @@ -3539,20 +3629,20 @@ msgid "" "%s\n" msgstr "\nWystąpił błąd %d podczas aktualizacji bazy danych:\n%s\n" -#: src/Database/DBStructure.php:161 +#: src/Database/DBStructure.php:160 msgid "Errors encountered performing database changes: " msgstr "Błędy napotkane podczas dokonywania zmian w bazie danych: " -#: src/Database/DBStructure.php:549 +#: src/Database/DBStructure.php:563 msgid "Another database update is currently running." msgstr "Trwa inna aktualizacja bazy danych." -#: src/Database/DBStructure.php:553 +#: src/Database/DBStructure.php:567 #, php-format msgid "%s: Database update" msgstr "%s: Aktualizacja bazy danych" -#: src/Database/DBStructure.php:803 +#: src/Database/DBStructure.php:817 #, php-format msgid "%s: updating %s table." msgstr "%s: aktualizowanie %s tabeli." @@ -3583,81 +3673,81 @@ msgstr "Wewnętrzny błąd serwera" msgid "Legacy module file not found: %s" msgstr "Nie znaleziono pliku modułu: %s" -#: src/Model/Contact.php:1089 src/Model/Contact.php:1101 +#: src/Model/Contact.php:1104 src/Model/Contact.php:1116 msgid "UnFollow" msgstr "Przestań obserwować" -#: src/Model/Contact.php:1107 src/Module/Admin/Users/Pending.php:107 +#: src/Model/Contact.php:1122 src/Module/Admin/Users/Pending.php:107 #: src/Module/Notifications/Introductions.php:130 #: src/Module/Notifications/Introductions.php:202 msgid "Approve" msgstr "Zatwierdź" -#: src/Model/Contact.php:1519 +#: src/Model/Contact.php:1534 msgid "Organisation" msgstr "Organizacja" -#: src/Model/Contact.php:1527 +#: src/Model/Contact.php:1542 msgid "Forum" msgstr "Forum" -#: src/Model/Contact.php:2503 +#: src/Model/Contact.php:2625 msgid "Disallowed profile URL." msgstr "Nie dozwolony adres URL profilu." -#: src/Model/Contact.php:2508 src/Module/Friendica.php:81 +#: src/Model/Contact.php:2630 src/Module/Friendica.php:81 msgid "Blocked domain" msgstr "Zablokowana domena" -#: src/Model/Contact.php:2513 +#: src/Model/Contact.php:2635 msgid "Connect URL missing." msgstr "Brak adresu URL połączenia." -#: src/Model/Contact.php:2522 +#: src/Model/Contact.php:2644 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "Nie można dodać kontaktu. Sprawdź odpowiednie poświadczenia sieciowe na stronie Ustawienia -> Sieci społecznościowe." -#: src/Model/Contact.php:2559 +#: src/Model/Contact.php:2686 msgid "The profile address specified does not provide adequate information." msgstr "Dany adres profilu nie dostarcza odpowiednich informacji." -#: src/Model/Contact.php:2561 +#: src/Model/Contact.php:2688 msgid "No compatible communication protocols or feeds were discovered." msgstr "Nie znaleziono żadnych kompatybilnych protokołów komunikacyjnych ani źródeł." -#: src/Model/Contact.php:2564 +#: src/Model/Contact.php:2691 msgid "An author or name was not found." msgstr "Autor lub nazwa nie zostało znalezione." -#: src/Model/Contact.php:2567 +#: src/Model/Contact.php:2694 msgid "No browser URL could be matched to this address." msgstr "Przeglądarka WWW nie może odnaleźć podanego adresu" -#: src/Model/Contact.php:2570 +#: src/Model/Contact.php:2697 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "Nie można dopasować @-stylu Adres identyfikacyjny ze znanym protokołem lub kontaktem e-mail." -#: src/Model/Contact.php:2571 +#: src/Model/Contact.php:2698 msgid "Use mailto: in front of address to force email check." msgstr "Użyj mailto: przed adresem, aby wymusić sprawdzanie poczty e-mail." -#: src/Model/Contact.php:2577 +#: src/Model/Contact.php:2704 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "Określony adres profilu należy do sieci, która została wyłączona na tej stronie." -#: src/Model/Contact.php:2582 +#: src/Model/Contact.php:2709 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "Profil ograniczony. Ta osoba będzie niezdolna do odbierania osobistych powiadomień od ciebie." -#: src/Model/Contact.php:2641 +#: src/Model/Contact.php:2768 msgid "Unable to retrieve contact information." msgstr "Nie można otrzymać informacji kontaktowych" @@ -3665,41 +3755,41 @@ msgstr "Nie można otrzymać informacji kontaktowych" msgid "l F d, Y \\@ g:i A \\G\\M\\TP (e)" msgstr "" -#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:464 +#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:463 #: src/Model/Event.php:897 msgid "Starts:" msgstr "Rozpoczęcie:" -#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:465 +#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:464 #: src/Model/Event.php:901 msgid "Finishes:" msgstr "Zakończenie:" -#: src/Model/Event.php:414 +#: src/Model/Event.php:413 msgid "all-day" msgstr "cały dzień" -#: src/Model/Event.php:440 +#: src/Model/Event.php:439 msgid "Sept" msgstr "Wrz" -#: src/Model/Event.php:462 +#: src/Model/Event.php:461 msgid "No events to display" msgstr "Brak wydarzeń do wyświetlenia" -#: src/Model/Event.php:578 +#: src/Model/Event.php:577 msgid "l, F j" msgstr "l, F j" -#: src/Model/Event.php:609 +#: src/Model/Event.php:608 msgid "Edit event" msgstr "Edytuj wydarzenie" -#: src/Model/Event.php:610 +#: src/Model/Event.php:609 msgid "Duplicate event" msgstr "Zduplikowane zdarzenie" -#: src/Model/Event.php:611 +#: src/Model/Event.php:610 msgid "Delete event" msgstr "Usuń wydarzenie" @@ -3723,112 +3813,112 @@ msgstr "Pokaż mapę" msgid "Hide map" msgstr "Ukryj mapę" -#: src/Model/Event.php:1009 +#: src/Model/Event.php:1010 #, php-format msgid "%s's birthday" msgstr "Urodziny %s" -#: src/Model/Event.php:1010 +#: src/Model/Event.php:1011 #, php-format msgid "Happy Birthday %s" msgstr "Wszystkiego najlepszego %s" -#: src/Model/Group.php:95 +#: 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 "Skasowana grupa o tej nazwie została przywrócona. Istniejące uprawnienia do pozycji mogą dotyczyć tej grupy i wszystkich przyszłych członków. Jeśli nie jest to zamierzone, utwórz inną grupę o innej nazwie." -#: src/Model/Group.php:486 +#: src/Model/Group.php:499 msgid "Default privacy group for new contacts" msgstr "Domyślne ustawienia prywatności dla nowych kontaktów" -#: src/Model/Group.php:518 +#: src/Model/Group.php:531 msgid "Everybody" msgstr "Wszyscy" -#: src/Model/Group.php:537 +#: src/Model/Group.php:550 msgid "edit" msgstr "edytuj" -#: src/Model/Group.php:569 +#: src/Model/Group.php:582 msgid "add" msgstr "dodaj" -#: src/Model/Group.php:574 +#: src/Model/Group.php:587 msgid "Edit group" msgstr "Edytuj grupy" -#: src/Model/Group.php:575 src/Module/Group.php:194 +#: src/Model/Group.php:588 src/Module/Group.php:194 msgid "Contacts not in any group" msgstr "Kontakt nie jest w żadnej grupie" -#: src/Model/Group.php:577 +#: src/Model/Group.php:590 msgid "Create a new group" msgstr "Stwórz nową grupę" -#: src/Model/Group.php:578 src/Module/Group.php:179 src/Module/Group.php:202 +#: src/Model/Group.php:591 src/Module/Group.php:179 src/Module/Group.php:202 #: src/Module/Group.php:277 msgid "Group Name: " msgstr "Nazwa grupy: " -#: src/Model/Group.php:579 +#: src/Model/Group.php:592 msgid "Edit groups" msgstr "Edytuj grupy" -#: src/Model/Item.php:1790 +#: src/Model/Item.php:1823 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "Wykryte języki w tym wpisie:\\n%s" -#: src/Model/Item.php:2696 +#: src/Model/Item.php:2730 msgid "activity" msgstr "aktywność" -#: src/Model/Item.php:2698 +#: src/Model/Item.php:2732 msgid "comment" msgstr "komentarz" -#: src/Model/Item.php:2701 +#: src/Model/Item.php:2735 msgid "post" msgstr "wpis" -#: src/Model/Item.php:2816 +#: src/Model/Item.php:2851 #, php-format msgid "Content warning: %s" msgstr "Ostrzeżenie o treści: %s" -#: src/Model/Item.php:3167 +#: src/Model/Item.php:3210 msgid "bytes" msgstr "bajty" -#: src/Model/Item.php:3201 +#: src/Model/Item.php:3244 #, php-format msgid "%s (%d%s, %d votes)" msgstr "%s (%d%s, %d głosów)" -#: src/Model/Item.php:3203 +#: src/Model/Item.php:3246 #, php-format msgid "%s (%d votes)" msgstr "%s (%d głosów)" -#: src/Model/Item.php:3208 +#: src/Model/Item.php:3251 #, php-format msgid "%d voters. Poll end: %s" msgstr "%d głosujących. Zakończenie głosowania: %s" -#: src/Model/Item.php:3210 +#: src/Model/Item.php:3253 #, php-format msgid "%d voters." msgstr "%d głosujących." -#: src/Model/Item.php:3212 +#: src/Model/Item.php:3255 #, php-format msgid "Poll end: %s" msgstr "Koniec ankiety: %s" -#: src/Model/Item.php:3246 src/Model/Item.php:3247 +#: src/Model/Item.php:3289 src/Model/Item.php:3290 msgid "View on separate page" msgstr "Zobacz na oddzielnej stronie" @@ -3836,147 +3926,147 @@ msgstr "Zobacz na oddzielnej stronie" msgid "[no subject]" msgstr "[bez tematu]" -#: src/Model/Profile.php:358 src/Module/Profile/Profile.php:256 +#: src/Model/Profile.php:359 src/Module/Profile/Profile.php:256 #: src/Module/Profile/Profile.php:258 msgid "Edit profile" msgstr "Edytuj profil" -#: src/Model/Profile.php:360 +#: src/Model/Profile.php:361 msgid "Change profile photo" msgstr "Zmień zdjęcie profilowe" -#: src/Model/Profile.php:373 src/Module/Directory.php:153 +#: src/Model/Profile.php:374 src/Module/Directory.php:153 #: src/Module/Profile/Profile.php:184 msgid "Homepage:" msgstr "Strona główna:" -#: src/Model/Profile.php:374 src/Module/Contact/Profile.php:375 +#: src/Model/Profile.php:375 src/Module/Contact/Profile.php:375 #: src/Module/Notifications/Introductions.php:187 msgid "About:" msgstr "O:" -#: src/Model/Profile.php:460 +#: src/Model/Profile.php:461 msgid "Atom feed" msgstr "Kanał Atom" -#: src/Model/Profile.php:504 +#: src/Model/Profile.php:505 msgid "F d" msgstr "F d" -#: src/Model/Profile.php:568 src/Model/Profile.php:652 +#: src/Model/Profile.php:569 src/Model/Profile.php:653 msgid "[today]" msgstr "[dziś]" -#: src/Model/Profile.php:577 +#: src/Model/Profile.php:578 msgid "Birthday Reminders" msgstr "Przypomnienia o urodzinach" -#: src/Model/Profile.php:578 +#: src/Model/Profile.php:579 msgid "Birthdays this week:" msgstr "Urodziny w tym tygodniu:" -#: src/Model/Profile.php:601 +#: src/Model/Profile.php:602 msgid "g A l F d" msgstr "g A I F d" -#: src/Model/Profile.php:639 +#: src/Model/Profile.php:640 msgid "[No description]" msgstr "[Brak opisu]" -#: src/Model/Profile.php:665 +#: src/Model/Profile.php:666 msgid "Event Reminders" msgstr "Przypominacze wydarzeń" -#: src/Model/Profile.php:666 +#: src/Model/Profile.php:667 msgid "Upcoming events the next 7 days:" msgstr "Nadchodzące wydarzenia w ciągu następnych 7 dni:" -#: src/Model/Profile.php:854 +#: src/Model/Profile.php:855 #, php-format msgid "OpenWebAuth: %1$s welcomes %2$s" msgstr "OpenWebAuth: %1$s wita %2$s" -#: src/Model/Profile.php:986 +#: src/Model/Profile.php:981 msgid "Hometown:" msgstr "Miasto rodzinne:" -#: src/Model/Profile.php:987 +#: src/Model/Profile.php:982 msgid "Marital Status:" msgstr "Stan cywilny:" -#: src/Model/Profile.php:988 +#: src/Model/Profile.php:983 msgid "With:" msgstr "Z:" -#: src/Model/Profile.php:989 +#: src/Model/Profile.php:984 msgid "Since:" msgstr "Od:" -#: src/Model/Profile.php:990 +#: src/Model/Profile.php:985 msgid "Sexual Preference:" msgstr "Preferencje seksualne:" -#: src/Model/Profile.php:991 +#: src/Model/Profile.php:986 msgid "Political Views:" msgstr "Poglądy polityczne:" -#: src/Model/Profile.php:992 +#: src/Model/Profile.php:987 msgid "Religious Views:" msgstr "Poglądy religijne:" -#: src/Model/Profile.php:993 +#: src/Model/Profile.php:988 msgid "Likes:" msgstr "Lubię to:" -#: src/Model/Profile.php:994 +#: src/Model/Profile.php:989 msgid "Dislikes:" msgstr "Nie lubię tego:" -#: src/Model/Profile.php:995 +#: src/Model/Profile.php:990 msgid "Title/Description:" msgstr "Tytuł/Opis:" -#: src/Model/Profile.php:996 src/Module/Admin/Summary.php:234 +#: src/Model/Profile.php:991 src/Module/Admin/Summary.php:234 msgid "Summary" msgstr "Podsumowanie" -#: src/Model/Profile.php:997 +#: src/Model/Profile.php:992 msgid "Musical interests" msgstr "Muzyka" -#: src/Model/Profile.php:998 +#: src/Model/Profile.php:993 msgid "Books, literature" msgstr "Literatura" -#: src/Model/Profile.php:999 +#: src/Model/Profile.php:994 msgid "Television" msgstr "Telewizja" -#: src/Model/Profile.php:1000 +#: src/Model/Profile.php:995 msgid "Film/dance/culture/entertainment" msgstr "Film/taniec/kultura/rozrywka" -#: src/Model/Profile.php:1001 +#: src/Model/Profile.php:996 msgid "Hobbies/Interests" msgstr "Zainteresowania" -#: src/Model/Profile.php:1002 +#: src/Model/Profile.php:997 msgid "Love/romance" msgstr "Miłość/romans" -#: src/Model/Profile.php:1003 +#: src/Model/Profile.php:998 msgid "Work/employment" msgstr "Praca/zatrudnienie" -#: src/Model/Profile.php:1004 +#: src/Model/Profile.php:999 msgid "School/education" msgstr "Szkoła/edukacja" -#: src/Model/Profile.php:1005 +#: src/Model/Profile.php:1000 msgid "Contact information and Social Networks" msgstr "Dane kontaktowe i Sieci społecznościowe" -#: src/Model/User.php:210 src/Model/User.php:1058 +#: src/Model/User.php:212 src/Model/User.php:1058 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "POWAŻNY BŁĄD: niepowodzenie podczas tworzenia kluczy zabezpieczeń." @@ -4023,13 +4113,13 @@ msgstr "Zaproszenie niezweryfikowane." msgid "Invalid OpenID url" msgstr "Nieprawidłowy adres url OpenID" -#: src/Model/User.php:970 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 msgid "" "We encountered a problem while logging in with the OpenID you provided. " "Please check the correct spelling of the ID." msgstr "Napotkaliśmy problem podczas logowania z podanym przez nas identyfikatorem OpenID. Sprawdź poprawną pisownię identyfikatora." -#: src/Model/User.php:970 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 msgid "The error message was:" msgstr "Komunikat o błędzie:" @@ -4115,7 +4205,7 @@ msgstr "Wystąpił błąd podczas tworzenia domyślnej grupy kontaktów. Proszę msgid "Profile Photos" msgstr "Zdjęcie profilowe" -#: src/Model/User.php:1368 +#: src/Model/User.php:1367 #, php-format msgid "" "\n" @@ -4123,7 +4213,7 @@ msgid "" "\t\t\tthe administrator of %2$s has set up an account for you." msgstr "\n\t\tSzanowna/y %1$s,\n\t\t\tadministrator of %2$s założył dla Ciebie konto." -#: src/Model/User.php:1371 +#: src/Model/User.php:1370 #, php-format msgid "" "\n" @@ -4155,12 +4245,12 @@ msgid "" "\t\tThank you and welcome to %4$s." msgstr "\n\t\tDane logowania są następuje:\n\n\t\tPołożenie witryny:\t%1$s\n\t\tNazwa użytkownika\t\t:%2$s\n\t\tHasło:\t\t%3$s\n\n\t\tPo zalogowaniu możesz zmienić hasło do swojego konta na stronie \"Ustawienia\".\n\n\t\tProszę poświęć chwilę, aby przejrzeć inne ustawienia konta na tej stronie.\n\n\t\tMożesz również chcieć dodać podstawowe informacje do swojego domyślnego profilu\n\t\t(na stronie \"Profile\"), aby inne osoby mogły łatwo Cię znaleźć.\n\n\t\tZalecamy ustawienie imienia i nazwiska, dodanie zdjęcia profilowego,\n\t\tdodanie pewnych \"słów kluczowych\" profilu (bardzo przydatne w nawiązywaniu nowych znajomości) \n\t\ti być może miejsca, gdzie mieszkasz; jeśli nie chcesz podawać więcej szczegółów.\n\n\t\tW pełni szanujemy Twoje prawo do prywatności i żadna z tych danych nie jest konieczna.\n\t\tJeśli jesteś nowy i nie znasz tutaj nikogo, mogą one Ci pomóc,\n\t\tw pozyskaniu nowych i interesujących przyjaciół.\n\n\t\tJeśli kiedykolwiek zechcesz usunąć swoje konto, możesz to zrobić na stronie %1$s/removeme\n\n\t\tDziękujemy i zapraszamy do%4$s." -#: src/Model/User.php:1404 src/Model/User.php:1511 +#: src/Model/User.php:1403 src/Model/User.php:1510 #, php-format msgid "Registration details for %s" msgstr "Szczegóły rejestracji dla %s" -#: src/Model/User.php:1424 +#: src/Model/User.php:1423 #, php-format msgid "" "\n" @@ -4175,12 +4265,12 @@ msgid "" "\t\t" msgstr "\n\t\t\tSzanowny Użytkowniku %1$s,\n\t\t\t\tDziękujemy za rejestrację na stronie %2$s. Twoje konto czeka na zatwierdzenie przez administratora.\n\n\t\t\tTwoje dane do logowania są następujące:\n\n\t\t\tLokalizacja witryny:\t%3$s\n\t\t\tNazwa użytkownika:\t\t%4$s\n\t\t\tHasło:\t\t%5$s\n\t\t" -#: src/Model/User.php:1443 +#: src/Model/User.php:1442 #, php-format msgid "Registration at %s" msgstr "Rejestracja w %s" -#: src/Model/User.php:1467 +#: src/Model/User.php:1466 #, php-format msgid "" "\n" @@ -4189,7 +4279,7 @@ msgid "" "\t\t\t" msgstr "\n\t\t\t\tSzanowna/y %1$s,\n\t\t\t\tDziękujemy za rejestrację w %2$s. Twoje konto zostało utworzone.\n\t\t\t" -#: src/Model/User.php:1475 +#: src/Model/User.php:1474 #, php-format msgid "" "\n" @@ -4252,7 +4342,7 @@ msgstr "Zezwól" #: src/Module/Admin/Blocklist/Server/Index.php:78 #: src/Module/Admin/Federation.php:196 src/Module/Admin/Item/Delete.php:64 #: src/Module/Admin/Logs/Settings.php:79 src/Module/Admin/Logs/View.php:84 -#: src/Module/Admin/Queue.php:72 src/Module/Admin/Site.php:498 +#: src/Module/Admin/Queue.php:72 src/Module/Admin/Site.php:431 #: src/Module/Admin/Storage.php:138 src/Module/Admin/Summary.php:233 #: src/Module/Admin/Themes/Details.php:90 #: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:75 @@ -4264,7 +4354,7 @@ msgid "Administration" msgstr "Administracja" #: src/Module/Admin/Addons/Details.php:112 -#: src/Module/Admin/Addons/Index.php:68 src/Module/BaseAdmin.php:93 +#: src/Module/Admin/Addons/Index.php:68 src/Module/BaseAdmin.php:96 #: src/Module/BaseSettings.php:85 msgid "Addons" msgstr "Dodatki" @@ -4343,19 +4433,19 @@ msgstr "Usunięte" msgid "List of pending user deletions" msgstr "Lista oczekujących na usunięcie użytkowników" -#: src/Module/Admin/BaseUsers.php:100 src/Module/Settings/Account.php:468 +#: src/Module/Admin/BaseUsers.php:100 src/Module/Settings/Account.php:493 msgid "Normal Account Page" msgstr "Normalna strona konta" -#: src/Module/Admin/BaseUsers.php:101 src/Module/Settings/Account.php:475 +#: src/Module/Admin/BaseUsers.php:101 src/Module/Settings/Account.php:500 msgid "Soapbox Page" msgstr "Strona Soapbox" -#: src/Module/Admin/BaseUsers.php:102 src/Module/Settings/Account.php:482 +#: src/Module/Admin/BaseUsers.php:102 src/Module/Settings/Account.php:507 msgid "Public Forum" msgstr "Forum publiczne" -#: src/Module/Admin/BaseUsers.php:103 src/Module/Settings/Account.php:489 +#: src/Module/Admin/BaseUsers.php:103 src/Module/Settings/Account.php:514 msgid "Automatic Friend Page" msgstr "Automatyczna strona znajomego" @@ -4363,19 +4453,19 @@ msgstr "Automatyczna strona znajomego" msgid "Private Forum" msgstr "Prywatne forum" -#: src/Module/Admin/BaseUsers.php:107 src/Module/Settings/Account.php:440 +#: src/Module/Admin/BaseUsers.php:107 src/Module/Settings/Account.php:465 msgid "Personal Page" msgstr "Strona osobista" -#: src/Module/Admin/BaseUsers.php:108 src/Module/Settings/Account.php:447 +#: src/Module/Admin/BaseUsers.php:108 src/Module/Settings/Account.php:472 msgid "Organisation Page" msgstr "Strona Organizacji" -#: src/Module/Admin/BaseUsers.php:109 src/Module/Settings/Account.php:454 +#: src/Module/Admin/BaseUsers.php:109 src/Module/Settings/Account.php:479 msgid "News Page" msgstr "Strona Wiadomości" -#: src/Module/Admin/BaseUsers.php:110 src/Module/Settings/Account.php:461 +#: src/Module/Admin/BaseUsers.php:110 src/Module/Settings/Account.php:486 msgid "Community Forum" msgstr "Forum społecznościowe" @@ -4754,7 +4844,7 @@ msgid "" "only reflect the part of the network your node is aware of." msgstr "Ta strona zawiera kilka numerów do znanej części federacyjnej sieci społecznościowej, do której należy Twój węzeł Friendica. Liczby te nie są kompletne, ale odzwierciedlają tylko część sieci, o której wie twój węzeł." -#: src/Module/Admin/Federation.php:197 src/Module/BaseAdmin.php:87 +#: src/Module/Admin/Federation.php:197 src/Module/BaseAdmin.php:90 msgid "Federation Statistics" msgstr "Statystyki Federacji" @@ -4770,7 +4860,7 @@ msgstr "Obecnie ten węzeł jest świadomy %s węzłów (%s aktywnych użytkowni msgid "Item marked for deletion." msgstr "Przedmiot oznaczony do usunięcia." -#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:106 +#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:109 msgid "Delete Item" msgstr "Usuń przedmiot" @@ -4799,7 +4889,7 @@ msgstr "GUID" msgid "The GUID of the item you want to delete." msgstr "Identyfikator elementu GUID, który chcesz usunąć." -#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:116 +#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:119 msgid "Item Source" msgstr "Źródło elementu" @@ -4862,8 +4952,8 @@ msgstr "Dziennik PHP jest obecnie włączony." msgid "PHP log currently disabled." msgstr "Dziennik PHP jest obecnie wyłączony." -#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:108 -#: src/Module/BaseAdmin.php:109 +#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:111 +#: src/Module/BaseAdmin.php:112 msgid "Logs" msgstr "Dzienniki" @@ -4916,7 +5006,7 @@ msgid "" "is readable." msgstr "Nie udało się otworzyć pliku dziennika %1$s. Sprawdź, czy plik %1$s jest odczytywalny." -#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:110 +#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:113 msgid "View Logs" msgstr "Zobacz rejestry" @@ -5017,462 +5107,459 @@ msgstr "Parametry zadania" msgid "Priority" msgstr "Priorytet" -#: src/Module/Admin/Site.php:71 -msgid "Can not parse base url. Must have at least ://" -msgstr "Nie można zanalizować podstawowego adresu URL. Musi mieć co najmniej : //" - -#: src/Module/Admin/Site.php:125 -msgid "Relocation started. Could take a while to complete." -msgstr "Rozpoczęła się relokacja. Może trochę potrwać." - -#: src/Module/Admin/Site.php:403 src/Module/Settings/Display.php:138 +#: src/Module/Admin/Site.php:336 src/Module/Settings/Display.php:138 msgid "No special theme for mobile devices" msgstr "Brak specialnego motywu dla urządzeń mobilnych" -#: src/Module/Admin/Site.php:420 src/Module/Settings/Display.php:148 +#: src/Module/Admin/Site.php:353 src/Module/Settings/Display.php:148 #, php-format msgid "%s - (Experimental)" msgstr "%s- (Eksperymentalne)" -#: src/Module/Admin/Site.php:432 +#: src/Module/Admin/Site.php:365 msgid "No community page for local users" msgstr "Brak strony społeczności dla użytkowników lokalnych" -#: src/Module/Admin/Site.php:433 +#: src/Module/Admin/Site.php:366 msgid "No community page" msgstr "Brak strony społeczności" -#: src/Module/Admin/Site.php:434 +#: src/Module/Admin/Site.php:367 msgid "Public postings from users of this site" msgstr "Publikacje publiczne od użytkowników tej strony" -#: src/Module/Admin/Site.php:435 +#: src/Module/Admin/Site.php:368 msgid "Public postings from the federated network" msgstr "Publikacje wpisy ze sfederowanej sieci" -#: src/Module/Admin/Site.php:436 +#: src/Module/Admin/Site.php:369 msgid "Public postings from local users and the federated network" msgstr "Publikacje publiczne od użytkowników lokalnych i sieci federacyjnej" -#: src/Module/Admin/Site.php:442 +#: src/Module/Admin/Site.php:375 msgid "Multi user instance" msgstr "Tryb wielu użytkowników" -#: src/Module/Admin/Site.php:469 +#: src/Module/Admin/Site.php:402 msgid "Closed" msgstr "Zamknięte" -#: src/Module/Admin/Site.php:470 +#: src/Module/Admin/Site.php:403 msgid "Requires approval" msgstr "Wymaga zatwierdzenia" -#: src/Module/Admin/Site.php:471 +#: src/Module/Admin/Site.php:404 msgid "Open" msgstr "Otwarta" -#: src/Module/Admin/Site.php:475 src/Module/Install.php:222 +#: src/Module/Admin/Site.php:408 src/Module/Install.php:222 msgid "No SSL policy, links will track page SSL state" msgstr "Brak SSL, linki będą śledzić stan SSL" -#: src/Module/Admin/Site.php:476 src/Module/Install.php:223 +#: src/Module/Admin/Site.php:409 src/Module/Install.php:223 msgid "Force all links to use SSL" msgstr "Wymuś używanie SSL na wszystkich odnośnikach" -#: src/Module/Admin/Site.php:477 src/Module/Install.php:224 +#: src/Module/Admin/Site.php:410 src/Module/Install.php:224 msgid "Self-signed certificate, use SSL for local links only (discouraged)" msgstr "Certyfikat z podpisem własnym, używaj SSL tylko dla łączy lokalnych (odradzane)" -#: src/Module/Admin/Site.php:481 +#: src/Module/Admin/Site.php:414 msgid "Don't check" msgstr "Nie sprawdzaj" -#: src/Module/Admin/Site.php:482 +#: src/Module/Admin/Site.php:415 msgid "check the stable version" msgstr "sprawdź wersję stabilną" -#: src/Module/Admin/Site.php:483 +#: src/Module/Admin/Site.php:416 msgid "check the development version" msgstr "sprawdź wersję rozwojową" -#: src/Module/Admin/Site.php:487 +#: src/Module/Admin/Site.php:420 msgid "none" msgstr "brak" -#: src/Module/Admin/Site.php:488 +#: src/Module/Admin/Site.php:421 msgid "Local contacts" msgstr "Kontakty lokalne" -#: src/Module/Admin/Site.php:489 +#: src/Module/Admin/Site.php:422 msgid "Interactors" msgstr "Interaktorzy" -#: src/Module/Admin/Site.php:499 src/Module/BaseAdmin.php:90 +#: src/Module/Admin/Site.php:432 src/Module/BaseAdmin.php:93 msgid "Site" msgstr "Strona" -#: src/Module/Admin/Site.php:500 +#: src/Module/Admin/Site.php:433 msgid "General Information" msgstr "Ogólne informacje" -#: src/Module/Admin/Site.php:502 +#: src/Module/Admin/Site.php:435 msgid "Republish users to directory" msgstr "Ponownie opublikuj użytkowników w katalogu" -#: src/Module/Admin/Site.php:503 src/Module/Register.php:152 +#: src/Module/Admin/Site.php:436 src/Module/Register.php:152 msgid "Registration" msgstr "Rejestracja" -#: src/Module/Admin/Site.php:504 +#: src/Module/Admin/Site.php:437 msgid "File upload" msgstr "Przesyłanie plików" -#: src/Module/Admin/Site.php:505 +#: src/Module/Admin/Site.php:438 msgid "Policies" msgstr "Zasady" -#: src/Module/Admin/Site.php:507 +#: src/Module/Admin/Site.php:440 msgid "Auto Discovered Contact Directory" msgstr "Katalog kontaktów automatycznie odkrytych" -#: src/Module/Admin/Site.php:508 +#: src/Module/Admin/Site.php:441 msgid "Performance" msgstr "Ustawienia" -#: src/Module/Admin/Site.php:509 +#: src/Module/Admin/Site.php:442 msgid "Worker" msgstr "Worker" -#: src/Module/Admin/Site.php:510 +#: src/Module/Admin/Site.php:443 msgid "Message Relay" msgstr "Przekaźnik wiadomości" -#: src/Module/Admin/Site.php:511 +#: src/Module/Admin/Site.php:444 msgid "" "Use the command \"console relay\" in the command line to add or remove " "relays." msgstr "Użyj polecenia „console relay” w wierszu poleceń, aby dodać lub usunąć przekaźniki." -#: src/Module/Admin/Site.php:512 +#: src/Module/Admin/Site.php:445 msgid "The system is not subscribed to any relays at the moment." msgstr "System nie jest aktualnie objęty abonamentem na żadne przekaźniki." -#: src/Module/Admin/Site.php:513 +#: src/Module/Admin/Site.php:446 msgid "The system is currently subscribed to the following relays:" msgstr "System jest obecnie objęty abonamentem na następujące przekaźniki:" -#: src/Module/Admin/Site.php:515 -msgid "Relocate Instance" -msgstr "Zmień lokalizację" +#: src/Module/Admin/Site.php:448 +msgid "Relocate Node" +msgstr "Przenieś węzeł" -#: src/Module/Admin/Site.php:516 +#: src/Module/Admin/Site.php:449 msgid "" -"Warning! Advanced function. Could make this server " -"unreachable." -msgstr "Ostrzeżenie! Zaawansowana funkcja. Może sprawić, że ten serwer będzie nieosiągalny." +"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 "Przeniesienie węzła umożliwia zmianę domeny DNS tego węzła i zachowanie wszystkich istniejących użytkowników i wpisów. Ten proces zajmuje trochę czasu i można go uruchomić tylko za pomocą konsolowego polecenia relokacji w następujący sposób:" -#: src/Module/Admin/Site.php:520 +#: src/Module/Admin/Site.php:450 +msgid "(Friendica directory)# bin/console relocate https://newdomain.com" +msgstr "(Katalog Friendica)# bin/console relocate https://nowadomena.pl" + +#: src/Module/Admin/Site.php:454 msgid "Site name" msgstr "Nazwa strony" -#: src/Module/Admin/Site.php:521 +#: src/Module/Admin/Site.php:455 msgid "Sender Email" msgstr "E-mail nadawcy" -#: src/Module/Admin/Site.php:521 +#: src/Module/Admin/Site.php:455 msgid "" "The email address your server shall use to send notification emails from." msgstr "Adres e-mail używany przez Twój serwer do wysyłania e-maili z powiadomieniami." -#: src/Module/Admin/Site.php:522 +#: src/Module/Admin/Site.php:456 msgid "Name of the system actor" msgstr "Imię i nazwisko aktora systemu" -#: src/Module/Admin/Site.php:522 +#: src/Module/Admin/Site.php:456 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 "Nazwa wewnętrznego konta systemowego, które jest używane do wykonywania żądań ActivityPub. Musi to być nieużywana nazwa użytkownika. Jeśli jest ustawiona, nie można jej zmienić ponownie." -#: src/Module/Admin/Site.php:523 +#: src/Module/Admin/Site.php:457 msgid "Banner/Logo" msgstr "Baner/Logo" -#: src/Module/Admin/Site.php:524 +#: src/Module/Admin/Site.php:458 msgid "Email Banner/Logo" msgstr "Baner/logo e-maila" -#: src/Module/Admin/Site.php:525 +#: src/Module/Admin/Site.php:459 msgid "Shortcut icon" msgstr "Ikona skrótu" -#: src/Module/Admin/Site.php:525 +#: src/Module/Admin/Site.php:459 msgid "Link to an icon that will be used for browsers." msgstr "Link do ikony, która będzie używana w przeglądarkach." -#: src/Module/Admin/Site.php:526 +#: src/Module/Admin/Site.php:460 msgid "Touch icon" msgstr "Dołącz ikonę" -#: src/Module/Admin/Site.php:526 +#: src/Module/Admin/Site.php:460 msgid "Link to an icon that will be used for tablets and mobiles." msgstr "Link do ikony, która będzie używana w tabletach i telefonach komórkowych." -#: src/Module/Admin/Site.php:527 +#: src/Module/Admin/Site.php:461 msgid "Additional Info" msgstr "Dodatkowe informacje" -#: src/Module/Admin/Site.php:527 +#: src/Module/Admin/Site.php:461 #, php-format msgid "" "For public servers: you can add additional information here that will be " "listed at %s/servers." msgstr "W przypadku serwerów publicznych: możesz tu dodać dodatkowe informacje, które będą wymienione na %s/servers." -#: src/Module/Admin/Site.php:528 +#: src/Module/Admin/Site.php:462 msgid "System language" msgstr "Język systemu" -#: src/Module/Admin/Site.php:529 +#: src/Module/Admin/Site.php:463 msgid "System theme" msgstr "Motyw systemowy" -#: src/Module/Admin/Site.php:529 +#: src/Module/Admin/Site.php:463 #, php-format msgid "" "Default system theme - may be over-ridden by user profiles - Change default theme settings" msgstr "Domyślny motyw systemu - może być nadpisywany przez profile użytkowników - Zmień domyślne ustawienia motywu" -#: src/Module/Admin/Site.php:530 +#: src/Module/Admin/Site.php:464 msgid "Mobile system theme" msgstr "Motyw systemu mobilnego" -#: src/Module/Admin/Site.php:530 +#: src/Module/Admin/Site.php:464 msgid "Theme for mobile devices" msgstr "Motyw na urządzenia mobilne" -#: src/Module/Admin/Site.php:531 src/Module/Install.php:232 +#: src/Module/Admin/Site.php:465 src/Module/Install.php:232 msgid "SSL link policy" msgstr "Polityka odnośników SSL" -#: src/Module/Admin/Site.php:531 src/Module/Install.php:234 +#: src/Module/Admin/Site.php:465 src/Module/Install.php:234 msgid "Determines whether generated links should be forced to use SSL" msgstr "Określa, czy generowane odnośniki będą obowiązkowo używały SSL" -#: src/Module/Admin/Site.php:532 +#: src/Module/Admin/Site.php:466 msgid "Force SSL" msgstr "Wymuś SSL" -#: src/Module/Admin/Site.php:532 +#: src/Module/Admin/Site.php:466 msgid "" "Force all Non-SSL requests to SSL - Attention: on some systems it could lead" " to endless loops." msgstr "Wymuszaj wszystkie żądania SSL bez SSL - Uwaga: w niektórych systemach może to prowadzić do niekończących się pętli." -#: src/Module/Admin/Site.php:533 +#: src/Module/Admin/Site.php:467 msgid "Show help entry from navigation menu" msgstr "Pokaż wpis pomocy z menu nawigacyjnego" -#: src/Module/Admin/Site.php:533 +#: src/Module/Admin/Site.php:467 msgid "" "Displays the menu entry for the Help pages from the navigation menu. It is " "always accessible by calling /help directly." msgstr "Wyświetla pozycję menu dla stron pomocy z menu nawigacyjnego. Jest zawsze dostępna, odwołując się bezpośrednio do /help." -#: src/Module/Admin/Site.php:534 +#: src/Module/Admin/Site.php:468 msgid "Single user instance" msgstr "Tryb pojedynczego użytkownika" -#: src/Module/Admin/Site.php:534 +#: src/Module/Admin/Site.php:468 msgid "Make this instance multi-user or single-user for the named user" msgstr "Ustawia tryb dla wielu użytkowników lub pojedynczego użytkownika dla nazwanego użytkownika" -#: src/Module/Admin/Site.php:536 +#: src/Module/Admin/Site.php:470 msgid "Maximum image size" msgstr "Maksymalny rozmiar zdjęcia" -#: src/Module/Admin/Site.php:536 +#: src/Module/Admin/Site.php:470 msgid "" "Maximum size in bytes of uploaded images. Default is 0, which means no " "limits." msgstr "Maksymalny rozmiar w bitach dla wczytywanego obrazu . Domyślnie jest to 0 , co oznacza bez limitu ." -#: src/Module/Admin/Site.php:537 +#: src/Module/Admin/Site.php:471 msgid "Maximum image length" msgstr "Maksymalna długość obrazu" -#: src/Module/Admin/Site.php:537 +#: src/Module/Admin/Site.php:471 msgid "" "Maximum length in pixels of the longest side of uploaded images. Default is " "-1, which means no limits." msgstr "Maksymalna długość w pikselach dłuższego boku przesyłanego obrazu. Wartością domyślną jest -1, co oznacza brak ograniczeń." -#: src/Module/Admin/Site.php:538 +#: src/Module/Admin/Site.php:472 msgid "JPEG image quality" msgstr "Jakość obrazu JPEG" -#: src/Module/Admin/Site.php:538 +#: src/Module/Admin/Site.php:472 msgid "" "Uploaded JPEGS will be saved at this quality setting [0-100]. Default is " "100, which is full quality." msgstr "Przesłane pliki JPEG zostaną zapisane w tym ustawieniu jakości [0-100]. Domyślna wartość to 100, która jest pełną jakością." -#: src/Module/Admin/Site.php:540 +#: src/Module/Admin/Site.php:474 msgid "Register policy" msgstr "Zasady rejestracji" -#: src/Module/Admin/Site.php:541 +#: src/Module/Admin/Site.php:475 msgid "Maximum Daily Registrations" msgstr "Maksymalna dzienna rejestracja" -#: src/Module/Admin/Site.php:541 +#: src/Module/Admin/Site.php:475 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 "Jeśli rejestracja powyżej jest dozwolona, to określa maksymalną liczbę nowych rejestracji użytkowników do zaakceptowania na dzień. Jeśli rejestracja jest ustawiona na \"Zamknięta\", to ustawienie to nie ma wpływu." -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:476 msgid "Register text" msgstr "Zarejestruj tekst" -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:476 msgid "" "Will be displayed prominently on the registration page. You can use BBCode " "here." msgstr "Będą wyświetlane w widocznym miejscu na stronie rejestracji. Możesz użyć BBCode tutaj." -#: src/Module/Admin/Site.php:543 +#: src/Module/Admin/Site.php:477 msgid "Forbidden Nicknames" msgstr "Zakazane pseudonimy" -#: src/Module/Admin/Site.php:543 +#: src/Module/Admin/Site.php:477 msgid "" "Comma separated list of nicknames that are forbidden from registration. " "Preset is a list of role names according RFC 2142." msgstr "Lista oddzielonych przecinkami pseudonimów, których nie wolno rejestrować. Preset to lista nazw ról zgodnie z RFC 2142." -#: src/Module/Admin/Site.php:544 +#: src/Module/Admin/Site.php:478 msgid "Accounts abandoned after x days" msgstr "Konta porzucone po x dni" -#: src/Module/Admin/Site.php:544 +#: src/Module/Admin/Site.php:478 msgid "" "Will not waste system resources polling external sites for abandonded " "accounts. Enter 0 for no time limit." msgstr "Nie będzie marnować zasobów systemu wypytując zewnętrzne strony o opuszczone konta. Ustaw 0 dla braku limitu czasu ." -#: src/Module/Admin/Site.php:545 +#: src/Module/Admin/Site.php:479 msgid "Allowed friend domains" msgstr "Dozwolone domeny przyjaciół" -#: src/Module/Admin/Site.php:545 +#: src/Module/Admin/Site.php:479 msgid "" "Comma separated list of domains which are allowed to establish friendships " "with this site. Wildcards are accepted. Empty to allow any domains" msgstr "Rozdzielana przecinkami lista domen, które mogą nawiązywać przyjaźnie z tą witryną. Symbole wieloznaczne są akceptowane. Pozostaw puste by zezwolić każdej domenie na zaprzyjaźnienie." -#: src/Module/Admin/Site.php:546 +#: src/Module/Admin/Site.php:480 msgid "Allowed email domains" msgstr "Dozwolone domeny e-mailowe" -#: src/Module/Admin/Site.php:546 +#: src/Module/Admin/Site.php:480 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 "Rozdzielana przecinkami lista domen dozwolonych w adresach e-mail do rejestracji na tej stronie. Symbole wieloznaczne są akceptowane. Opróżnij, aby zezwolić na dowolne domeny" -#: src/Module/Admin/Site.php:547 +#: src/Module/Admin/Site.php:481 msgid "No OEmbed rich content" msgstr "Brak treści multimedialnych ze znaczkiem HTML" -#: src/Module/Admin/Site.php:547 +#: src/Module/Admin/Site.php:481 msgid "" "Don't show the rich content (e.g. embedded PDF), except from the domains " "listed below." msgstr "Nie wyświetlaj zasobów treści (np. osadzonego pliku PDF), z wyjątkiem domen wymienionych poniżej." -#: src/Module/Admin/Site.php:548 +#: src/Module/Admin/Site.php:482 msgid "Trusted third-party domains" msgstr "Zaufane domeny zewnętrzne" -#: src/Module/Admin/Site.php:548 +#: src/Module/Admin/Site.php:482 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 "Oddzielona przecinkami lista domen, z których treść może być osadzana we wpisach, tak jak w przypadku OEmbed. Dozwolone są również wszystkie subdomeny wymienionych domen." -#: src/Module/Admin/Site.php:549 +#: src/Module/Admin/Site.php:483 msgid "Block public" msgstr "Blokuj publicznie" -#: src/Module/Admin/Site.php:549 +#: src/Module/Admin/Site.php:483 msgid "" "Check to block public access to all otherwise public personal pages on this " "site unless you are currently logged in." msgstr "Zaznacz, aby zablokować publiczny dostęp do wszystkich publicznych stron prywatnych w tej witrynie, chyba że jesteś zalogowany." -#: src/Module/Admin/Site.php:550 +#: src/Module/Admin/Site.php:484 msgid "Force publish" msgstr "Wymuś publikację" -#: src/Module/Admin/Site.php:550 +#: src/Module/Admin/Site.php:484 msgid "" "Check to force all profiles on this site to be listed in the site directory." msgstr "Zaznacz, aby wymusić umieszczenie wszystkich profili w tej witrynie w katalogu witryny." -#: src/Module/Admin/Site.php:550 +#: src/Module/Admin/Site.php:484 msgid "Enabling this may violate privacy laws like the GDPR" msgstr "Włączenie tego może naruszyć prawa ochrony prywatności, takie jak GDPR" -#: src/Module/Admin/Site.php:551 +#: src/Module/Admin/Site.php:485 msgid "Global directory URL" msgstr "Globalny adres URL katalogu" -#: src/Module/Admin/Site.php:551 +#: src/Module/Admin/Site.php:485 msgid "" "URL to the global directory. If this is not set, the global directory is " "completely unavailable to the application." msgstr "Adres URL do katalogu globalnego. Jeśli nie zostanie to ustawione, katalog globalny jest całkowicie niedostępny dla aplikacji." -#: src/Module/Admin/Site.php:552 +#: src/Module/Admin/Site.php:486 msgid "Private posts by default for new users" msgstr "Prywatne posty domyślnie dla nowych użytkowników" -#: src/Module/Admin/Site.php:552 +#: src/Module/Admin/Site.php:486 msgid "" "Set default post permissions for all new members to the default privacy " "group rather than public." msgstr "Ustaw domyślne uprawnienia do publikowania dla wszystkich nowych członków na domyślną grupę prywatności, a nie publiczną." -#: src/Module/Admin/Site.php:553 +#: src/Module/Admin/Site.php:487 msgid "Don't include post content in email notifications" msgstr "Nie wklejaj zawartości postu do powiadomienia o poczcie" -#: src/Module/Admin/Site.php:553 +#: src/Module/Admin/Site.php:487 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 "W celu ochrony prywatności, nie włączaj zawartości postu/komentarza/wiadomości prywatnej/etc. do powiadomień w wiadomościach mailowych wysyłanych z tej strony." -#: src/Module/Admin/Site.php:554 +#: src/Module/Admin/Site.php:488 msgid "Disallow public access to addons listed in the apps menu." msgstr "Nie zezwalaj na publiczny dostęp do dodatkowych wtyczek wyszczególnionych w menu aplikacji." -#: src/Module/Admin/Site.php:554 +#: src/Module/Admin/Site.php:488 msgid "" "Checking this box will restrict addons listed in the apps menu to members " "only." msgstr "Zaznaczenie tego pola spowoduje ograniczenie dodatków wymienionych w menu aplikacji tylko dla członków." -#: src/Module/Admin/Site.php:555 +#: src/Module/Admin/Site.php:489 msgid "Don't embed private images in posts" msgstr "Nie umieszczaj prywatnych zdjęć we wpisach" -#: src/Module/Admin/Site.php:555 +#: src/Module/Admin/Site.php:489 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 " @@ -5480,11 +5567,11 @@ msgid "" "while." msgstr "Nie zastępuj lokalnie hostowanych zdjęć prywatnych we wpisach za pomocą osadzonej kopii obrazu. Oznacza to, że osoby, które otrzymują posty zawierające prywatne zdjęcia, będą musiały uwierzytelnić i wczytać każdy obraz, co może trochę potrwać." -#: src/Module/Admin/Site.php:556 +#: src/Module/Admin/Site.php:490 msgid "Explicit Content" msgstr "Treści dla dorosłych" -#: src/Module/Admin/Site.php:556 +#: src/Module/Admin/Site.php:490 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 " @@ -5493,257 +5580,257 @@ msgid "" "will be shown at the user registration page." msgstr "Ustaw to, aby ogłosić, że Twój węzeł jest używany głównie do jawnej treści, która może nie być odpowiednia dla nieletnich. Informacje te zostaną opublikowane w informacjach o węźle i mogą zostać wykorzystane, np. w katalogu globalnym, aby filtrować węzeł z list węzłów do przyłączenia. Dodatkowo notatka o tym zostanie pokazana na stronie rejestracji użytkownika." -#: src/Module/Admin/Site.php:557 +#: src/Module/Admin/Site.php:491 msgid "Proxify external content" msgstr "Udostępniaj treści zewnętrzne" -#: src/Module/Admin/Site.php:557 +#: src/Module/Admin/Site.php:491 msgid "" "Route external content via the proxy functionality. This is used for example" " for some OEmbed accesses and in some other rare cases." msgstr "Kieruj zawartość zewnętrzną za pośrednictwem funkcji proxy. Jest to używane na przykład w przypadku niektórych dostępów OEmbed i w niektórych innych rzadkich przypadkach." -#: src/Module/Admin/Site.php:558 +#: src/Module/Admin/Site.php:492 msgid "Cache contact avatars" msgstr "Buforuj awatary kontaktów" -#: src/Module/Admin/Site.php:558 +#: src/Module/Admin/Site.php:492 msgid "" "Locally store the avatar pictures of the contacts. This uses a lot of " "storage space but it increases the performance." msgstr "Lokalnie przechowuj zdjęcia awatarów kontaktów. To zajmuje dużo miejsca, ale zwiększa wydajność." -#: src/Module/Admin/Site.php:559 +#: src/Module/Admin/Site.php:493 msgid "Allow Users to set remote_self" msgstr "Zezwól użytkownikom na ustawienie remote_self" -#: src/Module/Admin/Site.php:559 +#: src/Module/Admin/Site.php:493 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 "Po sprawdzeniu tego każdy użytkownik może zaznaczyć każdy kontakt jako zdalny w oknie dialogowym kontaktu naprawczego. Ustawienie tej flagi na kontakcie powoduje dublowanie każdego wpisu tego kontaktu w strumieniu użytkowników." -#: src/Module/Admin/Site.php:560 +#: src/Module/Admin/Site.php:494 msgid "Enable multiple registrations" msgstr "Włącz wiele rejestracji" -#: src/Module/Admin/Site.php:560 +#: src/Module/Admin/Site.php:494 msgid "Enable users to register additional accounts for use as pages." msgstr "Zezwól użytkownikom na rejestrowanie dodatkowych kont do użytku jako strony." -#: src/Module/Admin/Site.php:561 +#: src/Module/Admin/Site.php:495 msgid "Enable OpenID" msgstr "Włącz OpenID" -#: src/Module/Admin/Site.php:561 +#: src/Module/Admin/Site.php:495 msgid "Enable OpenID support for registration and logins." msgstr "Włącz obsługę OpenID dla rejestracji i logowania." -#: src/Module/Admin/Site.php:562 +#: src/Module/Admin/Site.php:496 msgid "Enable Fullname check" msgstr "Włącz sprawdzanie pełnej nazwy" -#: src/Module/Admin/Site.php:562 +#: src/Module/Admin/Site.php:496 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 "Włącz sprawdzenie, aby zezwolić użytkownikom tylko na rejestrację ze spacją między imieniem a nazwiskiem w ich pełnym imieniu." -#: src/Module/Admin/Site.php:563 +#: src/Module/Admin/Site.php:497 msgid "Community pages for visitors" msgstr "Strony społecznościowe dla odwiedzających" -#: src/Module/Admin/Site.php:563 +#: src/Module/Admin/Site.php:497 msgid "" "Which community pages should be available for visitors. Local users always " "see both pages." msgstr "Które strony społeczności powinny być dostępne dla odwiedzających. Lokalni użytkownicy zawsze widzą obie strony." -#: src/Module/Admin/Site.php:564 +#: src/Module/Admin/Site.php:498 msgid "Posts per user on community page" msgstr "Lista wpisów użytkownika na stronie społeczności" -#: src/Module/Admin/Site.php:564 +#: src/Module/Admin/Site.php:498 msgid "" "The maximum number of posts per user on the community page. (Not valid for " "\"Global Community\")" msgstr "Maksymalna liczba postów na użytkownika na stronie społeczności. (Nie dotyczy „Globalnej społeczności”)" -#: src/Module/Admin/Site.php:566 +#: src/Module/Admin/Site.php:500 msgid "Enable Mail support" msgstr "Włącz obsługę maili" -#: src/Module/Admin/Site.php:566 +#: src/Module/Admin/Site.php:500 msgid "" "Enable built-in mail support to poll IMAP folders and to reply via mail." msgstr "Włącz wbudowaną obsługę poczty, aby odpytywać katalogi IMAP i odpowiadać pocztą." -#: src/Module/Admin/Site.php:567 +#: src/Module/Admin/Site.php:501 msgid "" "Mail support can't be enabled because the PHP IMAP module is not installed." msgstr "Nie można włączyć obsługi poczty, ponieważ moduł PHP IMAP nie jest zainstalowany." -#: src/Module/Admin/Site.php:568 +#: src/Module/Admin/Site.php:502 msgid "Enable OStatus support" msgstr "Włącz obsługę OStatus" -#: src/Module/Admin/Site.php:568 +#: src/Module/Admin/Site.php:502 msgid "" "Enable built-in OStatus (StatusNet, GNU Social etc.) compatibility. All " "communications in OStatus are public." msgstr "Włącz wbudowaną kompatybilność z OStatus (StatusNet, GNU Social itp.). Wszystkie komunikaty w OSstatus są publiczne." -#: src/Module/Admin/Site.php:570 +#: src/Module/Admin/Site.php:504 msgid "" "Diaspora support can't be enabled because Friendica was installed into a sub" " directory." msgstr "Obsługa Diaspory nie może być włączona, ponieważ Friendica została zainstalowana w podkatalogu." -#: src/Module/Admin/Site.php:571 +#: src/Module/Admin/Site.php:505 msgid "Enable Diaspora support" msgstr "Włączyć obsługę Diaspory" -#: src/Module/Admin/Site.php:571 +#: src/Module/Admin/Site.php:505 msgid "" "Enable built-in Diaspora network compatibility for communicating with " "diaspora servers." msgstr "Włącz wbudowaną kompatybilność sieci Diaspora do komunikacji z serwerami diaspory." -#: src/Module/Admin/Site.php:572 +#: src/Module/Admin/Site.php:506 msgid "Verify SSL" msgstr "Weryfikacja SSL" -#: src/Module/Admin/Site.php:572 +#: src/Module/Admin/Site.php:506 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 "Jeśli chcesz, możesz włączyć ścisłe sprawdzanie certyfikatu. Oznacza to, że nie możesz połączyć się (w ogóle) z własnoręcznie podpisanymi stronami SSL." -#: src/Module/Admin/Site.php:573 +#: src/Module/Admin/Site.php:507 msgid "Proxy user" msgstr "Użytkownik proxy" -#: src/Module/Admin/Site.php:573 +#: src/Module/Admin/Site.php:507 msgid "User name for the proxy server." msgstr "Nazwa użytkownika serwera proxy." -#: src/Module/Admin/Site.php:574 +#: src/Module/Admin/Site.php:508 msgid "Proxy URL" msgstr "URL pośrednika" -#: src/Module/Admin/Site.php:574 +#: src/Module/Admin/Site.php:508 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 "Jeśli chcesz używać serwera proxy, którego Friendica powinna używać do łączenia się z siecią, umieść tutaj adres URL proxy." -#: src/Module/Admin/Site.php:575 +#: src/Module/Admin/Site.php:509 msgid "Network timeout" msgstr "Limit czasu sieci" -#: src/Module/Admin/Site.php:575 +#: src/Module/Admin/Site.php:509 msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." msgstr "Wartość jest w sekundach. Ustaw na 0 dla nieograniczonej (niezalecane)." -#: src/Module/Admin/Site.php:576 +#: src/Module/Admin/Site.php:510 msgid "Maximum Load Average" msgstr "Maksymalne obciążenie średnie" -#: src/Module/Admin/Site.php:576 +#: src/Module/Admin/Site.php:510 #, php-format msgid "" "Maximum system load before delivery and poll processes are deferred - " "default %d." msgstr "Maksymalne obciążenie systemu przed dostarczeniem i procesami odpytywania jest odroczone - domyślnie %d." -#: src/Module/Admin/Site.php:577 +#: src/Module/Admin/Site.php:511 msgid "Minimal Memory" msgstr "Minimalna pamięć" -#: src/Module/Admin/Site.php:577 +#: src/Module/Admin/Site.php:511 msgid "" "Minimal free memory in MB for the worker. Needs access to /proc/meminfo - " "default 0 (deactivated)." msgstr "Minimalna wolna pamięć w MB dla workera. Potrzebuje dostępu do /proc/ meminfo - domyślnie 0 (wyłączone)." -#: src/Module/Admin/Site.php:578 +#: src/Module/Admin/Site.php:512 msgid "Periodically optimize tables" msgstr "Okresowo optymalizuj tabele" -#: src/Module/Admin/Site.php:578 +#: src/Module/Admin/Site.php:512 msgid "Periodically optimize tables like the cache and the workerqueue" msgstr "Okresowo optymalizuj tabele, takie jak pamięć podręczna i kolejka workerów" -#: src/Module/Admin/Site.php:580 +#: src/Module/Admin/Site.php:514 msgid "Discover followers/followings from contacts" msgstr "Odkryj obserwujących/obserwowanych z kontaktów" -#: src/Module/Admin/Site.php:580 +#: src/Module/Admin/Site.php:514 msgid "" "If enabled, contacts are checked for their followers and following contacts." msgstr "Jeśli ta opcja jest włączona, kontakty są sprawdzane pod kątem ich obserwujących i śledzonych kontaktów." -#: src/Module/Admin/Site.php:581 +#: src/Module/Admin/Site.php:515 msgid "None - deactivated" msgstr "Brak - dezaktywowany" -#: src/Module/Admin/Site.php:582 +#: src/Module/Admin/Site.php:516 msgid "" "Local contacts - contacts of our local contacts are discovered for their " "followers/followings." msgstr "Kontakty lokalne - kontakty naszych lokalnych kontaktów są wykrywane dla ich obserwujących/obserwujących." -#: src/Module/Admin/Site.php:583 +#: src/Module/Admin/Site.php:517 msgid "" "Interactors - contacts of our local contacts and contacts who interacted on " "locally visible postings are discovered for their followers/followings." msgstr "Interaktorzy - kontakty naszych lokalnych kontaktów i kontakty, które wchodziły w interakcję z lokalnie widocznymi wpisami, są wykrywane dla ich obserwujących/obserwowanych." -#: src/Module/Admin/Site.php:585 +#: src/Module/Admin/Site.php:519 msgid "Synchronize the contacts with the directory server" msgstr "Synchronizuj kontakty z serwerem katalogowym" -#: src/Module/Admin/Site.php:585 +#: src/Module/Admin/Site.php:519 msgid "" "if enabled, the system will check periodically for new contacts on the " "defined directory server." msgstr "jeśli ta opcja jest włączona, system będzie okresowo sprawdzać nowe kontakty na zdefiniowanym serwerze katalogowym." -#: src/Module/Admin/Site.php:587 +#: src/Module/Admin/Site.php:521 msgid "Days between requery" msgstr "Dni między żądaniem" -#: src/Module/Admin/Site.php:587 +#: src/Module/Admin/Site.php:521 msgid "Number of days after which a server is requeried for his contacts." msgstr "Liczba dni, po upływie których serwer jest żądany dla swoich kontaktów." -#: src/Module/Admin/Site.php:588 +#: src/Module/Admin/Site.php:522 msgid "Discover contacts from other servers" msgstr "Odkryj kontakty z innych serwerów" -#: src/Module/Admin/Site.php:588 +#: src/Module/Admin/Site.php:522 msgid "" "Periodically query other servers for contacts. The system queries Friendica," " Mastodon and Hubzilla servers." msgstr "Okresowo pytaj inne serwery o kontakty. System wysyła zapytania do serwerów Friendica, Mastodon i Hubzilla." -#: src/Module/Admin/Site.php:589 +#: src/Module/Admin/Site.php:523 msgid "Search the local directory" msgstr "Wyszukaj w lokalnym katalogu" -#: src/Module/Admin/Site.php:589 +#: src/Module/Admin/Site.php:523 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 "Wyszukaj lokalny katalog zamiast katalogu globalnego. Podczas wyszukiwania lokalnie każde wyszukiwanie zostanie wykonane w katalogu globalnym w tle. Poprawia to wyniki wyszukiwania, gdy wyszukiwanie jest powtarzane." -#: src/Module/Admin/Site.php:591 +#: src/Module/Admin/Site.php:525 msgid "Publish server information" msgstr "Publikuj informacje o serwerze" -#: src/Module/Admin/Site.php:591 +#: src/Module/Admin/Site.php:525 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 " @@ -5751,50 +5838,50 @@ msgid "" " href=\"http://the-federation.info/\">the-federation.info for details." msgstr "Jeśli ta opcja jest włączona, ogólne dane dotyczące serwera i użytkowania zostaną opublikowane. Dane zawierają nazwę i wersję serwera, liczbę użytkowników z profilami publicznymi, liczbę postów i aktywowane protokoły i złącza. Szczegółowe informacje można znaleźć na the-federation.info." -#: src/Module/Admin/Site.php:593 +#: src/Module/Admin/Site.php:527 msgid "Check upstream version" msgstr "Sprawdź wersję powyżej" -#: src/Module/Admin/Site.php:593 +#: src/Module/Admin/Site.php:527 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 "Umożliwia sprawdzenie nowych wersji Friendica na github. Jeśli pojawi się nowa wersja, zostaniesz o tym poinformowany w panelu administracyjnym." -#: src/Module/Admin/Site.php:594 +#: src/Module/Admin/Site.php:528 msgid "Suppress Tags" msgstr "Pomiń znaczniki" -#: src/Module/Admin/Site.php:594 +#: src/Module/Admin/Site.php:528 msgid "Suppress showing a list of hashtags at the end of the posting." msgstr "Pomiń wyświetlenie listy hashtagów na końcu wpisu." -#: src/Module/Admin/Site.php:595 +#: src/Module/Admin/Site.php:529 msgid "Clean database" msgstr "Wyczyść bazę danych" -#: src/Module/Admin/Site.php:595 +#: src/Module/Admin/Site.php:529 msgid "" "Remove old remote items, orphaned database records and old content from some" " other helper tables." msgstr "Usuń stare zdalne pozycje, osierocone rekordy bazy danych i starą zawartość z innych tabel pomocników." -#: src/Module/Admin/Site.php:596 +#: src/Module/Admin/Site.php:530 msgid "Lifespan of remote items" msgstr "Żywotność odległych przedmiotów" -#: src/Module/Admin/Site.php:596 +#: src/Module/Admin/Site.php:530 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 "Po włączeniu czyszczenia bazy danych określa dni, po których zdalne elementy zostaną usunięte. Własne przedmioty oraz oznaczone lub wypełnione pozycje są zawsze przechowywane. 0 wyłącza to zachowanie." -#: src/Module/Admin/Site.php:597 +#: src/Module/Admin/Site.php:531 msgid "Lifespan of unclaimed items" msgstr "Żywotność nieodebranych przedmiotów" -#: src/Module/Admin/Site.php:597 +#: src/Module/Admin/Site.php:531 msgid "" "When the database cleanup is enabled, this defines the days after which " "unclaimed remote items (mostly content from the relay) will be deleted. " @@ -5802,144 +5889,134 @@ msgid "" "items if set to 0." msgstr "Po włączeniu czyszczenia bazy danych określa się dni, po których usunięte zostaną nieodebrane zdalne elementy (głównie zawartość z przekaźnika). Wartość domyślna to 90 dni. Wartość domyślna dla ogólnej długości życia zdalnych pozycji, jeśli jest ustawiona na 0." -#: src/Module/Admin/Site.php:598 +#: src/Module/Admin/Site.php:532 msgid "Lifespan of raw conversation data" msgstr "Trwałość nieprzetworzonych danych konwersacji" -#: src/Module/Admin/Site.php:598 +#: src/Module/Admin/Site.php:532 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 "Dane konwersacji są używane do ActivityPub i OStatus, a także do celów debugowania. Powinno być bezpieczne usunięcie go po 14 dniach, domyślnie jest to 90 dni." -#: src/Module/Admin/Site.php:599 +#: src/Module/Admin/Site.php:533 msgid "Maximum numbers of comments per post" msgstr "Maksymalna liczba komentarzy na wpis" -#: src/Module/Admin/Site.php:599 +#: src/Module/Admin/Site.php:533 msgid "How much comments should be shown for each post? Default value is 100." msgstr "Ile komentarzy powinno być wyświetlanych dla każdego wpisu? Domyślna wartość to 100." -#: src/Module/Admin/Site.php:600 +#: src/Module/Admin/Site.php:534 msgid "Maximum numbers of comments per post on the display page" msgstr "Maksymalna liczba komentarzy na wpis na wyświetlanej stronie" -#: src/Module/Admin/Site.php:600 +#: src/Module/Admin/Site.php:534 msgid "" "How many comments should be shown on the single view for each post? Default " "value is 1000." msgstr "Ile komentarzy powinno być wyświetlanych w pojedynczym widoku dla każdego wpisu? Wartość domyślna to 1000." -#: src/Module/Admin/Site.php:601 +#: src/Module/Admin/Site.php:535 msgid "Temp path" msgstr "Ścieżka do temp" -#: src/Module/Admin/Site.php:601 +#: src/Module/Admin/Site.php:535 msgid "" "If you have a restricted system where the webserver can't access the system " "temp path, enter another path here." msgstr "Jeśli masz zastrzeżony system, w którym serwer internetowy nie może uzyskać dostępu do ścieżki temp systemu, wprowadź tutaj inną ścieżkę." -#: src/Module/Admin/Site.php:602 +#: src/Module/Admin/Site.php:536 msgid "Only search in tags" msgstr "Szukaj tylko w znacznikach" -#: src/Module/Admin/Site.php:602 +#: src/Module/Admin/Site.php:536 msgid "On large systems the text search can slow down the system extremely." msgstr "W dużych systemach wyszukiwanie tekstu może wyjątkowo spowolnić system." -#: src/Module/Admin/Site.php:604 -msgid "New base url" -msgstr "Nowy bazowy adres url" - -#: src/Module/Admin/Site.php:604 -msgid "" -"Change base url for this server. Sends relocate message to all Friendica and" -" Diaspora* contacts of all users." -msgstr "Zmień bazowy adres URL dla tego serwera. Wysyła wiadomość o przeniesieniu do wszystkich kontaktów Friendica i Diaspora* wszystkich użytkowników." - -#: src/Module/Admin/Site.php:606 +#: src/Module/Admin/Site.php:538 msgid "Maximum number of parallel workers" msgstr "Maksymalna liczba równoległych workerów" -#: src/Module/Admin/Site.php:606 +#: src/Module/Admin/Site.php:538 #, php-format msgid "" "On shared hosters set this to %d. On larger systems, values of %d are great." " Default value is %d." msgstr "Na udostępnionych usługach hostingowych ustaw tę opcję %d. W większych systemach wartości %dsą świetne . Wartość domyślna to %d." -#: src/Module/Admin/Site.php:607 +#: src/Module/Admin/Site.php:539 msgid "Enable fastlane" msgstr "Włącz Fastlane" -#: src/Module/Admin/Site.php:607 +#: src/Module/Admin/Site.php:539 msgid "" "When enabed, the fastlane mechanism starts an additional worker if processes" " with higher priority are blocked by processes of lower priority." msgstr "Po włączeniu, system Fastlane uruchamia dodatkowego workera, jeśli procesy o wyższym priorytecie są blokowane przez procesy o niższym priorytecie." -#: src/Module/Admin/Site.php:609 +#: src/Module/Admin/Site.php:541 msgid "Direct relay transfer" msgstr "Bezpośredni transfer przekaźników" -#: src/Module/Admin/Site.php:609 +#: src/Module/Admin/Site.php:541 msgid "" "Enables the direct transfer to other servers without using the relay servers" msgstr "Umożliwia bezpośredni transfer do innych serwerów bez korzystania z serwerów przekazujących" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 msgid "Relay scope" msgstr "Zakres przekaźnika" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 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 "Mogą to być „wszystkie” lub „znaczniki”. „Wszystkie” oznacza, że ​​każdy publiczny wpis powinien zostać odebrany. „Znaczniki” oznaczają, że powinny być odbierane tylko wpisy z wybranymi znacznikami." -#: src/Module/Admin/Site.php:610 src/Module/Contact/Profile.php:273 -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Admin/Site.php:542 src/Module/Contact/Profile.php:273 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Disabled" msgstr "Wyłączony" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 msgid "all" msgstr "wszystko" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 msgid "tags" msgstr "znaczniki" -#: src/Module/Admin/Site.php:611 +#: src/Module/Admin/Site.php:543 msgid "Server tags" msgstr "Znaczniki serwera" -#: src/Module/Admin/Site.php:611 +#: src/Module/Admin/Site.php:543 msgid "Comma separated list of tags for the \"tags\" subscription." msgstr "Rozdzielana przecinkami lista tagów dla subskrypcji „tagi”." -#: src/Module/Admin/Site.php:612 +#: src/Module/Admin/Site.php:544 msgid "Deny Server tags" msgstr "Odrzuć znaczniki serwera" -#: src/Module/Admin/Site.php:612 +#: src/Module/Admin/Site.php:544 msgid "Comma separated list of tags that are rejected." msgstr "Lista oddzielonych przecinkami znaczników, które zostały odrzucone." -#: src/Module/Admin/Site.php:613 +#: src/Module/Admin/Site.php:545 msgid "Allow user tags" msgstr "Pozwól na znaczniki użytkowników" -#: src/Module/Admin/Site.php:613 +#: src/Module/Admin/Site.php:545 msgid "" "If enabled, the tags from the saved searches will used for the \"tags\" " "subscription in addition to the \"relay_server_tags\"." msgstr "Jeśli ta opcja jest włączona, tagi z zapisanych wyszukiwań będą używane jako subskrypcja „tagów” jako uzupełnienie do \"relay_server_tags\"." -#: src/Module/Admin/Site.php:616 +#: src/Module/Admin/Site.php:548 msgid "Start Relocation" msgstr "Rozpocznij przenoszenie" @@ -5965,7 +6042,7 @@ msgstr "Bieżące zaplecze pamięci przechowywania" msgid "Storage Configuration" msgstr "Konfiguracja przechowywania" -#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:91 +#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:94 msgid "Storage" msgstr "Przechowywanie" @@ -6182,7 +6259,7 @@ msgid "Screenshot" msgstr "Zrzut ekranu" #: src/Module/Admin/Themes/Details.php:91 -#: src/Module/Admin/Themes/Index.php:112 src/Module/BaseAdmin.php:94 +#: src/Module/Admin/Themes/Index.php:112 src/Module/BaseAdmin.php:97 msgid "Themes" msgstr "Wygląd" @@ -6392,7 +6469,7 @@ msgid "Permanent deletion" msgstr "Trwałe usunięcie" #: src/Module/Admin/Users/Index.php:150 src/Module/Admin/Users/Index.php:160 -#: src/Module/BaseAdmin.php:92 +#: src/Module/BaseAdmin.php:95 msgid "Users" msgstr "Użytkownicy" @@ -6498,93 +6575,93 @@ msgstr "Brak zainstalowanych aplikacji." msgid "Applications" msgstr "Aplikacje" -#: src/Module/Attach.php:49 src/Module/Attach.php:61 +#: src/Module/Attach.php:50 src/Module/Attach.php:62 msgid "Item was not found." msgstr "Element nie znaleziony." -#: src/Module/BaseAdmin.php:54 src/Module/BaseAdmin.php:58 +#: src/Module/BaseAdmin.php:57 src/Module/BaseAdmin.php:61 msgid "Please login to continue." msgstr "Zaloguj się aby kontynuować." -#: src/Module/BaseAdmin.php:63 +#: src/Module/BaseAdmin.php:66 msgid "You don't have access to administration pages." msgstr "Nie masz dostępu do stron administracyjnych." -#: src/Module/BaseAdmin.php:67 +#: src/Module/BaseAdmin.php:70 msgid "" "Submanaged account can't access the administration pages. Please log back in" " as the main account." msgstr "Konto zarządzane podrzędnie nie ma dostępu do stron administracyjnych. Zaloguj się ponownie poprzez konto główne." -#: src/Module/BaseAdmin.php:86 +#: src/Module/BaseAdmin.php:89 msgid "Overview" msgstr "Przegląd" -#: src/Module/BaseAdmin.php:89 +#: src/Module/BaseAdmin.php:92 msgid "Configuration" msgstr "Konfiguracja" -#: src/Module/BaseAdmin.php:95 src/Module/BaseSettings.php:63 +#: src/Module/BaseAdmin.php:98 src/Module/BaseSettings.php:63 msgid "Additional features" msgstr "Dodatkowe funkcje" -#: src/Module/BaseAdmin.php:98 +#: src/Module/BaseAdmin.php:101 msgid "Database" msgstr "Baza danych" -#: src/Module/BaseAdmin.php:99 +#: src/Module/BaseAdmin.php:102 msgid "DB updates" msgstr "Aktualizacje bazy danych" -#: src/Module/BaseAdmin.php:100 +#: src/Module/BaseAdmin.php:103 msgid "Inspect Deferred Workers" msgstr "Sprawdź odroczonych workerów" -#: src/Module/BaseAdmin.php:101 +#: src/Module/BaseAdmin.php:104 msgid "Inspect worker Queue" msgstr "Sprawdź kolejkę workerów" -#: src/Module/BaseAdmin.php:103 +#: src/Module/BaseAdmin.php:106 msgid "Tools" msgstr "Narzędzia" -#: src/Module/BaseAdmin.php:104 +#: src/Module/BaseAdmin.php:107 msgid "Contact Blocklist" msgstr "Lista zablokowanych kontaktów" -#: src/Module/BaseAdmin.php:105 +#: src/Module/BaseAdmin.php:108 msgid "Server Blocklist" msgstr "Lista zablokowanych serwerów" -#: src/Module/BaseAdmin.php:112 +#: src/Module/BaseAdmin.php:115 msgid "Diagnostics" msgstr "Diagnostyka" -#: src/Module/BaseAdmin.php:113 +#: src/Module/BaseAdmin.php:116 msgid "PHP Info" msgstr "Informacje o PHP" -#: src/Module/BaseAdmin.php:114 +#: src/Module/BaseAdmin.php:117 msgid "probe address" msgstr "adres probe" -#: src/Module/BaseAdmin.php:115 +#: src/Module/BaseAdmin.php:118 msgid "check webfinger" msgstr "sprawdź webfinger" -#: src/Module/BaseAdmin.php:117 +#: src/Module/BaseAdmin.php:120 msgid "Babel" msgstr "Babel" -#: src/Module/BaseAdmin.php:118 src/Module/Debug/ActivityPubConversion.php:142 +#: src/Module/BaseAdmin.php:121 src/Module/Debug/ActivityPubConversion.php:142 msgid "ActivityPub Conversion" msgstr "Konwersja ActivityPub" -#: src/Module/BaseAdmin.php:127 +#: src/Module/BaseAdmin.php:130 msgid "Addon Features" msgstr "Funkcje dodatkowe" -#: src/Module/BaseAdmin.php:128 +#: src/Module/BaseAdmin.php:131 msgid "User registrations waiting for confirmation" msgstr "Rejestracje użytkowników czekające na potwierdzenie" @@ -6651,8 +6728,8 @@ msgstr "Przeszukiwanie forum - %s" msgid "Account" msgstr "Konto" -#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:95 -#: src/Module/Settings/TwoFactor/Index.php:110 +#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:96 +#: src/Module/Settings/TwoFactor/Index.php:113 msgid "Two-factor authentication" msgstr "Uwierzytelnianie dwuskładnikowe" @@ -6668,7 +6745,7 @@ msgstr "Zarządzanie kontami" msgid "Connected apps" msgstr "Powiązane aplikacje" -#: src/Module/BaseSettings.php:106 src/Module/Settings/UserExport.php:75 +#: src/Module/BaseSettings.php:106 src/Module/Settings/UserExport.php:76 msgid "Export personal data" msgstr "Eksportuj dane osobiste" @@ -6706,7 +6783,7 @@ msgid "Only show blocked contacts" msgstr "Pokaż tylko zablokowane kontakty" #: src/Module/Contact.php:330 src/Module/Contact.php:377 -#: src/Object/Post.php:329 +#: src/Object/Post.php:339 msgid "Ignored" msgstr "Ignorowane" @@ -6738,7 +6815,7 @@ msgstr "Uporządkuj swoje grupy kontaktów" msgid "Search your contacts" msgstr "Wyszukaj w kontaktach" -#: src/Module/Contact.php:390 src/Module/Search/Index.php:192 +#: src/Module/Contact.php:390 src/Module/Search/Index.php:207 #, php-format msgid "Results for: %s" msgstr "Wyniki dla: %s" @@ -7113,7 +7190,7 @@ msgid "" msgstr "Rozdzielana przecinkami lista słów kluczowych, które nie powinny zostać przekonwertowane na hashtagi, gdy wybrana jest opcja 'Pobierz informacje i słowa kluczowe'" #: src/Module/Contact/Profile.php:378 -#: src/Module/Settings/TwoFactor/Index.php:132 +#: src/Module/Settings/TwoFactor/Index.php:135 msgid "Actions" msgstr "Akcja" @@ -7172,6 +7249,7 @@ msgstr "Czy na pewno chcesz cofnąć obserwowanie przez ten kontakt? Nie można #: src/Module/Contact/Revoke.php:107 #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:53 src/Module/Register.php:130 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "Yes" msgstr "Tak" @@ -7203,8 +7281,8 @@ msgstr "Zawiera" msgid "Hide" msgstr "Ukryj" -#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:137 -#: src/Module/Search/Index.php:179 +#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:152 +#: src/Module/Search/Index.php:194 msgid "No results." msgstr "Brak wyników." @@ -7264,7 +7342,7 @@ msgstr "Osobiste" msgid "Posts that mention or involve you" msgstr "Wpisy, które wspominają lub angażują Ciebie" -#: src/Module/Conversation/Network.php:287 src/Object/Post.php:341 +#: src/Module/Conversation/Network.php:287 src/Object/Post.php:351 msgid "Starred" msgstr "Ulubione" @@ -8087,6 +8165,7 @@ msgstr "Twierdzi, że go/ją znasz: " #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:54 src/Module/Register.php:131 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "No" msgstr "Nie" @@ -8150,11 +8229,11 @@ msgstr "Powiadomienia domowe" msgid "Show unread" msgstr "Pokaż nieprzeczytane" -#: src/Module/Notifications/Ping.php:218 +#: src/Module/Notifications/Ping.php:221 msgid "{0} requested registration" msgstr "{0} wymagana rejestracja" -#: src/Module/Notifications/Ping.php:229 +#: src/Module/Notifications/Ping.php:232 #, php-format msgid "{0} and %d others requested registration" msgstr "{0} i %d innych poprosili o rejestrację" @@ -8188,24 +8267,24 @@ msgstr "Skopiuj następujący kod uwierzytelniający do swojej aplikacji i zamkn msgid "Unsupported or missing grant type" msgstr "Nieobsługiwany lub brakujący typ dotacji" -#: src/Module/PermissionTooltip.php:48 +#: src/Module/PermissionTooltip.php:49 #, php-format msgid "Wrong type \"%s\", expected one of: %s" msgstr "Nieprawidłowy typ „%s”, oczekiwano jednego z:%s" -#: src/Module/PermissionTooltip.php:65 +#: src/Module/PermissionTooltip.php:66 msgid "Model not found" msgstr "Nie znaleziono modelu" -#: src/Module/PermissionTooltip.php:88 +#: src/Module/PermissionTooltip.php:89 msgid "Unlisted" msgstr "Niekatalogowany" -#: src/Module/PermissionTooltip.php:106 +#: src/Module/PermissionTooltip.php:107 msgid "Remote privacy information not available." msgstr "Nie są dostępne zdalne informacje o prywatności." -#: src/Module/PermissionTooltip.php:115 +#: src/Module/PermissionTooltip.php:116 msgid "Visible to:" msgstr "Widoczne dla:" @@ -8239,21 +8318,21 @@ msgstr "DW: %s
" msgid "BCC: %s
" msgstr "UDW: %s
" -#: src/Module/Photo.php:127 +#: src/Module/Photo.php:128 msgid "The Photo is not available." msgstr "Zdjęcie jest niedostępne." -#: src/Module/Photo.php:140 +#: src/Module/Photo.php:141 #, php-format msgid "The Photo with id %s is not available." msgstr "Zdjęcie z identyfikatorem %s nie jest dostępne." -#: src/Module/Photo.php:173 +#: src/Module/Photo.php:174 #, php-format msgid "Invalid external resource with url %s." msgstr "Nieprawidłowy zasób zewnętrzny z adresem URL %s." -#: src/Module/Photo.php:175 +#: src/Module/Photo.php:176 #, php-format msgid "Invalid photo with id %s." msgstr "Nieprawidłowe zdjęcie z identyfikatorem %s." @@ -8273,7 +8352,7 @@ msgid "" "class=\"btn btn-sm pull-right\">Cancel" msgstr "Obecnie przeglądasz swój profil jako %s Anuluj" -#: src/Module/Profile/Profile.php:144 src/Module/Settings/Account.php:548 +#: src/Module/Profile/Profile.php:144 src/Module/Settings/Account.php:575 msgid "Full Name:" msgstr "Imię i nazwisko:" @@ -8322,19 +8401,19 @@ msgstr "Zobacz jako" #: src/Module/Profile/Profile.php:326 src/Module/Profile/Profile.php:329 #: src/Module/Profile/Status.php:66 src/Module/Profile/Status.php:69 -#: src/Protocol/Feed.php:1017 src/Protocol/OStatus.php:1245 +#: src/Protocol/Feed.php:1018 src/Protocol/OStatus.php:1276 #, php-format msgid "%s's timeline" msgstr "oś czasu %s" #: src/Module/Profile/Profile.php:327 src/Module/Profile/Status.php:67 -#: src/Protocol/Feed.php:1021 src/Protocol/OStatus.php:1249 +#: src/Protocol/Feed.php:1022 src/Protocol/OStatus.php:1281 #, php-format msgid "%s's posts" msgstr "wpisy %s" #: src/Module/Profile/Profile.php:328 src/Module/Profile/Status.php:68 -#: src/Protocol/Feed.php:1024 src/Protocol/OStatus.php:1252 +#: src/Protocol/Feed.php:1025 src/Protocol/OStatus.php:1285 #, php-format msgid "%s's comments" msgstr "komentarze %s" @@ -8405,7 +8484,7 @@ msgstr "Twój adres e-mail: (Informacje początkowe zostaną wysłane tam, więc msgid "Please repeat your e-mail address:" msgstr "Powtórz swój adres e-mail:" -#: src/Module/Register.php:162 src/Module/Settings/Account.php:539 +#: src/Module/Register.php:162 src/Module/Settings/Account.php:566 msgid "New Password:" msgstr "Nowe hasło:" @@ -8413,7 +8492,7 @@ msgstr "Nowe hasło:" msgid "Leave empty for an auto generated password." msgstr "Pozostaw puste dla wygenerowanego automatycznie hasła." -#: src/Module/Register.php:163 src/Module/Settings/Account.php:540 +#: src/Module/Register.php:163 src/Module/Settings/Account.php:567 msgid "Confirm:" msgstr "Potwierdź:" @@ -8534,15 +8613,15 @@ msgstr "Jeśli nie jesteś jeszcze członkiem darmowej sieci społecznościowej, msgid "Your Webfinger address or profile URL:" msgstr "Twój adres lub adres URL profilu Webfinger:" -#: src/Module/Search/Index.php:54 +#: src/Module/Search/Index.php:69 msgid "Only logged in users are permitted to perform a search." msgstr "Tylko zalogowani użytkownicy mogą wyszukiwać." -#: src/Module/Search/Index.php:74 +#: src/Module/Search/Index.php:89 msgid "Only one search per minute is permitted for not logged in users." msgstr "Dla niezalogowanych użytkowników dozwolone jest tylko jedno wyszukiwanie na minutę." -#: src/Module/Search/Index.php:190 +#: src/Module/Search/Index.php:205 #, php-format msgid "Items tagged with: %s" msgstr "Elementy oznaczone znacznikiem: %s" @@ -8605,7 +8684,11 @@ msgstr "Polityka Prywatności Witryny" msgid "privacy policy" msgstr "polityka prywatności" -#: src/Module/Security/Logout.php:87 +#: src/Module/Security/Logout.php:83 +#: 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 "Wylogowano." @@ -8631,7 +8714,7 @@ msgid "Remaining recovery codes: %d" msgstr "Pozostałe kody odzyskiwania: %d" #: src/Module/Security/TwoFactor/Recovery.php:77 -#: src/Module/Security/TwoFactor/Verify.php:76 +#: src/Module/Security/TwoFactor/Verify.php:77 #: src/Module/Settings/TwoFactor/Verify.php:94 msgid "Invalid code, please retry." msgstr "Nieprawidłowy kod, spróbuj ponownie." @@ -8647,7 +8730,6 @@ msgid "" msgstr "

Możesz wprowadzić jeden ze swoich jednorazowych kodów odzyskiwania w przypadku utraty dostępu do urządzenia mobilnego.

" #: src/Module/Security/TwoFactor/Recovery.php:98 -#: src/Module/Security/TwoFactor/Verify.php:99 #, php-format msgid "Don’t have your phone? Enter a two-factor recovery code" msgstr "Nie masz telefonu? Wprowadzić dwuetapowy kod przywracania " @@ -8660,146 +8742,193 @@ msgstr "Wprowadź kod odzyskiwania" msgid "Submit recovery code and complete login" msgstr "Prześlij kod odzyskiwania i pełne logowanie" -#: src/Module/Security/TwoFactor/Verify.php:96 +#: src/Module/Security/TwoFactor/Signout.php:122 +msgid "Sign out of this browser?" +msgstr "Wylogować z tej przeglądarki?" + +#: 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 "

Jeśli ufasz tej przeglądarce, przy następnym logowaniu nie zostaniesz poproszony o podanie kodu weryfikacyjnego.

" + +#: src/Module/Security/TwoFactor/Signout.php:124 +msgid "Sign out" +msgstr "Wyloguj" + +#: src/Module/Security/TwoFactor/Signout.php:126 +msgid "Trust and sign out" +msgstr "Zaufaj i wyloguj" + +#: src/Module/Security/TwoFactor/Trust.php:89 +msgid "Couldn't save browser to Cookie." +msgstr "Nie można zapisać informacji o przeglądarce do ciasteczek." + +#: src/Module/Security/TwoFactor/Trust.php:119 +msgid "Trust this browser?" +msgstr "Ufać tej przeglądarce?" + +#: src/Module/Security/TwoFactor/Trust.php:120 +msgid "" +"

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

" +msgstr "

Jeśli zdecydujesz się zaufać tej przeglądarce, przy następnym logowaniu nie zostaniesz poproszony o podanie kodu weryfikacyjnego.

" + +#: src/Module/Security/TwoFactor/Trust.php:121 +msgid "Not now" +msgstr "Nie teraz" + +#: src/Module/Security/TwoFactor/Trust.php:122 +msgid "Don't trust" +msgstr "Nie ufaj" + +#: src/Module/Security/TwoFactor/Trust.php:123 +msgid "Trust" +msgstr "Truj" + +#: 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 "

Otwórz aplikację uwierzytelniania dwuskładnikowego na swoim urządzeniu, aby uzyskać kod uwierzytelniający i zweryfikować swoją tożsamość.

" #: 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 "Jeśli nie masz dostępu do swojego kodu uwierzytelniającego, możesz użyć dwuskładnikowego kodu odzyskiwania." + +#: src/Module/Security/TwoFactor/Verify.php:101 #: src/Module/Settings/TwoFactor/Verify.php:154 msgid "Please enter a code from your authentication app" msgstr "Wprowadź kod z aplikacji uwierzytelniającej" -#: src/Module/Security/TwoFactor/Verify.php:101 -msgid "This is my two-factor authenticator app device" -msgstr "To jest moje urządzenie z dwuskładnikową aplikacją uwierzytelniającą" - #: src/Module/Security/TwoFactor/Verify.php:102 msgid "Verify code and complete login" msgstr "Zweryfikuj kod i zakończ logowanie" -#: src/Module/Settings/Account.php:65 +#: src/Module/Settings/Account.php:66 msgid "Passwords do not match." msgstr "Hasła nie pasują do siebie." -#: src/Module/Settings/Account.php:79 +#: src/Module/Settings/Account.php:80 msgid "Password unchanged." msgstr "Hasło niezmienione." -#: src/Module/Settings/Account.php:94 +#: src/Module/Settings/Account.php:95 msgid "Please use a shorter name." msgstr "Użyj krótszej nazwy." -#: src/Module/Settings/Account.php:97 +#: src/Module/Settings/Account.php:98 msgid "Name too short." msgstr "Nazwa jest za krótka. " -#: src/Module/Settings/Account.php:106 +#: src/Module/Settings/Account.php:107 msgid "Wrong Password." msgstr "Nieprawidłowe hasło." -#: src/Module/Settings/Account.php:111 +#: src/Module/Settings/Account.php:112 msgid "Invalid email." msgstr "Niepoprawny e-mail." -#: src/Module/Settings/Account.php:117 +#: src/Module/Settings/Account.php:118 msgid "Cannot change to that email." msgstr "Nie można zmienić tego e-maila." -#: src/Module/Settings/Account.php:147 src/Module/Settings/Account.php:199 -#: src/Module/Settings/Account.php:219 src/Module/Settings/Account.php:279 -#: src/Module/Settings/Account.php:328 +#: src/Module/Settings/Account.php:148 src/Module/Settings/Account.php:200 +#: src/Module/Settings/Account.php:220 src/Module/Settings/Account.php:304 +#: src/Module/Settings/Account.php:353 msgid "Settings were not updated." msgstr "Ustawienia nie zostały zaktualizowane." -#: src/Module/Settings/Account.php:340 +#: src/Module/Settings/Account.php:365 msgid "Contact CSV file upload error" msgstr "Kontakt z plikiem CSV błąd przekazywania plików" -#: src/Module/Settings/Account.php:359 +#: src/Module/Settings/Account.php:384 msgid "Importing Contacts done" msgstr "Importowanie kontaktów zakończone" -#: src/Module/Settings/Account.php:372 +#: src/Module/Settings/Account.php:397 msgid "Relocate message has been send to your contacts" msgstr "Przeniesienie wiadomości zostało wysłane do Twoich kontaktów" -#: src/Module/Settings/Account.php:389 +#: src/Module/Settings/Account.php:414 msgid "Unable to find your profile. Please contact your admin." msgstr "Nie można znaleźć Twojego profilu. Skontaktuj się z administratorem." -#: src/Module/Settings/Account.php:431 +#: src/Module/Settings/Account.php:456 msgid "Personal Page Subtypes" msgstr "Podtypy osobistych stron" -#: src/Module/Settings/Account.php:432 +#: src/Module/Settings/Account.php:457 msgid "Community Forum Subtypes" msgstr "Podtypy społeczności forum" -#: src/Module/Settings/Account.php:442 +#: src/Module/Settings/Account.php:467 msgid "Account for a personal profile." msgstr "Konto dla profilu osobistego." -#: src/Module/Settings/Account.php:449 +#: src/Module/Settings/Account.php:474 msgid "" "Account for an organisation that automatically approves contact requests as " "\"Followers\"." msgstr "Konto dla organizacji, która automatycznie zatwierdza prośby o kontakt jako \"Obserwatorzy\"." -#: src/Module/Settings/Account.php:456 +#: src/Module/Settings/Account.php:481 msgid "" "Account for a news reflector that automatically approves contact requests as" " \"Followers\"." msgstr "Konto dla reflektora wiadomości, który automatycznie zatwierdza prośby o kontakt jako \"Obserwatorzy\"." -#: src/Module/Settings/Account.php:463 +#: src/Module/Settings/Account.php:488 msgid "Account for community discussions." msgstr "Konto do dyskusji w społeczności." -#: src/Module/Settings/Account.php:470 +#: src/Module/Settings/Account.php:495 msgid "" "Account for a regular personal profile that requires manual approval of " "\"Friends\" and \"Followers\"." msgstr "Konto dla zwykłego profilu osobistego, który wymaga ręcznej zgody \"Przyjaciół\" i \"Obserwatorów\"." -#: src/Module/Settings/Account.php:477 +#: src/Module/Settings/Account.php:502 msgid "" "Account for a public profile that automatically approves contact requests as" " \"Followers\"." msgstr "Konto dla profilu publicznego, który automatycznie zatwierdza prośby o kontakt jako \"Obserwatorzy\"." -#: src/Module/Settings/Account.php:484 +#: src/Module/Settings/Account.php:509 msgid "Automatically approves all contact requests." msgstr "Automatycznie zatwierdza wszystkie prośby o kontakt." -#: src/Module/Settings/Account.php:491 +#: src/Module/Settings/Account.php:516 msgid "" "Account for a popular profile that automatically approves contact requests " "as \"Friends\"." msgstr "Konto popularnego profilu, które automatycznie zatwierdza prośby o kontakt jako \"Przyjaciele\"." -#: src/Module/Settings/Account.php:496 +#: src/Module/Settings/Account.php:521 msgid "Private Forum [Experimental]" msgstr "Prywatne Forum [Eksperymentalne]" -#: src/Module/Settings/Account.php:498 +#: src/Module/Settings/Account.php:523 msgid "Requires manual approval of contact requests." msgstr "Wymaga ręcznego zatwierdzania żądań kontaktów." -#: src/Module/Settings/Account.php:507 +#: src/Module/Settings/Account.php:532 msgid "OpenID:" msgstr "OpenID:" -#: src/Module/Settings/Account.php:507 +#: src/Module/Settings/Account.php:532 msgid "(Optional) Allow this OpenID to login to this account." msgstr "(Opcjonalnie) Pozwól zalogować się na to konto przy pomocy OpenID." -#: src/Module/Settings/Account.php:515 +#: src/Module/Settings/Account.php:540 msgid "Publish your profile in your local site directory?" msgstr "Czy opublikować twój profil w katalogu lokalnej witryny?" -#: src/Module/Settings/Account.php:515 +#: src/Module/Settings/Account.php:540 #, php-format msgid "" "Your profile will be published in this node's local " @@ -8807,103 +8936,103 @@ msgid "" " system settings." msgstr "Twój profil zostanie opublikowany w lokalnym katalogu tego węzła. Dane Twojego profilu mogą być publicznie widoczne w zależności od ustawień systemu." -#: src/Module/Settings/Account.php:521 +#: src/Module/Settings/Account.php:546 #, php-format msgid "" "Your profile will also be published in the global friendica directories " "(e.g. %s)." msgstr "Twój profil zostanie również opublikowany w globalnych katalogach Friendica (np. %s)." -#: src/Module/Settings/Account.php:529 +#: src/Module/Settings/Account.php:556 msgid "Account Settings" msgstr "Ustawienia konta" -#: src/Module/Settings/Account.php:530 +#: src/Module/Settings/Account.php:557 #, php-format msgid "Your Identity Address is '%s' or '%s'." msgstr "Twój adres tożsamości to '%s' lub '%s'." -#: src/Module/Settings/Account.php:538 +#: src/Module/Settings/Account.php:565 msgid "Password Settings" msgstr "Ustawienia hasła" -#: src/Module/Settings/Account.php:539 +#: src/Module/Settings/Account.php:566 msgid "" "Allowed characters are a-z, A-Z, 0-9 and special characters except white " "spaces, accentuated letters and colon (:)." msgstr "Dozwolone znaki to a-z, A-Z, 0-9 i znaki specjalne, z wyjątkiem białych znaków, podkreślonych liter i dwukropka (:)." -#: src/Module/Settings/Account.php:540 +#: src/Module/Settings/Account.php:567 msgid "Leave password fields blank unless changing" msgstr "Pozostaw pole hasła puste, jeżeli nie chcesz go zmienić." -#: src/Module/Settings/Account.php:541 +#: src/Module/Settings/Account.php:568 msgid "Current Password:" msgstr "Aktualne hasło:" -#: src/Module/Settings/Account.php:541 +#: src/Module/Settings/Account.php:568 msgid "Your current password to confirm the changes" msgstr "Wpisz aktualne hasło, aby potwierdzić zmiany" -#: src/Module/Settings/Account.php:542 +#: src/Module/Settings/Account.php:569 msgid "Password:" msgstr "Hasło:" -#: src/Module/Settings/Account.php:542 +#: src/Module/Settings/Account.php:569 msgid "Your current password to confirm the changes of the email address" msgstr "Twoje obecne hasło, aby potwierdzić zmiany adresu e-mail" -#: src/Module/Settings/Account.php:545 +#: src/Module/Settings/Account.php:572 msgid "Delete OpenID URL" msgstr "Usuń adres URL OpenID" -#: src/Module/Settings/Account.php:547 +#: src/Module/Settings/Account.php:574 msgid "Basic Settings" msgstr "Ustawienia podstawowe" -#: src/Module/Settings/Account.php:549 +#: src/Module/Settings/Account.php:576 msgid "Email Address:" msgstr "Adres email:" -#: src/Module/Settings/Account.php:550 +#: src/Module/Settings/Account.php:577 msgid "Your Timezone:" msgstr "Twoja strefa czasowa:" -#: src/Module/Settings/Account.php:551 +#: src/Module/Settings/Account.php:578 msgid "Your Language:" msgstr "Twój język:" -#: src/Module/Settings/Account.php:551 +#: src/Module/Settings/Account.php:578 msgid "" "Set the language we use to show you friendica interface and to send you " "emails" msgstr "Wybierz język, ktory bedzie używany do wyświetlania użytkownika friendica i wysłania Ci e-maili" -#: src/Module/Settings/Account.php:552 +#: src/Module/Settings/Account.php:579 msgid "Default Post Location:" msgstr "Domyślna lokalizacja wpisów:" -#: src/Module/Settings/Account.php:553 +#: src/Module/Settings/Account.php:580 msgid "Use Browser Location:" msgstr "Używaj lokalizacji przeglądarki:" -#: src/Module/Settings/Account.php:555 +#: src/Module/Settings/Account.php:582 msgid "Security and Privacy Settings" msgstr "Ustawienia bezpieczeństwa i prywatności" -#: src/Module/Settings/Account.php:557 +#: src/Module/Settings/Account.php:584 msgid "Maximum Friend Requests/Day:" msgstr "Maksymalna dzienna liczba zaproszeń do grona przyjaciół:" -#: src/Module/Settings/Account.php:557 src/Module/Settings/Account.php:567 +#: src/Module/Settings/Account.php:584 src/Module/Settings/Account.php:594 msgid "(to prevent spam abuse)" msgstr "(aby zapobiec spamowaniu)" -#: src/Module/Settings/Account.php:559 +#: src/Module/Settings/Account.php:586 msgid "Allow your profile to be searchable globally?" msgstr "Czy Twój profil ma być dostępny do wyszukiwania na całym świecie?" -#: src/Module/Settings/Account.php:559 +#: 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 " @@ -8911,43 +9040,43 @@ msgid "" "indexed or not." msgstr "Aktywuj to ustawienie, jeśli chcesz, aby inni mogli Cię łatwo znaleźć i śledzić. Twój profil będzie można przeszukiwać na zdalnych systemach. To ustawienie określa również, czy Friendica poinformuje wyszukiwarki, że Twój profil powinien być indeksowany, czy nie." -#: src/Module/Settings/Account.php:560 +#: src/Module/Settings/Account.php:587 msgid "Hide your contact/friend list from viewers of your profile?" msgstr "Ukryć listę kontaktów/znajomych przed osobami przeglądającymi Twój profil?" -#: src/Module/Settings/Account.php:560 +#: 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 "Lista kontaktów jest wyświetlana na stronie profilu. Aktywuj tę opcję, aby wyłączyć wyświetlanie listy kontaktów." -#: src/Module/Settings/Account.php:561 +#: src/Module/Settings/Account.php:588 msgid "Hide your profile details from anonymous viewers?" msgstr "Ukryć dane Twojego profilu przed anonimowymi widzami?" -#: src/Module/Settings/Account.php:561 +#: src/Module/Settings/Account.php:588 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 "Anonimowi użytkownicy zobaczą tylko Twoje zdjęcie profilowe, swoją wyświetlaną nazwę i pseudonim, którego używasz na stronie profilu. Twoje publiczne posty i odpowiedzi będą nadal dostępne w inny sposób." -#: src/Module/Settings/Account.php:562 +#: src/Module/Settings/Account.php:589 msgid "Make public posts unlisted" msgstr "Ustaw publiczne wpisy jako niepubliczne" -#: src/Module/Settings/Account.php:562 +#: 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 "Twoje publiczne posty nie będą wyświetlane na stronach społeczności ani w wynikach wyszukiwania ani nie będą wysyłane do serwerów przekazywania. Jednak nadal mogą one pojawiać się w publicznych kanałach na serwerach zdalnych." -#: src/Module/Settings/Account.php:563 +#: src/Module/Settings/Account.php:590 msgid "Make all posted pictures accessible" msgstr "Udostępnij wszystkie opublikowane zdjęcia" -#: src/Module/Settings/Account.php:563 +#: 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 " @@ -8955,213 +9084,237 @@ msgid "" "public on your photo albums though." msgstr "Ta opcja powoduje, że każde opublikowane zdjęcie jest dostępne poprzez bezpośredni link. Jest to obejście problemu polegającego na tym, że większość innych sieci nie może obsłużyć uprawnień do zdjęć. Jednak zdjęcia niepubliczne nadal nie będą widoczne publicznie w Twoich albumach." -#: src/Module/Settings/Account.php:564 +#: src/Module/Settings/Account.php:591 msgid "Allow friends to post to your profile page?" msgstr "Zezwalać znajomym na publikowanie postów na stronie Twojego profilu?" -#: src/Module/Settings/Account.php:564 +#: 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 "Twoi znajomi mogą pisać posty na stronie Twojego profilu. Posty zostaną przesłane do Twoich kontaktów." -#: src/Module/Settings/Account.php:565 +#: src/Module/Settings/Account.php:592 msgid "Allow friends to tag your posts?" msgstr "Zezwolić na oznaczanie Twoich postów przez znajomych?" -#: src/Module/Settings/Account.php:565 +#: src/Module/Settings/Account.php:592 msgid "Your contacts can add additional tags to your posts." msgstr "Twoje kontakty mogą dodawać do tagów dodatkowe posty." -#: src/Module/Settings/Account.php:566 +#: src/Module/Settings/Account.php:593 msgid "Permit unknown people to send you private mail?" msgstr "Zezwolić nieznanym osobom na wysyłanie prywatnych wiadomości?" -#: src/Module/Settings/Account.php:566 +#: 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 "Użytkownicy sieci w serwisie Friendica mogą wysyłać prywatne wiadomości, nawet jeśli nie znajdują się one na liście kontaktów." -#: src/Module/Settings/Account.php:567 +#: src/Module/Settings/Account.php:594 msgid "Maximum private messages per day from unknown people:" msgstr "Maksymalna liczba prywatnych wiadomości dziennie od nieznanych osób:" -#: src/Module/Settings/Account.php:569 +#: src/Module/Settings/Account.php:596 msgid "Default Post Permissions" msgstr "Domyślne prawa dostępu wiadomości" -#: src/Module/Settings/Account.php:573 +#: src/Module/Settings/Account.php:600 msgid "Expiration settings" msgstr "Ustawienia ważności" -#: src/Module/Settings/Account.php:574 +#: src/Module/Settings/Account.php:601 msgid "Automatically expire posts after this many days:" msgstr "Posty wygasną automatycznie po następującej liczbie dni:" -#: src/Module/Settings/Account.php:574 +#: src/Module/Settings/Account.php:601 msgid "If empty, posts will not expire. Expired posts will be deleted" msgstr "Pole puste, wiadomość nie wygaśnie. Niezapisane wpisy zostaną usunięte." -#: src/Module/Settings/Account.php:575 +#: src/Module/Settings/Account.php:602 msgid "Expire posts" msgstr "Ważność wpisów" -#: src/Module/Settings/Account.php:575 +#: src/Module/Settings/Account.php:602 msgid "When activated, posts and comments will be expired." msgstr "Po aktywacji posty i komentarze wygasną." -#: src/Module/Settings/Account.php:576 +#: src/Module/Settings/Account.php:603 msgid "Expire personal notes" msgstr "Ważność osobistych notatek" -#: src/Module/Settings/Account.php:576 +#: src/Module/Settings/Account.php:603 msgid "" "When activated, the personal notes on your profile page will be expired." msgstr "Po aktywacji osobiste notatki na stronie profilu wygasną." -#: src/Module/Settings/Account.php:577 +#: src/Module/Settings/Account.php:604 msgid "Expire starred posts" msgstr "Wygasaj wpisy oznaczone gwiazdką" -#: src/Module/Settings/Account.php:577 +#: src/Module/Settings/Account.php:604 msgid "" "Starring posts keeps them from being expired. That behaviour is overwritten " "by this setting." msgstr "Oznaczanie postów gwiazdką powoduje, że wygasają. To zachowanie jest zastępowane przez to ustawienie." -#: src/Module/Settings/Account.php:578 +#: src/Module/Settings/Account.php:605 msgid "Only expire posts by others" msgstr "Wygasają tylko wpisy innych osób" -#: src/Module/Settings/Account.php:578 +#: 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 "Po aktywacji Twoje posty nigdy nie wygasają. Zatem powyższe ustawienia obowiązują tylko dla otrzymanych postów." -#: src/Module/Settings/Account.php:581 +#: src/Module/Settings/Account.php:608 msgid "Notification Settings" msgstr "Ustawienia powiadomień" -#: src/Module/Settings/Account.php:582 +#: src/Module/Settings/Account.php:609 msgid "Send a notification email when:" msgstr "Wysyłaj powiadmonienia na email, kiedy:" -#: src/Module/Settings/Account.php:583 +#: src/Module/Settings/Account.php:610 msgid "You receive an introduction" msgstr "Otrzymałeś zaproszenie" -#: src/Module/Settings/Account.php:584 +#: src/Module/Settings/Account.php:611 msgid "Your introductions are confirmed" msgstr "Twoje zaproszenie jest potwierdzone" -#: src/Module/Settings/Account.php:585 +#: src/Module/Settings/Account.php:612 msgid "Someone writes on your profile wall" msgstr "Ktoś pisze na Twojej tablicy profilu" -#: src/Module/Settings/Account.php:586 +#: src/Module/Settings/Account.php:613 msgid "Someone writes a followup comment" msgstr "Ktoś pisze komentarz nawiązujący." -#: src/Module/Settings/Account.php:587 +#: src/Module/Settings/Account.php:614 msgid "You receive a private message" msgstr "Otrzymałeś prywatną wiadomość" -#: src/Module/Settings/Account.php:588 +#: src/Module/Settings/Account.php:615 msgid "You receive a friend suggestion" msgstr "Otrzymałeś propozycję od znajomych" -#: src/Module/Settings/Account.php:589 +#: src/Module/Settings/Account.php:616 msgid "You are tagged in a post" msgstr "Jesteś oznaczony znacznikiem we wpisie" -#: src/Module/Settings/Account.php:590 +#: src/Module/Settings/Account.php:617 msgid "You are poked/prodded/etc. in a post" msgstr "Jesteś zaczepiony/zaczepiona/itp. w poście" -#: src/Module/Settings/Account.php:592 +#: src/Module/Settings/Account.php:619 msgid "Create a desktop notification when:" msgstr "Utwórz powiadomienia na pulpicie gdy:" -#: src/Module/Settings/Account.php:593 +#: src/Module/Settings/Account.php:620 +msgid "Someone tagged you" +msgstr "Ktoś Cię oznaczył" + +#: src/Module/Settings/Account.php:621 +msgid "Someone directly commented on your post" +msgstr "Ktoś bezpośrednio skomentował Twój wpis" + +#: src/Module/Settings/Account.php:622 msgid "Someone liked your content" msgstr "Ktoś polubił Twoje treści" -#: src/Module/Settings/Account.php:594 +#: src/Module/Settings/Account.php:622 src/Module/Settings/Account.php:623 +msgid "Can only be enabled, when the direct comment notification is enabled." +msgstr "Można włączyć tylko wtedy, gdy włączone jest bezpośrednie powiadomienie o komentarzach." + +#: src/Module/Settings/Account.php:623 msgid "Someone shared your content" msgstr "Ktoś udostępnił Twoje treści" -#: src/Module/Settings/Account.php:596 +#: src/Module/Settings/Account.php:624 +msgid "Someone commented in your thread" +msgstr "Ktoś skomentował w Twoim wątku" + +#: src/Module/Settings/Account.php:625 +msgid "Someone commented in a thread where you commented" +msgstr "Ktoś skomentował w wątku, w którym Ty skomentowałeś" + +#: src/Module/Settings/Account.php:626 +msgid "Someone commented in a thread where you interacted" +msgstr "Ktoś skomentował w wątku, w którym wchodziłeś w interakcję" + +#: src/Module/Settings/Account.php:628 msgid "Activate desktop notifications" msgstr "Aktywuj powiadomienia na pulpicie" -#: src/Module/Settings/Account.php:596 +#: src/Module/Settings/Account.php:628 msgid "Show desktop popup on new notifications" msgstr "Pokazuj wyskakujące okienko gdy otrzymasz powiadomienie" -#: src/Module/Settings/Account.php:600 +#: src/Module/Settings/Account.php:632 msgid "Text-only notification emails" msgstr "E-maile z powiadomieniami tekstowymi" -#: src/Module/Settings/Account.php:602 +#: src/Module/Settings/Account.php:634 msgid "Send text only notification emails, without the html part" msgstr "Wysyłaj tylko e-maile z powiadomieniami tekstowymi, bez części html" -#: src/Module/Settings/Account.php:606 +#: src/Module/Settings/Account.php:638 msgid "Show detailled notifications" msgstr "Pokazuj szczegółowe powiadomienia" -#: src/Module/Settings/Account.php:608 +#: src/Module/Settings/Account.php:640 msgid "" "Per default, notifications are condensed to a single notification per item. " "When enabled every notification is displayed." msgstr "Domyślne powiadomienia są skondensowane z jednym powiadomieniem dla każdego przedmiotu. Po włączeniu wyświetlane jest każde powiadomienie." -#: src/Module/Settings/Account.php:612 +#: src/Module/Settings/Account.php:644 msgid "Show notifications of ignored contacts" msgstr "Pokaż powiadomienia o zignorowanych kontaktach" -#: src/Module/Settings/Account.php:614 +#: src/Module/Settings/Account.php:646 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 "Nie widzisz wpisów od ignorowanych kontaktów. Ale nadal widzisz ich komentarze. To ustawienie określa, czy chcesz nadal otrzymywać regularne powiadomienia, które są powodowane przez ignorowane kontakty, czy nie." -#: src/Module/Settings/Account.php:617 +#: src/Module/Settings/Account.php:649 msgid "Advanced Account/Page Type Settings" msgstr "Zaawansowane ustawienia konta/rodzaju strony" -#: src/Module/Settings/Account.php:618 +#: src/Module/Settings/Account.php:650 msgid "Change the behaviour of this account for special situations" msgstr "Zmień zachowanie tego konta w sytuacjach specjalnych" -#: src/Module/Settings/Account.php:621 +#: src/Module/Settings/Account.php:653 msgid "Import Contacts" msgstr "Import kontaktów" -#: src/Module/Settings/Account.php:622 +#: src/Module/Settings/Account.php:654 msgid "" "Upload a CSV file that contains the handle of your followed accounts in the " "first column you exported from the old account." msgstr "Prześlij plik CSV zawierający obsługę obserwowanych kont w pierwszej kolumnie wyeksportowanej ze starego konta." -#: src/Module/Settings/Account.php:623 +#: src/Module/Settings/Account.php:655 msgid "Upload File" msgstr "Prześlij plik" -#: src/Module/Settings/Account.php:626 +#: src/Module/Settings/Account.php:658 msgid "Relocate" msgstr "Przeniesienie" -#: src/Module/Settings/Account.php:627 +#: src/Module/Settings/Account.php:659 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 "Jeśli ten profil został przeniesiony z innego serwera, a niektóre z Twoich kontaktów nie otrzymają aktualizacji, spróbuj nacisnąć ten przycisk." -#: src/Module/Settings/Account.php:628 +#: src/Module/Settings/Account.php:660 msgid "Resend relocate message to contacts" msgstr "Wyślij ponownie przenieść wiadomości do kontaktów" @@ -9657,99 +9810,95 @@ msgstr "Friendiqa na moim Fairphone 2..." msgid "Generate" msgstr "Utwórz" -#: src/Module/Settings/TwoFactor/Index.php:67 +#: src/Module/Settings/TwoFactor/Index.php:68 msgid "Two-factor authentication successfully disabled." msgstr "Autoryzacja dwuskładnikowa została pomyślnie wyłączona." -#: src/Module/Settings/TwoFactor/Index.php:93 -msgid "Wrong Password" -msgstr "Złe hasło" - -#: src/Module/Settings/TwoFactor/Index.php:113 +#: src/Module/Settings/TwoFactor/Index.php:116 msgid "" "

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

" msgstr "

Użyj aplikacji na urządzeniu mobilnym, aby uzyskać dwuskładnikowe kody uwierzytelniające po wyświetleniu monitu o zalogowanie.

" -#: src/Module/Settings/TwoFactor/Index.php:117 +#: src/Module/Settings/TwoFactor/Index.php:120 msgid "Authenticator app" msgstr "Aplikacja Authenticator" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Configured" msgstr "Skonfigurowane" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Not Configured" msgstr "Nie skonfigurowane" -#: src/Module/Settings/TwoFactor/Index.php:119 +#: src/Module/Settings/TwoFactor/Index.php:122 msgid "

You haven't finished configuring your authenticator app.

" msgstr "

Nie zakończyłeś konfigurowania aplikacji uwierzytelniającej.

" -#: src/Module/Settings/TwoFactor/Index.php:120 +#: src/Module/Settings/TwoFactor/Index.php:123 msgid "

Your authenticator app is correctly configured.

" msgstr "

Twoja aplikacja uwierzytelniająca jest poprawnie skonfigurowana.

" -#: src/Module/Settings/TwoFactor/Index.php:122 +#: src/Module/Settings/TwoFactor/Index.php:125 msgid "Recovery codes" msgstr "Kody odzyskiwania" -#: src/Module/Settings/TwoFactor/Index.php:123 +#: src/Module/Settings/TwoFactor/Index.php:126 msgid "Remaining valid codes" msgstr "Pozostałe ważne kody" -#: src/Module/Settings/TwoFactor/Index.php:125 +#: src/Module/Settings/TwoFactor/Index.php:128 msgid "" "

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

" msgstr "

Te jednorazowe kody mogą zastąpić kod aplikacji uwierzytelniającej w przypadku utraty dostępu do niej.

" -#: src/Module/Settings/TwoFactor/Index.php:127 +#: src/Module/Settings/TwoFactor/Index.php:130 msgid "App-specific passwords" msgstr "Hasła specyficzne dla aplikacji" -#: src/Module/Settings/TwoFactor/Index.php:128 +#: src/Module/Settings/TwoFactor/Index.php:131 msgid "Generated app-specific passwords" msgstr "Wygenerowane hasła specyficzne dla aplikacji" -#: src/Module/Settings/TwoFactor/Index.php:130 +#: src/Module/Settings/TwoFactor/Index.php:133 msgid "" "

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

" msgstr "

Losowo generowane hasła umożliwiają uwierzytelnianie w aplikacjach nie obsługujących uwierzytelniania dwuskładnikowego.

" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:136 msgid "Current password:" msgstr "Aktualne hasło:" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:136 msgid "" "You need to provide your current password to change two-factor " "authentication settings." msgstr "Musisz podać swoje aktualne hasło, aby zmienić ustawienia uwierzytelniania dwuskładnikowego." -#: src/Module/Settings/TwoFactor/Index.php:134 +#: src/Module/Settings/TwoFactor/Index.php:137 msgid "Enable two-factor authentication" msgstr "Włącz uwierzytelnianie dwuskładnikowe" -#: src/Module/Settings/TwoFactor/Index.php:135 +#: src/Module/Settings/TwoFactor/Index.php:138 msgid "Disable two-factor authentication" msgstr "Wyłącz uwierzytelnianie dwuskładnikowe" -#: src/Module/Settings/TwoFactor/Index.php:136 +#: src/Module/Settings/TwoFactor/Index.php:139 msgid "Show recovery codes" msgstr "Pokaż kody odzyskiwania" -#: src/Module/Settings/TwoFactor/Index.php:137 +#: src/Module/Settings/TwoFactor/Index.php:140 msgid "Manage app-specific passwords" msgstr "Zarządzaj hasłami specyficznymi dla aplikacji" -#: src/Module/Settings/TwoFactor/Index.php:138 +#: src/Module/Settings/TwoFactor/Index.php:141 msgid "Manage trusted browsers" msgstr "Zarządzaj zaufanymi przeglądarkami" -#: src/Module/Settings/TwoFactor/Index.php:139 +#: src/Module/Settings/TwoFactor/Index.php:142 msgid "Finish app configuration" msgstr "Zakończ konfigurację aplikacji" @@ -9792,34 +9941,38 @@ msgstr "Zaufane przeglądarki zostały pomyślnie usunięte." msgid "Trusted browser successfully removed." msgstr "Zaufana przeglądarka została pomyślnie usunięta." -#: src/Module/Settings/TwoFactor/Trusted.php:133 +#: src/Module/Settings/TwoFactor/Trusted.php:134 msgid "Two-factor Trusted Browsers" msgstr "Zaufane przeglądarki dwuskładnikowe" -#: src/Module/Settings/TwoFactor/Trusted.php:134 +#: src/Module/Settings/TwoFactor/Trusted.php:135 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 "Zaufane przeglądarki to indywidualne przeglądarki, które zostały wybrane, aby pominąć uwierzytelnianie dwuskładnikowe celem uzyskania dostępu do Friendica. Korzystaj z tej funkcji oszczędnie, ponieważ może ona negować korzyści płynące z uwierzytelniania dwuskładnikowego." -#: src/Module/Settings/TwoFactor/Trusted.php:135 +#: src/Module/Settings/TwoFactor/Trusted.php:136 msgid "Device" msgstr "Urządzenie" -#: src/Module/Settings/TwoFactor/Trusted.php:136 +#: src/Module/Settings/TwoFactor/Trusted.php:137 msgid "OS" msgstr "System operacyjny" -#: src/Module/Settings/TwoFactor/Trusted.php:138 +#: src/Module/Settings/TwoFactor/Trusted.php:139 msgid "Trusted" msgstr "Zaufane" -#: src/Module/Settings/TwoFactor/Trusted.php:139 +#: src/Module/Settings/TwoFactor/Trusted.php:140 +msgid "Created At" +msgstr "Utworzono" + +#: src/Module/Settings/TwoFactor/Trusted.php:141 msgid "Last Use" msgstr "Ostatnie użycie" -#: src/Module/Settings/TwoFactor/Trusted.php:141 +#: src/Module/Settings/TwoFactor/Trusted.php:143 msgid "Remove All" msgstr "Usuń wszystkie" @@ -9868,32 +10021,32 @@ msgstr "

Możesz też otworzyć następujący adres URL w urządzeniu mobilnym msgid "Verify code and enable two-factor authentication" msgstr "Sprawdź kod i włącz uwierzytelnianie dwuskładnikowe" -#: src/Module/Settings/UserExport.php:67 +#: src/Module/Settings/UserExport.php:68 msgid "Export account" msgstr "Eksportuj konto" -#: src/Module/Settings/UserExport.php:67 +#: src/Module/Settings/UserExport.php:68 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 "Eksportuj informacje o swoim koncie i kontaktach. Użyj tego do utworzenia kopii zapasowej konta i/lub przeniesienia go na inny serwer." -#: src/Module/Settings/UserExport.php:68 +#: src/Module/Settings/UserExport.php:69 msgid "Export all" msgstr "Eksportuj wszystko" -#: src/Module/Settings/UserExport.php:68 +#: src/Module/Settings/UserExport.php:69 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 "Wyeksportuj informacje o swoim koncie, kontakty i wszystkie swoje elementy jako json. Może to być bardzo duży plik i może zająć dużo czasu. Użyj tego, aby wykonać pełną kopię zapasową swojego konta (zdjęcia nie są eksportowane)." -#: src/Module/Settings/UserExport.php:69 +#: src/Module/Settings/UserExport.php:70 msgid "Export Contacts to CSV" msgstr "Eksportuj kontakty do CSV" -#: src/Module/Settings/UserExport.php:69 +#: src/Module/Settings/UserExport.php:70 msgid "" "Export the list of the accounts you are following as CSV file. Compatible to" " e.g. Mastodon." @@ -10108,10 +10261,14 @@ msgid "" " features and resources." msgstr "Na naszych stronach pomocy można znaleźć szczegółowe informacje na temat innych funkcji programu i zasobów." -#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:135 +#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:134 msgid "{0} wants to follow you" msgstr "{0} chce Cię obserwować" +#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:136 +msgid "{0} has started following you" +msgstr "{0} zaczął Cię obserwować" + #: src/Navigation/Notifications/Factory/FormattedNotify.php:91 #, php-format msgid "%s liked %s's post" @@ -10165,330 +10322,330 @@ msgstr "Prośba o dodanie do przyjaciół/powiązanych" msgid "New Follower" msgstr "Nowy obserwujący" -#: src/Navigation/Notifications/Factory/Notification.php:119 +#: src/Navigation/Notifications/Factory/Notification.php:134 #, php-format msgid "%1$s wants to follow you" msgstr "%1$s chce Cię obserwować" -#: src/Navigation/Notifications/Factory/Notification.php:121 +#: src/Navigation/Notifications/Factory/Notification.php:136 #, php-format msgid "%1$s has started following you" msgstr "%1$s zaczął Cię obserwować" -#: src/Navigation/Notifications/Factory/Notification.php:186 +#: src/Navigation/Notifications/Factory/Notification.php:200 #, php-format msgid "%1$s liked your comment on %2$s" msgstr "%1$s polubił Twój komentarz o %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:189 +#: src/Navigation/Notifications/Factory/Notification.php:203 #, php-format msgid "%1$s liked your post %2$s" msgstr "%1$s polubił Twój wpis %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:196 +#: src/Navigation/Notifications/Factory/Notification.php:210 #, php-format msgid "%1$s disliked your comment on %2$s" msgstr "%1$s nie lubi Twojego komentarza o %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:199 +#: src/Navigation/Notifications/Factory/Notification.php:213 #, php-format msgid "%1$s disliked your post %2$s" msgstr "%1$s nie lubi Twojego wpisu %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:206 +#: src/Navigation/Notifications/Factory/Notification.php:220 #, php-format msgid "%1$s shared your comment %2$s" msgstr "%1$s udostępnił Twój komentarz %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:209 +#: src/Navigation/Notifications/Factory/Notification.php:223 #, php-format msgid "%1$s shared your post %2$s" msgstr "%1$s udostępnił Twój wpis %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:213 -#: src/Navigation/Notifications/Factory/Notification.php:282 +#: src/Navigation/Notifications/Factory/Notification.php:227 +#: src/Navigation/Notifications/Factory/Notification.php:297 #, php-format msgid "%1$s shared the post %2$s from %3$s" msgstr "%1$s udostępnił wpis %2$s z %3$s" -#: src/Navigation/Notifications/Factory/Notification.php:215 -#: src/Navigation/Notifications/Factory/Notification.php:284 +#: src/Navigation/Notifications/Factory/Notification.php:229 +#: src/Navigation/Notifications/Factory/Notification.php:299 #, php-format msgid "%1$s shared a post from %3$s" msgstr "%1$s udostępnił wpis z %3$s" -#: src/Navigation/Notifications/Factory/Notification.php:217 -#: src/Navigation/Notifications/Factory/Notification.php:286 +#: src/Navigation/Notifications/Factory/Notification.php:231 +#: src/Navigation/Notifications/Factory/Notification.php:301 #, php-format msgid "%1$s shared the post %2$s" msgstr "%1$s udostępnił wpis %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:219 -#: src/Navigation/Notifications/Factory/Notification.php:288 +#: src/Navigation/Notifications/Factory/Notification.php:233 +#: src/Navigation/Notifications/Factory/Notification.php:303 #, php-format msgid "%1$s shared a post" msgstr "%1$s udostępnił wpis" -#: src/Navigation/Notifications/Factory/Notification.php:227 +#: src/Navigation/Notifications/Factory/Notification.php:241 #, php-format msgid "%1$s wants to attend your event %2$s" msgstr "%1$s chce uczestniczyć w Twoim wydarzeniu %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:234 +#: src/Navigation/Notifications/Factory/Notification.php:248 #, php-format msgid "%1$s does not want to attend your event %2$s" msgstr "%1$s nie chce uczestniczyć w Twoim wydarzeniu %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:241 +#: src/Navigation/Notifications/Factory/Notification.php:255 #, php-format msgid "%1$s maybe wants to attend your event %2$s" msgstr "%1$s może chcieć wziąć udział w Twoim wydarzeniu %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:248 +#: src/Navigation/Notifications/Factory/Notification.php:262 #, php-format msgid "%1$s tagged you on %2$s" msgstr "%1$s oznaczył Cię na %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:252 +#: src/Navigation/Notifications/Factory/Notification.php:266 #, php-format msgid "%1$s replied to you on %2$s" msgstr "%1$s odpowiedział Ci na %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:256 +#: src/Navigation/Notifications/Factory/Notification.php:270 #, php-format msgid "%1$s commented in your thread %2$s" msgstr "%1$s skomentował w Twoim wątku %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:260 +#: src/Navigation/Notifications/Factory/Notification.php:274 #, php-format msgid "%1$s commented on your comment %2$s" msgstr "%1$s skomentował Twój komentarz %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:266 +#: src/Navigation/Notifications/Factory/Notification.php:281 #, php-format msgid "%1$s commented in their thread %2$s" msgstr "%1$s skomentował w swoim wątku %2$s" -#: src/Navigation/Notifications/Factory/Notification.php:268 +#: src/Navigation/Notifications/Factory/Notification.php:283 #, php-format msgid "%1$s commented in their thread" msgstr "%1$s skomentował w swoim wątku" -#: src/Navigation/Notifications/Factory/Notification.php:270 +#: src/Navigation/Notifications/Factory/Notification.php:285 #, php-format msgid "%1$s commented in the thread %2$s from %3$s" msgstr "%1$s skomentował w wątku %2$s od %3$s" -#: src/Navigation/Notifications/Factory/Notification.php:272 +#: src/Navigation/Notifications/Factory/Notification.php:287 #, php-format msgid "%1$s commented in the thread from %3$s" msgstr "%1$s skomentował w wątku od %3$s" -#: src/Navigation/Notifications/Factory/Notification.php:277 +#: src/Navigation/Notifications/Factory/Notification.php:292 #, php-format msgid "%1$s commented on your thread %2$s" msgstr "%1$s skomentował Twój wątek %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:214 -#: src/Navigation/Notifications/Repository/Notify.php:697 +#: src/Navigation/Notifications/Repository/Notify.php:222 +#: src/Navigation/Notifications/Repository/Notify.php:736 msgid "[Friendica:Notify]" msgstr "[Friendica: Powiadomienie]" -#: src/Navigation/Notifications/Repository/Notify.php:278 +#: src/Navigation/Notifications/Repository/Notify.php:286 #, php-format msgid "%s New mail received at %s" msgstr "%s Nowa poczta otrzymana o %s" -#: src/Navigation/Notifications/Repository/Notify.php:280 +#: src/Navigation/Notifications/Repository/Notify.php:288 #, php-format msgid "%1$s sent you a new private message at %2$s." msgstr "%1$s wysłał(-a) ci nową prywatną wiadomość na %2$s." -#: src/Navigation/Notifications/Repository/Notify.php:281 +#: src/Navigation/Notifications/Repository/Notify.php:289 msgid "a private message" msgstr "prywatna wiadomość" -#: src/Navigation/Notifications/Repository/Notify.php:281 +#: src/Navigation/Notifications/Repository/Notify.php:289 #, php-format msgid "%1$s sent you %2$s." msgstr "%1$s wysłał(-a) ci %2$s." -#: src/Navigation/Notifications/Repository/Notify.php:283 +#: src/Navigation/Notifications/Repository/Notify.php:291 #, php-format msgid "Please visit %s to view and/or reply to your private messages." msgstr "Odwiedź %s, aby zobaczyć i/lub odpowiedzieć na twoje prywatne wiadomości." -#: src/Navigation/Notifications/Repository/Notify.php:314 +#: src/Navigation/Notifications/Repository/Notify.php:321 #, php-format msgid "%1$s commented on %2$s's %3$s %4$s" msgstr "%1$s skomentował %2$s's %3$s %4$s" -#: src/Navigation/Notifications/Repository/Notify.php:319 +#: src/Navigation/Notifications/Repository/Notify.php:326 #, php-format msgid "%1$s commented on your %2$s %3$s" msgstr "%1$s skomentował Twój %2$s %3$s" -#: src/Navigation/Notifications/Repository/Notify.php:323 +#: src/Navigation/Notifications/Repository/Notify.php:330 #, php-format msgid "%1$s commented on their %2$s %3$s" msgstr "%1$s skomentował swój %2$s %3$s" -#: src/Navigation/Notifications/Repository/Notify.php:327 -#: src/Navigation/Notifications/Repository/Notify.php:732 +#: src/Navigation/Notifications/Repository/Notify.php:334 +#: src/Navigation/Notifications/Repository/Notify.php:770 #, php-format msgid "%1$s Comment to conversation #%2$d by %3$s" msgstr "%1$s Komentarz do rozmowy #%2$d autor %3$s" -#: src/Navigation/Notifications/Repository/Notify.php:329 +#: src/Navigation/Notifications/Repository/Notify.php:336 #, php-format msgid "%s commented on an item/conversation you have been following." msgstr "%s skomentował(-a) rozmowę którą śledzisz." -#: src/Navigation/Notifications/Repository/Notify.php:333 -#: src/Navigation/Notifications/Repository/Notify.php:348 -#: src/Navigation/Notifications/Repository/Notify.php:367 -#: src/Navigation/Notifications/Repository/Notify.php:747 +#: src/Navigation/Notifications/Repository/Notify.php:340 +#: src/Navigation/Notifications/Repository/Notify.php:355 +#: src/Navigation/Notifications/Repository/Notify.php:374 +#: src/Navigation/Notifications/Repository/Notify.php:785 #, php-format msgid "Please visit %s to view and/or reply to the conversation." msgstr "Odwiedź %s, aby zobaczyć i/lub odpowiedzieć na rozmowę." -#: src/Navigation/Notifications/Repository/Notify.php:340 +#: src/Navigation/Notifications/Repository/Notify.php:347 #, php-format msgid "%s %s posted to your profile wall" msgstr "%s %s opublikował na Twojej tablicy profilu" -#: src/Navigation/Notifications/Repository/Notify.php:342 +#: src/Navigation/Notifications/Repository/Notify.php:349 #, php-format msgid "%1$s posted to your profile wall at %2$s" msgstr "%1$s opublikował(-a) wpis na Twojej tablicy o %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:343 +#: src/Navigation/Notifications/Repository/Notify.php:350 #, php-format msgid "%1$s posted to [url=%2$s]your wall[/url]" msgstr "%1$s opublikował(-a) na [url=%2$s]Twojej tablicy[/url]" -#: src/Navigation/Notifications/Repository/Notify.php:355 +#: src/Navigation/Notifications/Repository/Notify.php:362 #, php-format msgid "%1$s %2$s poked you" msgstr "%1$s %2$s zaczepił Cię" -#: src/Navigation/Notifications/Repository/Notify.php:357 +#: src/Navigation/Notifications/Repository/Notify.php:364 #, php-format msgid "%1$s poked you at %2$s" msgstr "%1$s zaczepił Cię %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:358 +#: src/Navigation/Notifications/Repository/Notify.php:365 #, php-format msgid "%1$s [url=%2$s]poked you[/url]." msgstr "%1$s[url=%2$s] zaczepił Cię[/url]." -#: src/Navigation/Notifications/Repository/Notify.php:375 +#: src/Navigation/Notifications/Repository/Notify.php:382 #, php-format msgid "%s Introduction received" msgstr "%s Otrzymano wprowadzenie" -#: src/Navigation/Notifications/Repository/Notify.php:377 +#: src/Navigation/Notifications/Repository/Notify.php:384 #, php-format msgid "You've received an introduction from '%1$s' at %2$s" msgstr "Otrzymałeś wstęp od '%1$s' z %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:378 +#: src/Navigation/Notifications/Repository/Notify.php:385 #, php-format msgid "You've received [url=%1$s]an introduction[/url] from %2$s." msgstr "Zostałeś [url=%1$s] przyjęty [/ url] z %2$s." -#: src/Navigation/Notifications/Repository/Notify.php:383 -#: src/Navigation/Notifications/Repository/Notify.php:429 +#: src/Navigation/Notifications/Repository/Notify.php:390 +#: src/Navigation/Notifications/Repository/Notify.php:436 #, php-format msgid "You may visit their profile at %s" msgstr "Możesz odwiedzić ich profil na stronie %s" -#: src/Navigation/Notifications/Repository/Notify.php:385 +#: src/Navigation/Notifications/Repository/Notify.php:392 #, php-format msgid "Please visit %s to approve or reject the introduction." msgstr "Odwiedż %s aby zatwierdzić lub odrzucić przedstawienie." -#: src/Navigation/Notifications/Repository/Notify.php:392 +#: src/Navigation/Notifications/Repository/Notify.php:399 #, php-format msgid "%s A new person is sharing with you" msgstr "%s Nowa osoba udostępnia Ci coś" -#: src/Navigation/Notifications/Repository/Notify.php:394 -#: src/Navigation/Notifications/Repository/Notify.php:395 +#: src/Navigation/Notifications/Repository/Notify.php:401 +#: src/Navigation/Notifications/Repository/Notify.php:402 #, php-format msgid "%1$s is sharing with you at %2$s" msgstr "%1$s dzieli się z tobą w %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:402 +#: src/Navigation/Notifications/Repository/Notify.php:409 #, php-format msgid "%s You have a new follower" msgstr "%s Masz nowego obserwującego" -#: src/Navigation/Notifications/Repository/Notify.php:404 -#: src/Navigation/Notifications/Repository/Notify.php:405 +#: src/Navigation/Notifications/Repository/Notify.php:411 +#: src/Navigation/Notifications/Repository/Notify.php:412 #, php-format msgid "You have a new follower at %2$s : %1$s" msgstr "Masz nowego obserwatora na %2$s : %1$s" -#: src/Navigation/Notifications/Repository/Notify.php:418 +#: src/Navigation/Notifications/Repository/Notify.php:425 #, php-format msgid "%s Friend suggestion received" msgstr "%s Otrzymano sugestię znajomego" -#: src/Navigation/Notifications/Repository/Notify.php:420 +#: src/Navigation/Notifications/Repository/Notify.php:427 #, php-format msgid "You've received a friend suggestion from '%1$s' at %2$s" msgstr "Otrzymałeś od znajomego sugestię '%1$s' na %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:421 +#: src/Navigation/Notifications/Repository/Notify.php:428 #, php-format msgid "" "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." msgstr "Otrzymałeś [url=%1$s] sugestię znajomego [/url] dla %2$s od %3$s." -#: src/Navigation/Notifications/Repository/Notify.php:427 +#: src/Navigation/Notifications/Repository/Notify.php:434 msgid "Name:" msgstr "Imię:" -#: src/Navigation/Notifications/Repository/Notify.php:428 +#: src/Navigation/Notifications/Repository/Notify.php:435 msgid "Photo:" msgstr "Zdjęcie:" -#: src/Navigation/Notifications/Repository/Notify.php:431 +#: src/Navigation/Notifications/Repository/Notify.php:438 #, php-format msgid "Please visit %s to approve or reject the suggestion." msgstr "Odwiedź stronę %s, aby zatwierdzić lub odrzucić sugestię." -#: src/Navigation/Notifications/Repository/Notify.php:439 -#: src/Navigation/Notifications/Repository/Notify.php:454 +#: src/Navigation/Notifications/Repository/Notify.php:446 +#: src/Navigation/Notifications/Repository/Notify.php:461 #, php-format msgid "%s Connection accepted" msgstr "%s Połączenie zaakceptowane" -#: src/Navigation/Notifications/Repository/Notify.php:441 -#: src/Navigation/Notifications/Repository/Notify.php:456 +#: src/Navigation/Notifications/Repository/Notify.php:448 +#: src/Navigation/Notifications/Repository/Notify.php:463 #, php-format msgid "'%1$s' has accepted your connection request at %2$s" msgstr "'%1$s' zaakceptował Twoją prośbę o połączenie na %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:442 -#: src/Navigation/Notifications/Repository/Notify.php:457 +#: src/Navigation/Notifications/Repository/Notify.php:449 +#: src/Navigation/Notifications/Repository/Notify.php:464 #, php-format msgid "%2$s has accepted your [url=%1$s]connection request[/url]." msgstr "%2$s zaakceptował twoją [url=%1$s] prośbę o połączenie [/url]." -#: src/Navigation/Notifications/Repository/Notify.php:447 +#: src/Navigation/Notifications/Repository/Notify.php:454 msgid "" "You are now mutual friends and may exchange status updates, photos, and " "email without restriction." msgstr "Jesteście teraz przyjaciółmi i możesz wymieniać aktualizacje stanu, zdjęcia i e-maile bez ograniczeń." -#: src/Navigation/Notifications/Repository/Notify.php:449 +#: src/Navigation/Notifications/Repository/Notify.php:456 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "Odwiedź stronę %s jeśli chcesz wprowadzić zmiany w tym związku." -#: src/Navigation/Notifications/Repository/Notify.php:462 +#: src/Navigation/Notifications/Repository/Notify.php:469 #, php-format msgid "" "'%1$s' has chosen to accept you a fan, which restricts some forms of " @@ -10497,33 +10654,33 @@ msgid "" "automatically." msgstr "'%1$s' zdecydował się zaakceptować Cię jako fana, który ogranicza niektóre formy komunikacji - takie jak prywatne wiadomości i niektóre interakcje w profilu. Jeśli jest to strona celebrytów lub społeczności, ustawienia te zostały zastosowane automatycznie." -#: src/Navigation/Notifications/Repository/Notify.php:464 +#: src/Navigation/Notifications/Repository/Notify.php:471 #, php-format msgid "" "'%1$s' may choose to extend this into a two-way or more permissive " "relationship in the future." msgstr "'%1$s' możesz zdecydować o przedłużeniu tego w dwukierunkową lub bardziej ścisłą relację w przyszłości. " -#: src/Navigation/Notifications/Repository/Notify.php:466 +#: src/Navigation/Notifications/Repository/Notify.php:473 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "Odwiedź stronę %s, jeśli chcesz wprowadzić zmiany w tej relacji." -#: src/Navigation/Notifications/Repository/Notify.php:476 +#: src/Navigation/Notifications/Repository/Notify.php:483 msgid "registration request" msgstr "prośba o rejestrację" -#: src/Navigation/Notifications/Repository/Notify.php:478 +#: src/Navigation/Notifications/Repository/Notify.php:485 #, php-format msgid "You've received a registration request from '%1$s' at %2$s" msgstr "Otrzymałeś wniosek rejestracyjny od '%1$s' na %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:479 +#: src/Navigation/Notifications/Repository/Notify.php:486 #, php-format msgid "You've received a [url=%1$s]registration request[/url] from %2$s." msgstr "Otrzymałeś [url=%1$s] żądanie rejestracji [/url] od %2$s." -#: src/Navigation/Notifications/Repository/Notify.php:484 +#: src/Navigation/Notifications/Repository/Notify.php:491 #, php-format msgid "" "Full Name:\t%s\n" @@ -10531,17 +10688,17 @@ msgid "" "Login Name:\t%s (%s)" msgstr "Imię i nazwisko:\t%s\nLokalizacja witryny:\t%s\nNazwa użytkownika:\t%s(%s)" -#: src/Navigation/Notifications/Repository/Notify.php:490 +#: src/Navigation/Notifications/Repository/Notify.php:497 #, php-format msgid "Please visit %s to approve or reject the request." msgstr "Odwiedź stronę %s, aby zatwierdzić lub odrzucić wniosek." -#: src/Navigation/Notifications/Repository/Notify.php:726 +#: src/Navigation/Notifications/Repository/Notify.php:764 #, php-format msgid "%s %s tagged you" msgstr "%s %s oznaczył Cię" -#: src/Navigation/Notifications/Repository/Notify.php:729 +#: src/Navigation/Notifications/Repository/Notify.php:767 #, php-format msgid "%s %s shared a new post" msgstr "%s %s udostępnił nowy wpis" @@ -10569,194 +10726,194 @@ msgstr "Jeśli nie chcesz otrzymywać tych wiadomości kontaktuj się z nadawcą msgid "%s posted an update." msgstr "%s zaktualizował wpis." -#: src/Object/Post.php:134 +#: src/Object/Post.php:136 msgid "Private Message" msgstr "Wiadomość prywatna" -#: src/Object/Post.php:137 +#: src/Object/Post.php:140 msgid "Public Message" msgstr "Wiadomość publiczna" -#: src/Object/Post.php:140 +#: src/Object/Post.php:144 msgid "Unlisted Message" msgstr "Wiadomość niepubliczna" -#: src/Object/Post.php:170 +#: src/Object/Post.php:179 msgid "This entry was edited" msgstr "Ten wpis został zedytowany" -#: src/Object/Post.php:198 +#: src/Object/Post.php:207 msgid "Connector Message" msgstr "Komunikat łącznika" -#: src/Object/Post.php:213 src/Object/Post.php:215 +#: src/Object/Post.php:222 src/Object/Post.php:224 msgid "Edit" msgstr "Edytuj" -#: src/Object/Post.php:239 +#: src/Object/Post.php:248 msgid "Delete globally" msgstr "Usuń globalnie" -#: src/Object/Post.php:239 +#: src/Object/Post.php:248 msgid "Remove locally" msgstr "Usuń lokalnie" -#: src/Object/Post.php:255 +#: src/Object/Post.php:264 #, php-format msgid "Block %s" msgstr "Zablokuj %s" -#: src/Object/Post.php:260 +#: src/Object/Post.php:269 msgid "Save to folder" msgstr "Zapisz w katalogu" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I will attend" msgstr "Będę uczestniczyć" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I will not attend" msgstr "Nie będę uczestniczyć" -#: src/Object/Post.php:294 +#: src/Object/Post.php:304 msgid "I might attend" msgstr "Mogę wziąć udział" -#: src/Object/Post.php:324 +#: src/Object/Post.php:334 msgid "Ignore thread" msgstr "Zignoruj ​​wątek" -#: src/Object/Post.php:325 +#: src/Object/Post.php:335 msgid "Unignore thread" msgstr "Przestań ignorować ​​wątek" -#: src/Object/Post.php:326 +#: src/Object/Post.php:336 msgid "Toggle ignore status" msgstr "Przełącz stan ignorowania" -#: src/Object/Post.php:336 +#: src/Object/Post.php:346 msgid "Add star" msgstr "Dodaj gwiazdkę" -#: src/Object/Post.php:337 +#: src/Object/Post.php:347 msgid "Remove star" msgstr "Usuń gwiazdkę" -#: src/Object/Post.php:338 +#: src/Object/Post.php:348 msgid "Toggle star status" msgstr "Przełącz stan gwiazdy" -#: src/Object/Post.php:349 +#: src/Object/Post.php:359 msgid "Pin" msgstr "Przypnij" -#: src/Object/Post.php:350 +#: src/Object/Post.php:360 msgid "Unpin" msgstr "Odepnij" -#: src/Object/Post.php:351 +#: src/Object/Post.php:361 msgid "Toggle pin status" msgstr "Przełącz stan podpięcia" -#: src/Object/Post.php:354 +#: src/Object/Post.php:364 msgid "Pinned" msgstr "Przypięty" -#: src/Object/Post.php:359 +#: src/Object/Post.php:369 msgid "Add tag" msgstr "Dodaj znacznik" -#: src/Object/Post.php:372 +#: src/Object/Post.php:382 msgid "Quote share this" msgstr "Cytuj udostępnij to" -#: src/Object/Post.php:372 +#: src/Object/Post.php:382 msgid "Quote Share" msgstr "Udostępnienie cytatu" -#: src/Object/Post.php:375 +#: src/Object/Post.php:385 msgid "Reshare this" msgstr "Udostępnij to dalej" -#: src/Object/Post.php:375 +#: src/Object/Post.php:385 msgid "Reshare" msgstr "Udostępnij dalej" -#: src/Object/Post.php:376 +#: src/Object/Post.php:386 msgid "Cancel your Reshare" msgstr "Anuluj swoje dalsze udostępnianie" -#: src/Object/Post.php:376 +#: src/Object/Post.php:386 msgid "Unshare" msgstr "Przestań udostępniać" -#: src/Object/Post.php:423 +#: src/Object/Post.php:433 #, php-format msgid "%s (Received %s)" msgstr "%s (Otrzymano %s)" -#: src/Object/Post.php:428 +#: src/Object/Post.php:438 msgid "Comment this item on your system" msgstr "Skomentuj ten element w swoim systemie" -#: src/Object/Post.php:428 +#: src/Object/Post.php:438 msgid "Remote comment" msgstr "Zdalny komentarz" -#: src/Object/Post.php:449 +#: src/Object/Post.php:459 msgid "Share via ..." msgstr "Udostępnij poprzez..." -#: src/Object/Post.php:449 +#: src/Object/Post.php:459 msgid "Share via external services" msgstr "Udostępnij za pośrednictwem usług zewnętrznych" -#: src/Object/Post.php:478 +#: src/Object/Post.php:488 msgid "to" msgstr "do" -#: src/Object/Post.php:479 +#: src/Object/Post.php:489 msgid "via" msgstr "przez" -#: src/Object/Post.php:480 +#: src/Object/Post.php:490 msgid "Wall-to-Wall" msgstr "Tablica-w-Tablicę" -#: src/Object/Post.php:481 +#: src/Object/Post.php:491 msgid "via Wall-To-Wall:" msgstr "przez Tablica-w-Tablicę:" -#: src/Object/Post.php:523 +#: src/Object/Post.php:533 #, php-format msgid "Reply to %s" msgstr "Odpowiedź %s" -#: src/Object/Post.php:526 +#: src/Object/Post.php:536 msgid "More" msgstr "Więcej" -#: src/Object/Post.php:544 +#: src/Object/Post.php:554 msgid "Notifier task is pending" msgstr "Zadanie Notifier jest w toku" -#: src/Object/Post.php:545 +#: src/Object/Post.php:555 msgid "Delivery to remote servers is pending" msgstr "Trwa przesyłanie do serwerów zdalnych" -#: src/Object/Post.php:546 +#: src/Object/Post.php:556 msgid "Delivery to remote servers is underway" msgstr "Trwa dostawa do serwerów zdalnych" -#: src/Object/Post.php:547 +#: src/Object/Post.php:557 msgid "Delivery to remote servers is mostly done" msgstr "Dostawa do zdalnych serwerów jest w większości wykonywana" -#: src/Object/Post.php:548 +#: src/Object/Post.php:558 msgid "Delivery to remote servers is done" msgstr "Trwa dostarczanie do zdalnych serwerów" -#: src/Object/Post.php:568 +#: src/Object/Post.php:578 #, php-format msgid "%d comment" msgid_plural "%d comments" @@ -10765,50 +10922,50 @@ msgstr[1] "%d komentarze" msgstr[2] "%d komentarzy" msgstr[3] "%d komentarzy" -#: src/Object/Post.php:569 +#: src/Object/Post.php:579 msgid "Show more" msgstr "Pokaż więcej" -#: src/Object/Post.php:570 +#: src/Object/Post.php:580 msgid "Show fewer" msgstr "Pokaż mniej" -#: src/Protocol/OStatus.php:1648 +#: src/Protocol/OStatus.php:1705 #, php-format msgid "%s is now following %s." msgstr "%s zaczął(-ęła) obserwować %s." -#: src/Protocol/OStatus.php:1649 +#: src/Protocol/OStatus.php:1706 msgid "following" msgstr "następujący" -#: src/Protocol/OStatus.php:1652 +#: src/Protocol/OStatus.php:1709 #, php-format msgid "%s stopped following %s." msgstr "%s przestał(a) obserwować %s." -#: src/Protocol/OStatus.php:1653 +#: src/Protocol/OStatus.php:1710 msgid "stopped following" msgstr "przestał śledzić" -#: src/Render/FriendicaSmartyEngine.php:52 +#: src/Render/FriendicaSmartyEngine.php:65 msgid "The folder view/smarty3/ must be writable by webserver." msgstr "Katalog view/smarty3/ musi być zapisywalny przez serwer WWW." -#: src/Security/Authentication.php:221 +#: src/Security/Authentication.php:226 msgid "Login failed." msgstr "Logowanie nieudane." -#: src/Security/Authentication.php:262 +#: src/Security/Authentication.php:267 msgid "Login failed. Please check your credentials." msgstr "Logowanie nie powiodło się. Sprawdź swoje dane uwierzytelniające." -#: src/Security/Authentication.php:360 +#: src/Security/Authentication.php:369 #, php-format msgid "Welcome %s" msgstr "Witaj %s" -#: src/Security/Authentication.php:361 +#: src/Security/Authentication.php:370 msgid "Please upload a profile photo." msgstr "Proszę dodać zdjęcie profilowe." @@ -10906,15 +11063,15 @@ msgstr "w %1$d %2$s" msgid "%1$d %2$s ago" msgstr "%1$d %2$s temu" -#: src/Worker/Delivery.php:524 +#: src/Worker/Delivery.php:525 msgid "(no subject)" msgstr "(bez tematu)" -#: src/Worker/PushSubscription.php:103 +#: src/Worker/PushSubscription.php:112 msgid "Notification from Friendica" msgstr "Powiadomienia z Friendica" -#: src/Worker/PushSubscription.php:104 +#: src/Worker/PushSubscription.php:113 msgid "Empty Post" msgstr "Pusty wpis" @@ -11060,39 +11217,39 @@ msgstr "Kolor tła strony logowania" msgid "Leave background image and color empty for theme defaults" msgstr "Pozostaw pusty obraz tła i kolor dla domyślnych ustawień motywu" -#: view/theme/frio/php/Image.php:40 +#: view/theme/frio/php/Image.php:39 msgid "Top Banner" msgstr "Górny baner" -#: view/theme/frio/php/Image.php:40 +#: 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 "Zmień rozmiar obrazu do szerokości ekranu i pokaż kolor tła poniżej na długich stronach." -#: view/theme/frio/php/Image.php:41 +#: view/theme/frio/php/Image.php:40 msgid "Full screen" msgstr "Pełny ekran" -#: view/theme/frio/php/Image.php:41 +#: view/theme/frio/php/Image.php:40 msgid "" "Resize image to fill entire screen, clipping either the right or the bottom." msgstr "Zmień rozmiar obrazu, aby wypełnić cały ekran, przycinając prawy lub dolny." -#: view/theme/frio/php/Image.php:42 +#: view/theme/frio/php/Image.php:41 msgid "Single row mosaic" msgstr "Mozaika jednorzędowa" -#: view/theme/frio/php/Image.php:42 +#: view/theme/frio/php/Image.php:41 msgid "" "Resize image to repeat it on a single row, either vertical or horizontal." msgstr "Zmień rozmiar obrazu, aby powtórzyć go w jednym wierszu, w pionie lub w poziomie." -#: view/theme/frio/php/Image.php:43 +#: view/theme/frio/php/Image.php:42 msgid "Mosaic" msgstr "Mozaika" -#: view/theme/frio/php/Image.php:43 +#: view/theme/frio/php/Image.php:42 msgid "Repeat image to fill the screen." msgstr "Powtórz obraz, aby wypełnić ekran." diff --git a/view/lang/pl/strings.php b/view/lang/pl/strings.php index b827a085c0..8d4beab19c 100644 --- a/view/lang/pl/strings.php +++ b/view/lang/pl/strings.php @@ -418,6 +418,25 @@ $a->strings['Could not find any unarchived contact entry for this URL (%s)'] = ' $a->strings['The contact entries have been archived'] = 'Wpisy kontaktów zostały zarchiwizowane'; $a->strings['Could not find any contact entry for this URL (%s)'] = 'Nie można znaleźć żadnego kontaktu dla tego adresu URL (%s)'; $a->strings['The contact has been blocked from the node'] = 'Kontakt został zablokowany w węźle'; +$a->strings['%d %s, %d duplicates.'] = '%d %s, %d duplikaty.'; +$a->strings['uri-id is empty for contact %s.'] = 'uri-id jest pusty dla kontaktu%s.'; +$a->strings['No valid first countact found for uri-id %d.'] = 'Nie znaleziono prawidłowego pierwszego kontaktu dla identyfikatora uri-id %d.'; +$a->strings['Wrong duplicate found for uri-id %d in %d (url: %s != %s).'] = 'Odnaleziono nieprawidłowy duplikat dla identyfikatora uri %d w %d (url: %s != %s).'; +$a->strings['Wrong duplicate found for uri-id %d in %d (nurl: %s != %s).'] = 'Odnaleziono nieprawidłowy duplikat dla identyfikatora uri %d w %d (nurl: %s != %s).'; +$a->strings['Deletion of id %d failed'] = 'Nie udało się usunąć identyfikatora %d'; +$a->strings['Deletion of id %d was successful'] = 'Usunięcie identyfikatora %d powiodło się'; +$a->strings['Updating "%s" in "%s" from %d to %d'] = 'Aktualizowanie "%s" w "%s" z %d do %d'; +$a->strings[' - found'] = '- znaleziono'; +$a->strings[' - failed'] = ' - błąd'; +$a->strings[' - success'] = ' - powodzenie'; +$a->strings[' - deleted'] = ' - usunięto'; +$a->strings[' - done'] = ' - zrobiono'; +$a->strings['The avatar cache needs to be enabled to use this command.'] = 'Aby użyć tego polecenia, pamięć podręczna awatarów musi być włączona.'; +$a->strings['no resource in photo %s'] = 'brak zasobu na zdjęciu %s'; +$a->strings['no photo with id %s'] = 'brak zdjęcia z identyfikatorem %s'; +$a->strings['no image data for photo with id %s'] = 'brak danych obrazu dla zdjęcia z identyfikatorem %s'; +$a->strings['invalid image for id %s'] = 'nieprawidłowy obraz dla identyfikatora %s'; +$a->strings['Quit on invalid photo %s'] = 'Zakończ na nieprawidłowym zdjęciu %s'; $a->strings['Post update version number has been set to %s.'] = 'Numer wersji aktualizacji posta został ustawiony na %s.'; $a->strings['Check for pending update actions.'] = 'Sprawdź oczekujące działania aktualizacji.'; $a->strings['Done.'] = 'Gotowe.'; @@ -1336,8 +1355,6 @@ $a->strings['ID'] = 'ID'; $a->strings['Command'] = 'Polecenie'; $a->strings['Job Parameters'] = 'Parametry zadania'; $a->strings['Priority'] = 'Priorytet'; -$a->strings['Can not parse base url. Must have at least ://'] = 'Nie można zanalizować podstawowego adresu URL. Musi mieć co najmniej : //'; -$a->strings['Relocation started. Could take a while to complete.'] = 'Rozpoczęła się relokacja. Może trochę potrwać.'; $a->strings['No special theme for mobile devices'] = 'Brak specialnego motywu dla urządzeń mobilnych'; $a->strings['%s - (Experimental)'] = '%s- (Eksperymentalne)'; $a->strings['No community page for local users'] = 'Brak strony społeczności dla użytkowników lokalnych'; @@ -1371,8 +1388,9 @@ $a->strings['Message Relay'] = 'Przekaźnik wiadomości'; $a->strings['Use the command "console relay" in the command line to add or remove relays.'] = 'Użyj polecenia „console relay” w wierszu poleceń, aby dodać lub usunąć przekaźniki.'; $a->strings['The system is not subscribed to any relays at the moment.'] = 'System nie jest aktualnie objęty abonamentem na żadne przekaźniki.'; $a->strings['The system is currently subscribed to the following relays:'] = 'System jest obecnie objęty abonamentem na następujące przekaźniki:'; -$a->strings['Relocate Instance'] = 'Zmień lokalizację'; -$a->strings['Warning! Advanced function. Could make this server unreachable.'] = 'Ostrzeżenie! Zaawansowana funkcja. Może sprawić, że ten serwer będzie nieosiągalny.'; +$a->strings['Relocate Node'] = 'Przenieś węzeł'; +$a->strings['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:'] = 'Przeniesienie węzła umożliwia zmianę domeny DNS tego węzła i zachowanie wszystkich istniejących użytkowników i wpisów. Ten proces zajmuje trochę czasu i można go uruchomić tylko za pomocą konsolowego polecenia relokacji w następujący sposób:'; +$a->strings['(Friendica directory)# bin/console relocate https://newdomain.com'] = '(Katalog Friendica)# bin/console relocate https://nowadomena.pl'; $a->strings['Site name'] = 'Nazwa strony'; $a->strings['Sender Email'] = 'E-mail nadawcy'; $a->strings['The email address your server shall use to send notification emails from.'] = 'Adres e-mail używany przez Twój serwer do wysyłania e-maili z powiadomieniami.'; @@ -1512,8 +1530,6 @@ $a->strings['Temp path'] = 'Ścieżka do temp'; $a->strings['If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.'] = 'Jeśli masz zastrzeżony system, w którym serwer internetowy nie może uzyskać dostępu do ścieżki temp systemu, wprowadź tutaj inną ścieżkę.'; $a->strings['Only search in tags'] = 'Szukaj tylko w znacznikach'; $a->strings['On large systems the text search can slow down the system extremely.'] = 'W dużych systemach wyszukiwanie tekstu może wyjątkowo spowolnić system.'; -$a->strings['New base url'] = 'Nowy bazowy adres url'; -$a->strings['Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users.'] = 'Zmień bazowy adres URL dla tego serwera. Wysyła wiadomość o przeniesieniu do wszystkich kontaktów Friendica i Diaspora* wszystkich użytkowników.'; $a->strings['Maximum number of parallel workers'] = 'Maksymalna liczba równoległych workerów'; $a->strings['On shared hosters set this to %d. On larger systems, values of %d are great. Default value is %d.'] = 'Na udostępnionych usługach hostingowych ustaw tę opcję %d. W większych systemach wartości %dsą świetne . Wartość domyślna to %d.'; $a->strings['Enable fastlane'] = 'Włącz Fastlane'; @@ -2185,9 +2201,19 @@ $a->strings['

You can enter one of your one-time recovery codes in case you lo $a->strings['Don’t have your phone? Enter a two-factor recovery code'] = 'Nie masz telefonu? Wprowadzić dwuetapowy kod przywracania '; $a->strings['Please enter a recovery code'] = 'Wprowadź kod odzyskiwania'; $a->strings['Submit recovery code and complete login'] = 'Prześlij kod odzyskiwania i pełne logowanie'; +$a->strings['Sign out of this browser?'] = 'Wylogować z tej przeglądarki?'; +$a->strings['

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

'] = '

Jeśli ufasz tej przeglądarce, przy następnym logowaniu nie zostaniesz poproszony o podanie kodu weryfikacyjnego.

'; +$a->strings['Sign out'] = 'Wyloguj'; +$a->strings['Trust and sign out'] = 'Zaufaj i wyloguj'; +$a->strings['Couldn\'t save browser to Cookie.'] = 'Nie można zapisać informacji o przeglądarce do ciasteczek.'; +$a->strings['Trust this browser?'] = 'Ufać tej przeglądarce?'; +$a->strings['

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

'] = '

Jeśli zdecydujesz się zaufać tej przeglądarce, przy następnym logowaniu nie zostaniesz poproszony o podanie kodu weryfikacyjnego.

'; +$a->strings['Not now'] = 'Nie teraz'; +$a->strings['Don\'t trust'] = 'Nie ufaj'; +$a->strings['Trust'] = 'Truj'; $a->strings['

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

'] = '

Otwórz aplikację uwierzytelniania dwuskładnikowego na swoim urządzeniu, aby uzyskać kod uwierzytelniający i zweryfikować swoją tożsamość.

'; +$a->strings['If you do not have access to your authentication code you can use a two-factor recovery code.'] = 'Jeśli nie masz dostępu do swojego kodu uwierzytelniającego, możesz użyć dwuskładnikowego kodu odzyskiwania.'; $a->strings['Please enter a code from your authentication app'] = 'Wprowadź kod z aplikacji uwierzytelniającej'; -$a->strings['This is my two-factor authenticator app device'] = 'To jest moje urządzenie z dwuskładnikową aplikacją uwierzytelniającą'; $a->strings['Verify code and complete login'] = 'Zweryfikuj kod i zakończ logowanie'; $a->strings['Passwords do not match.'] = 'Hasła nie pasują do siebie.'; $a->strings['Password unchanged.'] = 'Hasło niezmienione.'; @@ -2278,8 +2304,14 @@ $a->strings['You receive a friend suggestion'] = 'Otrzymałeś propozycję od zn $a->strings['You are tagged in a post'] = 'Jesteś oznaczony znacznikiem we wpisie'; $a->strings['You are poked/prodded/etc. in a post'] = 'Jesteś zaczepiony/zaczepiona/itp. w poście'; $a->strings['Create a desktop notification when:'] = 'Utwórz powiadomienia na pulpicie gdy:'; +$a->strings['Someone tagged you'] = 'Ktoś Cię oznaczył'; +$a->strings['Someone directly commented on your post'] = 'Ktoś bezpośrednio skomentował Twój wpis'; $a->strings['Someone liked your content'] = 'Ktoś polubił Twoje treści'; +$a->strings['Can only be enabled, when the direct comment notification is enabled.'] = 'Można włączyć tylko wtedy, gdy włączone jest bezpośrednie powiadomienie o komentarzach.'; $a->strings['Someone shared your content'] = 'Ktoś udostępnił Twoje treści'; +$a->strings['Someone commented in your thread'] = 'Ktoś skomentował w Twoim wątku'; +$a->strings['Someone commented in a thread where you commented'] = 'Ktoś skomentował w wątku, w którym Ty skomentowałeś'; +$a->strings['Someone commented in a thread where you interacted'] = 'Ktoś skomentował w wątku, w którym wchodziłeś w interakcję'; $a->strings['Activate desktop notifications'] = 'Aktywuj powiadomienia na pulpicie'; $a->strings['Show desktop popup on new notifications'] = 'Pokazuj wyskakujące okienko gdy otrzymasz powiadomienie'; $a->strings['Text-only notification emails'] = 'E-maile z powiadomieniami tekstowymi'; @@ -2416,7 +2448,6 @@ $a->strings['Generate new app-specific password'] = 'Wygeneruj nowe hasło specy $a->strings['Friendiqa on my Fairphone 2...'] = 'Friendiqa na moim Fairphone 2...'; $a->strings['Generate'] = 'Utwórz'; $a->strings['Two-factor authentication successfully disabled.'] = 'Autoryzacja dwuskładnikowa została pomyślnie wyłączona.'; -$a->strings['Wrong Password'] = 'Złe hasło'; $a->strings['

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

'] = '

Użyj aplikacji na urządzeniu mobilnym, aby uzyskać dwuskładnikowe kody uwierzytelniające po wyświetleniu monitu o zalogowanie.

'; $a->strings['Authenticator app'] = 'Aplikacja Authenticator'; $a->strings['Configured'] = 'Skonfigurowane'; @@ -2450,6 +2481,7 @@ $a->strings['Trusted browsers are individual browsers you chose to skip two-fact $a->strings['Device'] = 'Urządzenie'; $a->strings['OS'] = 'System operacyjny'; $a->strings['Trusted'] = 'Zaufane'; +$a->strings['Created At'] = 'Utworzono'; $a->strings['Last Use'] = 'Ostatnie użycie'; $a->strings['Remove All'] = 'Usuń wszystkie'; $a->strings['Two-factor authentication successfully activated.'] = 'Uwierzytelnienie dwuskładnikowe zostało pomyślnie aktywowane.'; @@ -2529,6 +2561,7 @@ $a->strings['Getting Help'] = 'Otrzymaj pomoc'; $a->strings['Go to the Help Section'] = 'Przejdź do sekcji pomocy'; $a->strings['Our help pages may be consulted for detail on other program features and resources.'] = 'Na naszych stronach pomocy można znaleźć szczegółowe informacje na temat innych funkcji programu i zasobów.'; $a->strings['{0} wants to follow you'] = '{0} chce Cię obserwować'; +$a->strings['{0} has started following you'] = '{0} zaczął Cię obserwować'; $a->strings['%s liked %s\'s post'] = '%s polubił wpis %s'; $a->strings['%s disliked %s\'s post'] = '%s nie lubi wpisów %s'; $a->strings['%s is attending %s\'s event'] = '%s uczestniczy w wydarzeniu %s'; diff --git a/view/lang/sv/messages.po b/view/lang/sv/messages.po index 3448fb54bb..8012fc90c6 100644 --- a/view/lang/sv/messages.po +++ b/view/lang/sv/messages.po @@ -9,13 +9,14 @@ # Mike Macgirvin, 2010 # Tim Stahel , 2018 # Bjoessi , 2019 +# Viktor Nilsson, 2022 msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-01-24 04:58+0000\n" -"PO-Revision-Date: 2022-01-26 19:44+0000\n" -"Last-Translator: Kristoffer Grundström \n" +"POT-Creation-Date: 2022-06-25 22:37+0200\n" +"PO-Revision-Date: 2011-05-05 10:19+0000\n" +"Last-Translator: Viktor Nilsson, 2022\n" "Language-Team: Swedish (http://www.transifex.com/Friendica/friendica/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -23,73 +24,74 @@ msgstr "" "Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: mod/cal.php:44 mod/cal.php:48 mod/follow.php:39 mod/redir.php:34 -#: mod/redir.php:175 src/Module/Conversation/Community.php:181 -#: src/Module/Debug/ItemBody.php:37 src/Module/Diaspora/Receive.php:57 +#: mod/cal.php:46 mod/cal.php:50 mod/follow.php:39 mod/redir.php:36 +#: mod/redir.php:177 src/Module/Conversation/Community.php:181 +#: src/Module/Debug/ItemBody.php:38 src/Module/Diaspora/Receive.php:57 #: src/Module/Item/Follow.php:42 src/Module/Item/Ignore.php:41 #: src/Module/Item/Pin.php:42 src/Module/Item/Pin.php:57 #: src/Module/Item/Star.php:43 msgid "Access denied." msgstr "Åtkomst nekad." -#: mod/cal.php:61 mod/cal.php:78 mod/photos.php:69 mod/photos.php:140 -#: mod/photos.php:804 src/Model/Profile.php:229 src/Module/HCard.php:52 -#: src/Module/Profile/Common.php:41 src/Module/Profile/Common.php:52 -#: src/Module/Profile/Contacts.php:40 src/Module/Profile/Contacts.php:50 -#: src/Module/Profile/Media.php:38 src/Module/Profile/Status.php:58 -#: src/Module/Register.php:267 src/Module/RemoteFollow.php:58 +#: mod/cal.php:63 mod/cal.php:80 mod/photos.php:69 mod/photos.php:140 +#: mod/photos.php:798 src/Model/Profile.php:232 src/Module/Feed.php:72 +#: src/Module/HCard.php:52 src/Module/Profile/Common.php:41 +#: src/Module/Profile/Common.php:52 src/Module/Profile/Contacts.php:40 +#: src/Module/Profile/Contacts.php:50 src/Module/Profile/Media.php:38 +#: src/Module/Profile/Status.php:59 src/Module/Register.php:267 +#: src/Module/RemoteFollow.php:58 msgid "User not found." msgstr "Användaren hittades inte." -#: mod/cal.php:120 mod/display.php:270 src/Module/Profile/Profile.php:94 -#: src/Module/Profile/Profile.php:109 src/Module/Profile/Status.php:109 +#: mod/cal.php:122 mod/display.php:262 src/Module/Profile/Profile.php:94 +#: src/Module/Profile/Profile.php:109 src/Module/Profile/Status.php:110 #: src/Module/Update/Profile.php:56 msgid "Access to this profile has been restricted." msgstr "Åtkomst till den här profilen har begränsats." -#: mod/cal.php:242 mod/events.php:377 src/Content/Nav.php:194 +#: mod/cal.php:243 mod/events.php:374 src/Content/Nav.php:194 #: src/Content/Nav.php:258 src/Module/BaseProfile.php:84 #: src/Module/BaseProfile.php:95 view/theme/frio/theme.php:229 #: view/theme/frio/theme.php:233 msgid "Events" msgstr "Evenemang" -#: mod/cal.php:243 mod/events.php:378 +#: mod/cal.php:244 mod/events.php:375 msgid "View" msgstr "Visa" -#: mod/cal.php:244 mod/events.php:380 +#: mod/cal.php:245 mod/events.php:377 msgid "Previous" msgstr "Föregående" -#: mod/cal.php:245 mod/events.php:381 src/Module/Install.php:214 +#: mod/cal.php:246 mod/events.php:378 src/Module/Install.php:214 msgid "Next" msgstr "Nästa" -#: mod/cal.php:248 mod/events.php:386 src/Model/Event.php:457 +#: mod/cal.php:249 mod/events.php:383 src/Model/Event.php:456 msgid "today" msgstr "idag" -#: mod/cal.php:249 mod/events.php:387 src/Model/Event.php:458 +#: mod/cal.php:250 mod/events.php:384 src/Model/Event.php:457 #: src/Util/Temporal.php:334 msgid "month" msgstr "månad" -#: mod/cal.php:250 mod/events.php:388 src/Model/Event.php:459 +#: mod/cal.php:251 mod/events.php:385 src/Model/Event.php:458 #: src/Util/Temporal.php:335 msgid "week" msgstr "vecka" -#: mod/cal.php:251 mod/events.php:389 src/Model/Event.php:460 +#: mod/cal.php:252 mod/events.php:386 src/Model/Event.php:459 #: src/Util/Temporal.php:336 msgid "day" msgstr "dag" -#: mod/cal.php:252 mod/events.php:390 +#: mod/cal.php:253 mod/events.php:387 msgid "list" msgstr "lista" -#: mod/cal.php:265 src/Console/User.php:182 src/Model/User.php:659 +#: mod/cal.php:265 src/Console/User.php:182 src/Model/User.php:661 #: src/Module/Admin/Users/Active.php:73 src/Module/Admin/Users/Blocked.php:74 #: src/Module/Admin/Users/Index.php:80 src/Module/Admin/Users/Pending.php:71 #: src/Module/Api/Twitter/ContactEndpoint.php:74 @@ -102,52 +104,53 @@ msgstr "Kalenderformatet stöds inte" #: mod/cal.php:276 msgid "No exportable data found" -msgstr "" +msgstr "Inga data att exportera hittades" -#: mod/cal.php:293 +#: mod/cal.php:292 msgid "calendar" msgstr "kalender" -#: mod/display.php:165 mod/photos.php:808 -#: src/Module/Conversation/Community.php:175 src/Module/Directory.php:48 -#: src/Module/Search/Index.php:49 +#: mod/display.php:143 mod/photos.php:802 +#: src/Module/Conversation/Community.php:175 src/Module/Directory.php:49 +#: src/Module/Search/Index.php:65 msgid "Public access denied." msgstr "Publik åtkomst nekades." -#: mod/display.php:221 mod/display.php:295 +#: mod/display.php:213 mod/display.php:287 msgid "The requested item doesn't exist or has been deleted." msgstr "" -#: mod/display.php:375 +#: mod/display.php:367 msgid "The feed for this item is unavailable." msgstr "Flödet för det här föremålet är otillgängligt." -#: mod/editpost.php:38 mod/events.php:220 mod/follow.php:56 mod/follow.php:130 -#: mod/item.php:185 mod/item.php:190 mod/item.php:937 mod/message.php:69 -#: mod/message.php:111 mod/notes.php:44 mod/ostatus_subscribe.php:32 -#: mod/photos.php:160 mod/photos.php:897 mod/repair_ostatus.php:31 -#: mod/settings.php:46 mod/settings.php:56 mod/settings.php:412 +#: mod/editpost.php:38 mod/events.php:217 mod/follow.php:56 mod/follow.php:130 +#: mod/item.php:181 mod/item.php:186 mod/item.php:875 mod/message.php:69 +#: mod/message.php:111 mod/notes.php:44 mod/ostatus_subscribe.php:33 +#: mod/photos.php:160 mod/photos.php:891 mod/repair_ostatus.php:31 +#: mod/settings.php:40 mod/settings.php:50 mod/settings.php:156 #: mod/suggest.php:34 mod/uimport.php:33 mod/unfollow.php:35 -#: mod/unfollow.php:50 mod/unfollow.php:82 mod/wall_attach.php:68 -#: mod/wall_attach.php:71 mod/wall_upload.php:90 mod/wall_upload.php:93 +#: mod/unfollow.php:50 mod/unfollow.php:82 mod/wall_attach.php:67 +#: mod/wall_attach.php:69 mod/wall_upload.php:89 mod/wall_upload.php:91 #: mod/wallmessage.php:37 mod/wallmessage.php:56 mod/wallmessage.php:90 -#: mod/wallmessage.php:110 src/Module/Attach.php:55 src/Module/BaseApi.php:93 +#: mod/wallmessage.php:110 src/Module/Attach.php:56 src/Module/BaseApi.php:93 #: src/Module/BaseNotifications.php:97 src/Module/Contact/Advanced.php:60 #: src/Module/Delegation.php:119 src/Module/FollowConfirm.php:38 #: src/Module/FriendSuggest.php:56 src/Module/Group.php:42 -#: src/Module/Group.php:85 src/Module/Invite.php:41 src/Module/Invite.php:130 -#: src/Module/Notifications/Notification.php:48 -#: src/Module/Notifications/Notification.php:79 +#: src/Module/Group.php:85 src/Module/Invite.php:42 src/Module/Invite.php:131 +#: src/Module/Notifications/Notification.php:75 +#: src/Module/Notifications/Notification.php:106 #: src/Module/Profile/Common.php:56 src/Module/Profile/Contacts.php:56 #: src/Module/Profile/Schedule.php:39 src/Module/Profile/Schedule.php:56 #: 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/Delegation.php:42 +#: src/Module/Search/Directory.php:37 src/Module/Settings/Account.php:49 +#: src/Module/Settings/Account.php:409 src/Module/Settings/Delegation.php:42 #: src/Module/Settings/Delegation.php:70 src/Module/Settings/Display.php:42 #: src/Module/Settings/Display.php:120 #: src/Module/Settings/Profile/Photo/Crop.php:166 #: src/Module/Settings/Profile/Photo/Index.php:112 -#: src/Module/Settings/UserExport.php:57 src/Module/Settings/UserExport.php:91 +#: src/Module/Settings/UserExport.php:58 src/Module/Settings/UserExport.php:92 #: src/Module/Settings/UserExport.php:196 #: src/Module/Settings/UserExport.php:216 #: src/Module/Settings/UserExport.php:281 @@ -162,30 +165,30 @@ msgstr "Hittades inte" msgid "Edit post" msgstr "Ändra inlägg" -#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:875 +#: mod/editpost.php:91 mod/notes.php:56 src/Content/Text/HTML.php:882 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:73 msgid "Save" msgstr "Spara" -#: mod/editpost.php:92 mod/photos.php:1344 src/Content/Conversation.php:326 -#: src/Module/Contact/Poke.php:176 src/Object/Post.php:966 +#: mod/editpost.php:92 mod/photos.php:1338 src/Content/Conversation.php:338 +#: src/Module/Contact/Poke.php:176 src/Object/Post.php:993 msgid "Loading..." msgstr "Laddar..." #: mod/editpost.php:93 mod/message.php:198 mod/message.php:355 -#: mod/wallmessage.php:140 src/Content/Conversation.php:327 +#: mod/wallmessage.php:140 src/Content/Conversation.php:339 msgid "Upload photo" msgstr "Ladda upp bild" -#: mod/editpost.php:94 src/Content/Conversation.php:328 +#: mod/editpost.php:94 src/Content/Conversation.php:340 msgid "upload photo" msgstr "ladda upp bild" -#: mod/editpost.php:95 src/Content/Conversation.php:329 +#: mod/editpost.php:95 src/Content/Conversation.php:341 msgid "Attach file" msgstr "Bifoga fil" -#: mod/editpost.php:96 src/Content/Conversation.php:330 +#: mod/editpost.php:96 src/Content/Conversation.php:342 msgid "attach file" msgstr "bifoga fil" @@ -214,125 +217,126 @@ msgstr "Klistra in ljudlänk" msgid "audio link" msgstr "ljudlänk" -#: mod/editpost.php:103 src/Content/Conversation.php:340 -#: src/Module/Item/Compose.php:161 +#: mod/editpost.php:103 src/Content/Conversation.php:352 +#: src/Module/Item/Compose.php:173 msgid "Set your location" msgstr "Ange plats" -#: mod/editpost.php:104 src/Content/Conversation.php:341 +#: mod/editpost.php:104 src/Content/Conversation.php:353 msgid "set location" msgstr "ange plats" -#: mod/editpost.php:105 src/Content/Conversation.php:342 +#: mod/editpost.php:105 src/Content/Conversation.php:354 msgid "Clear browser location" msgstr "Clear browser location" -#: mod/editpost.php:106 src/Content/Conversation.php:343 +#: mod/editpost.php:106 src/Content/Conversation.php:355 msgid "clear location" msgstr "rensa plats" #: mod/editpost.php:107 mod/message.php:200 mod/message.php:358 -#: mod/photos.php:1495 mod/wallmessage.php:142 -#: src/Content/Conversation.php:355 src/Content/Conversation.php:690 -#: src/Module/Item/Compose.php:165 src/Object/Post.php:504 +#: mod/photos.php:1489 mod/wallmessage.php:142 +#: src/Content/Conversation.php:368 src/Content/Conversation.php:713 +#: src/Module/Item/Compose.php:177 src/Object/Post.php:538 msgid "Please wait" msgstr "Var god vänta" -#: mod/editpost.php:108 src/Content/Conversation.php:356 +#: mod/editpost.php:108 src/Content/Conversation.php:369 msgid "Permission settings" msgstr "Åtkomstinställningar" -#: mod/editpost.php:116 src/Core/ACL.php:325 +#: mod/editpost.php:116 src/Core/ACL.php:326 msgid "CC: email addresses" msgstr "Kopia: e-postadresser" -#: mod/editpost.php:117 src/Content/Conversation.php:366 +#: mod/editpost.php:117 src/Content/Conversation.php:379 msgid "Public post" msgstr "Offentligt inlägg" -#: mod/editpost.php:120 src/Content/Conversation.php:345 -#: src/Module/Item/Compose.php:166 +#: mod/editpost.php:120 src/Content/Conversation.php:357 +#: src/Module/Item/Compose.php:178 msgid "Set title" msgstr "Ange rubrik" -#: mod/editpost.php:122 src/Content/Conversation.php:347 -#: src/Module/Item/Compose.php:167 +#: mod/editpost.php:122 src/Content/Conversation.php:359 +#: src/Module/Item/Compose.php:179 msgid "Categories (comma-separated list)" msgstr "Kategorier (kommaseparerad lista)" -#: mod/editpost.php:123 src/Core/ACL.php:326 +#: mod/editpost.php:123 src/Core/ACL.php:327 msgid "Example: bob@example.com, mary@example.com" msgstr "Exempel: adam@exempel.com, bertil@exempel.com" -#: mod/editpost.php:128 mod/events.php:517 mod/photos.php:1343 -#: mod/photos.php:1399 mod/photos.php:1473 src/Content/Conversation.php:370 -#: src/Module/Item/Compose.php:160 src/Object/Post.php:976 +#: mod/editpost.php:128 mod/events.php:513 mod/photos.php:1337 +#: mod/photos.php:1393 mod/photos.php:1467 src/Content/Conversation.php:383 +#: src/Module/Item/Compose.php:172 src/Object/Post.php:1003 msgid "Preview" msgstr "Förhandsgranskning" -#: mod/editpost.php:130 mod/fbrowser.php:117 mod/fbrowser.php:144 -#: mod/follow.php:144 mod/photos.php:1010 mod/photos.php:1111 mod/tagrm.php:35 -#: mod/tagrm.php:127 mod/unfollow.php:97 src/Content/Conversation.php:373 -#: src/Module/Contact/Revoke.php:110 src/Module/RemoteFollow.php:127 +#: mod/editpost.php:130 mod/fbrowser.php:118 mod/fbrowser.php:145 +#: mod/follow.php:144 mod/photos.php:1004 mod/photos.php:1105 mod/tagrm.php:35 +#: mod/tagrm.php:127 mod/unfollow.php:97 src/Content/Conversation.php:386 +#: src/Module/Contact/Revoke.php:108 src/Module/RemoteFollow.php:127 +#: src/Module/Security/TwoFactor/Signout.php:125 msgid "Cancel" msgstr "Avbryt" -#: mod/editpost.php:134 src/Content/Conversation.php:331 -#: src/Module/Item/Compose.php:151 src/Object/Post.php:967 +#: mod/editpost.php:134 src/Content/Conversation.php:343 +#: src/Module/Item/Compose.php:163 src/Object/Post.php:994 msgid "Bold" msgstr "Fet" -#: mod/editpost.php:135 src/Content/Conversation.php:332 -#: src/Module/Item/Compose.php:152 src/Object/Post.php:968 +#: mod/editpost.php:135 src/Content/Conversation.php:344 +#: src/Module/Item/Compose.php:164 src/Object/Post.php:995 msgid "Italic" msgstr "Kursiv" -#: mod/editpost.php:136 src/Content/Conversation.php:333 -#: src/Module/Item/Compose.php:153 src/Object/Post.php:969 +#: mod/editpost.php:136 src/Content/Conversation.php:345 +#: src/Module/Item/Compose.php:165 src/Object/Post.php:996 msgid "Underline" msgstr "Understruken" -#: mod/editpost.php:137 src/Content/Conversation.php:334 -#: src/Module/Item/Compose.php:154 src/Object/Post.php:970 +#: mod/editpost.php:137 src/Content/Conversation.php:346 +#: src/Module/Item/Compose.php:166 src/Object/Post.php:997 msgid "Quote" msgstr "Citat" -#: mod/editpost.php:138 src/Content/Conversation.php:335 -#: src/Module/Item/Compose.php:155 src/Object/Post.php:971 +#: mod/editpost.php:138 src/Content/Conversation.php:347 +#: src/Module/Item/Compose.php:167 src/Object/Post.php:998 msgid "Code" msgstr "Källkod" -#: mod/editpost.php:139 src/Content/Conversation.php:337 -#: src/Module/Item/Compose.php:157 src/Object/Post.php:973 +#: mod/editpost.php:139 src/Content/Conversation.php:349 +#: src/Module/Item/Compose.php:169 src/Object/Post.php:1000 msgid "Link" msgstr "Länk" -#: mod/editpost.php:140 src/Content/Conversation.php:338 -#: src/Module/Item/Compose.php:158 src/Object/Post.php:974 +#: mod/editpost.php:140 src/Content/Conversation.php:350 +#: src/Module/Item/Compose.php:170 src/Object/Post.php:1001 msgid "Link or Media" msgstr "Länk eller media" -#: mod/editpost.php:143 src/Content/Conversation.php:380 -#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:460 -#: src/Module/Admin/Logs/View.php:92 +#: mod/editpost.php:143 src/Content/Conversation.php:393 +#: src/Content/Widget/VCard.php:113 src/Model/Profile.php:463 +#: src/Module/Admin/Logs/View.php:93 msgid "Message" msgstr "Meddelande" -#: mod/editpost.php:144 src/Content/Conversation.php:381 -#: src/Module/Settings/TwoFactor/Trusted.php:137 +#: mod/editpost.php:144 src/Content/Conversation.php:394 +#: src/Module/Settings/TwoFactor/Trusted.php:138 msgid "Browser" msgstr "Bläddra" -#: mod/editpost.php:145 mod/events.php:522 mod/photos.php:945 -#: mod/photos.php:1297 src/Content/Conversation.php:357 +#: mod/editpost.php:145 mod/events.php:518 mod/photos.php:939 +#: mod/photos.php:1291 src/Content/Conversation.php:370 msgid "Permissions" msgstr "Åtkomst" -#: mod/editpost.php:147 src/Content/Conversation.php:383 +#: mod/editpost.php:147 src/Content/Conversation.php:396 msgid "Open Compose page" msgstr "" -#: mod/events.php:123 mod/events.php:125 +#: mod/events.php:124 mod/events.php:126 msgid "Event can not end before it has started." msgstr "Evenemanget kan inte sluta före det har börjat." @@ -340,23 +344,23 @@ msgstr "Evenemanget kan inte sluta före det har börjat." msgid "Event title and start time are required." msgstr "Evenemangets titel och start-tid krävs." -#: mod/events.php:379 +#: mod/events.php:376 msgid "Create New Event" msgstr "Skapa nytt evenemang" -#: mod/events.php:478 src/Module/Admin/Logs/View.php:96 +#: mod/events.php:474 src/Module/Admin/Logs/View.php:97 msgid "Event details" msgstr "Evenemangets detaljer" -#: mod/events.php:479 +#: mod/events.php:475 msgid "Starting date and Title are required." msgstr "Start-datum och titel krävs." -#: mod/events.php:480 mod/events.php:485 +#: mod/events.php:476 mod/events.php:481 msgid "Event Starts:" msgstr "Evenemanget börjar:" -#: mod/events.php:480 mod/events.php:510 +#: mod/events.php:476 mod/events.php:506 #: src/Module/Admin/Blocklist/Server/Add.php:104 #: src/Module/Admin/Blocklist/Server/Add.php:106 #: src/Module/Admin/Blocklist/Server/Index.php:68 @@ -369,83 +373,83 @@ msgstr "Evenemanget börjar:" #: src/Module/Install.php:286 src/Module/Install.php:291 #: src/Module/Install.php:305 src/Module/Install.php:320 #: src/Module/Install.php:347 src/Module/Register.php:148 -#: src/Module/Security/TwoFactor/Verify.php:100 -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Security/TwoFactor/Verify.php:101 +#: src/Module/Settings/TwoFactor/Index.php:136 #: src/Module/Settings/TwoFactor/Verify.php:154 msgid "Required" msgstr "Krävs" -#: mod/events.php:493 mod/events.php:516 +#: mod/events.php:489 mod/events.php:512 msgid "Finish date/time is not known or not relevant" msgstr "Slut-datum/tid är inte känt eller icke relevant" -#: mod/events.php:495 mod/events.php:500 +#: mod/events.php:491 mod/events.php:496 msgid "Event Finishes:" msgstr "Evenemanget slutar:" -#: mod/events.php:506 src/Module/Profile/Profile.php:172 +#: mod/events.php:502 src/Module/Profile/Profile.php:172 #: src/Module/Settings/Profile/Index.php:238 msgid "Description:" msgstr "Beskrivning:" -#: mod/events.php:508 src/Content/Widget/VCard.php:98 src/Model/Event.php:80 -#: src/Model/Event.php:107 src/Model/Event.php:466 src/Model/Event.php:915 -#: src/Model/Profile.php:368 src/Module/Contact/Profile.php:369 -#: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:185 +#: mod/events.php:504 src/Content/Widget/VCard.php:104 src/Model/Event.php:80 +#: src/Model/Event.php:107 src/Model/Event.php:465 src/Model/Event.php:915 +#: src/Model/Profile.php:371 src/Module/Contact/Profile.php:369 +#: src/Module/Directory.php:148 src/Module/Notifications/Introductions.php:185 #: src/Module/Profile/Profile.php:194 msgid "Location:" msgstr "Plats:" -#: mod/events.php:510 mod/events.php:512 +#: mod/events.php:506 mod/events.php:508 msgid "Title:" msgstr "Titel:" -#: mod/events.php:513 mod/events.php:514 +#: mod/events.php:509 mod/events.php:510 msgid "Share this event" msgstr "Dela det här evenemanget" -#: mod/events.php:519 mod/message.php:201 mod/message.php:357 -#: mod/photos.php:927 mod/photos.php:1031 mod/photos.php:1301 -#: mod/photos.php:1342 mod/photos.php:1398 mod/photos.php:1472 +#: mod/events.php:515 mod/message.php:201 mod/message.php:357 +#: mod/photos.php:921 mod/photos.php:1025 mod/photos.php:1295 +#: mod/photos.php:1336 mod/photos.php:1392 mod/photos.php:1466 #: src/Module/Admin/Item/Source.php:65 src/Module/Contact/Advanced.php:132 #: src/Module/Contact/Poke.php:177 src/Module/Contact/Profile.php:327 -#: src/Module/Debug/ActivityPubConversion.php:141 +#: src/Module/Debug/ActivityPubConversion.php:145 #: 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:148 src/Module/FriendSuggest.php:144 #: src/Module/Install.php:252 src/Module/Install.php:294 -#: src/Module/Install.php:331 src/Module/Invite.php:177 -#: src/Module/Item/Compose.php:150 src/Module/Profile/Profile.php:247 -#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:965 +#: src/Module/Install.php:331 src/Module/Invite.php:178 +#: src/Module/Item/Compose.php:162 src/Module/Profile/Profile.php:247 +#: src/Module/Settings/Profile/Index.php:222 src/Object/Post.php:992 #: view/theme/duepuntozero/config.php:69 view/theme/frio/config.php:160 #: view/theme/quattro/config.php:71 view/theme/vier/config.php:119 msgid "Submit" msgstr "Spara" -#: mod/events.php:520 src/Module/Profile/Profile.php:248 +#: mod/events.php:516 src/Module/Profile/Profile.php:248 msgid "Basic" msgstr "Standard" -#: mod/events.php:521 src/Module/Admin/Site.php:506 src/Module/Contact.php:474 +#: mod/events.php:517 src/Module/Admin/Site.php:439 src/Module/Contact.php:474 #: src/Module/Profile/Profile.php:249 msgid "Advanced" msgstr "Avancerat" -#: mod/events.php:538 +#: mod/events.php:534 msgid "Failed to remove event" msgstr "Borttagning av evenemanget misslyckades" -#: mod/fbrowser.php:60 src/Content/Nav.php:192 src/Module/BaseProfile.php:64 +#: mod/fbrowser.php:61 src/Content/Nav.php:192 src/Module/BaseProfile.php:64 #: view/theme/frio/theme.php:227 msgid "Photos" msgstr "Bilder" -#: mod/fbrowser.php:119 mod/fbrowser.php:146 +#: mod/fbrowser.php:120 mod/fbrowser.php:147 #: src/Module/Settings/Profile/Photo/Index.php:129 msgid "Upload" msgstr "Ladda upp" -#: mod/fbrowser.php:141 +#: mod/fbrowser.php:142 msgid "Files" msgstr "Filer" @@ -469,8 +473,8 @@ msgstr "Stödet för Diaspora är inte aktiverat. Kontakten kan inte läggas til msgid "OStatus support is disabled. Contact can't be added." msgstr "Stödet för OStatus är inaktiverat. Kontakten kan inte läggas till." -#: mod/follow.php:138 src/Content/Item.php:463 src/Content/Widget.php:76 -#: src/Model/Contact.php:1056 src/Model/Contact.php:1068 +#: mod/follow.php:138 src/Content/Item.php:443 src/Content/Widget.php:80 +#: src/Model/Contact.php:1103 src/Model/Contact.php:1115 #: view/theme/vier/theme.php:172 msgid "Connect/Follow" msgstr "Gör till kontakt/Följ" @@ -515,29 +519,29 @@ msgstr "Statusmeddelanden och inlägg" msgid "The contact could not be added." msgstr "Kontakten kunde inte läggas till." -#: mod/item.php:135 mod/item.php:139 +#: mod/item.php:131 mod/item.php:135 msgid "Unable to locate original post." msgstr "Hittar inte det ursprungliga inlägget." -#: mod/item.php:341 mod/item.php:346 +#: mod/item.php:337 mod/item.php:342 msgid "Empty post discarded." msgstr "Tomt inlägg. Inte sparat." -#: mod/item.php:743 +#: mod/item.php:687 msgid "Post updated." msgstr "Inlägget uppdaterades." -#: mod/item.php:753 mod/item.php:758 +#: mod/item.php:697 mod/item.php:702 msgid "Item wasn't stored." msgstr "Objektet lagrades inte." -#: mod/item.php:769 +#: mod/item.php:713 msgid "Item couldn't be fetched." msgstr "Objektet kunde inte hämtas." -#: mod/item.php:915 src/Module/Admin/Themes/Details.php:39 -#: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:41 -#: src/Module/Debug/ItemBody.php:56 +#: mod/item.php:853 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 msgid "Item not found." msgstr "Hittar inte." @@ -679,7 +683,7 @@ msgstr "Ditt lösenord ändrades den %s" msgid "No keywords to match. Please add keywords to your profile." msgstr "" -#: mod/match.php:93 src/Module/BaseSearch.php:116 +#: mod/match.php:93 src/Module/BaseSearch.php:119 msgid "No matches" msgstr "Ingen träff" @@ -709,7 +713,7 @@ msgstr "Insamling av meddelanden misslyckades." #: mod/message.php:120 src/Module/Notifications/Introductions.php:133 #: src/Module/Notifications/Introductions.php:168 -#: src/Module/Notifications/Notification.php:57 +#: src/Module/Notifications/Notification.php:84 msgid "Discard" msgstr "Ta bort" @@ -746,7 +750,7 @@ msgid "Subject:" msgstr "Rubrik:" #: mod/message.php:195 mod/message.php:351 mod/wallmessage.php:138 -#: src/Module/Invite.php:170 +#: src/Module/Invite.php:171 msgid "Your message:" msgstr "Meddelande:" @@ -810,51 +814,51 @@ msgstr "Personliga anteckningar" msgid "Personal notes are visible only by yourself." msgstr "Personliga anteckningar kan endast ses av dig själv." -#: mod/ostatus_subscribe.php:37 +#: mod/ostatus_subscribe.php:38 msgid "Subscribing to contacts" msgstr "Prenumererar på kontakter" -#: mod/ostatus_subscribe.php:47 +#: mod/ostatus_subscribe.php:48 msgid "No contact provided." -msgstr "" +msgstr "Ingen kontakt angedd" -#: mod/ostatus_subscribe.php:53 +#: mod/ostatus_subscribe.php:54 msgid "Couldn't fetch information for contact." msgstr "Kunde inte hämta information för kontakten." -#: mod/ostatus_subscribe.php:64 +#: mod/ostatus_subscribe.php:65 msgid "Couldn't fetch friends for contact." msgstr "Kunde inte hämta vänner för kontakt." -#: mod/ostatus_subscribe.php:70 mod/ostatus_subscribe.php:81 +#: mod/ostatus_subscribe.php:71 mod/ostatus_subscribe.php:82 msgid "Couldn't fetch following contacts." msgstr "Kunde inte hämta följande kontakter." -#: mod/ostatus_subscribe.php:76 +#: mod/ostatus_subscribe.php:77 msgid "Couldn't fetch remote profile." -msgstr "" +msgstr "Kunde inte hämta profil" -#: mod/ostatus_subscribe.php:86 +#: mod/ostatus_subscribe.php:87 msgid "Unsupported network" msgstr "Nätverket stöds inte" -#: mod/ostatus_subscribe.php:102 mod/repair_ostatus.php:51 +#: mod/ostatus_subscribe.php:103 mod/repair_ostatus.php:51 msgid "Done" msgstr "Färdig" -#: mod/ostatus_subscribe.php:116 +#: mod/ostatus_subscribe.php:117 msgid "success" msgstr "lyckades" -#: mod/ostatus_subscribe.php:118 +#: mod/ostatus_subscribe.php:119 msgid "failed" msgstr "misslyckades" -#: mod/ostatus_subscribe.php:121 +#: mod/ostatus_subscribe.php:122 msgid "ignored" msgstr "ignorerades" -#: mod/ostatus_subscribe.php:126 mod/repair_ostatus.php:57 +#: mod/ostatus_subscribe.php:127 mod/repair_ostatus.php:57 msgid "Keep this window open until done." msgstr "Håll det här fönstret öppet tills du är klar." @@ -862,11 +866,11 @@ msgstr "Håll det här fönstret öppet tills du är klar." msgid "Photo Albums" msgstr "Fotoalbum" -#: mod/photos.php:109 mod/photos.php:1590 +#: mod/photos.php:109 mod/photos.php:1584 msgid "Recent Photos" msgstr "Nyligen tillagda bilder" -#: mod/photos.php:111 mod/photos.php:1079 mod/photos.php:1592 +#: mod/photos.php:111 mod/photos.php:1073 mod/photos.php:1586 msgid "Upload New Photos" msgstr "Ladda upp bilder" @@ -894,242 +898,229 @@ msgstr "Albumet var tomt." msgid "Failed to delete the photo." msgstr "Borttagningen av fotot misslyckades." -#: mod/photos.php:559 +#: mod/photos.php:553 msgid "a photo" msgstr "ett foto" -#: mod/photos.php:559 +#: mod/photos.php:553 #, php-format msgid "%1$s was tagged in %2$s by %3$s" msgstr "%1$s taggades i %2$s av %3$s" -#: mod/photos.php:642 mod/photos.php:645 mod/photos.php:672 -#: mod/wall_upload.php:204 src/Module/Settings/Profile/Photo/Index.php:60 +#: mod/photos.php:636 mod/photos.php:639 mod/photos.php:666 +#: mod/wall_upload.php:201 src/Module/Settings/Profile/Photo/Index.php:60 #, php-format msgid "Image exceeds size limit of %s" -msgstr "" +msgstr "Bildstorlek överstiger %s" -#: mod/photos.php:648 +#: mod/photos.php:642 msgid "Image upload didn't complete, please try again" msgstr "Uppladdningen av bilden slutfördes inte, vänligen försök igen." -#: mod/photos.php:651 +#: mod/photos.php:645 msgid "Image file is missing" msgstr "Bildfilen saknas" -#: mod/photos.php:656 +#: mod/photos.php:650 msgid "" "Server can't accept new file upload at this time, please contact your " "administrator" msgstr "Servern kan just nu inte acceptera uppladdning av en ny fil, vänligen kontakta din administratör" -#: mod/photos.php:680 +#: mod/photos.php:674 msgid "Image file is empty." msgstr "Bildfilen är tom." -#: mod/photos.php:695 mod/wall_upload.php:166 +#: mod/photos.php:689 mod/wall_upload.php:163 #: src/Module/Settings/Profile/Photo/Index.php:69 msgid "Unable to process image." msgstr "Det gick inte att behandla bilden." -#: mod/photos.php:721 mod/wall_upload.php:229 +#: mod/photos.php:715 mod/wall_upload.php:226 #: src/Module/Settings/Profile/Photo/Index.php:96 msgid "Image upload failed." msgstr "Fel vid bilduppladdning." -#: mod/photos.php:813 +#: mod/photos.php:807 msgid "No photos selected" msgstr "Inga bilder har valts" -#: mod/photos.php:882 +#: mod/photos.php:876 msgid "Access to this item is restricted." msgstr "Åtkomst till det här objekt är begränsat." -#: mod/photos.php:937 +#: mod/photos.php:931 msgid "Upload Photos" msgstr "Ladda upp bilder" -#: mod/photos.php:941 mod/photos.php:1027 +#: mod/photos.php:935 mod/photos.php:1021 msgid "New album name: " msgstr "Nytt album med namn: " -#: mod/photos.php:942 +#: mod/photos.php:936 msgid "or select existing album:" msgstr "eller välj befintligt album:" -#: mod/photos.php:943 +#: mod/photos.php:937 msgid "Do not show a status post for this upload" msgstr "Visa inte ett status-inlägg för den här uppladdningen" -#: mod/photos.php:1008 +#: mod/photos.php:1002 msgid "Do you really want to delete this photo album and all its photos?" msgstr "Vill du verkligen ta bort det här fotoalbumet och alla dess foton?" -#: mod/photos.php:1009 mod/photos.php:1032 +#: mod/photos.php:1003 mod/photos.php:1026 msgid "Delete Album" msgstr "Ta bort album" -#: mod/photos.php:1036 +#: mod/photos.php:1030 msgid "Edit Album" msgstr "Redigera album" -#: mod/photos.php:1037 +#: mod/photos.php:1031 msgid "Drop Album" msgstr "Släpp albumet" -#: mod/photos.php:1041 +#: mod/photos.php:1035 msgid "Show Newest First" msgstr "Visa nyaste först" -#: mod/photos.php:1043 +#: mod/photos.php:1037 msgid "Show Oldest First" msgstr "Visa äldsta först" -#: mod/photos.php:1064 mod/photos.php:1575 +#: mod/photos.php:1058 mod/photos.php:1569 msgid "View Photo" msgstr "Visa bild" -#: mod/photos.php:1097 +#: mod/photos.php:1091 msgid "Permission denied. Access to this item may be restricted." msgstr "Tillståndet nekades. Åtkomst till det här objektet kan vara begränsad." -#: mod/photos.php:1099 +#: mod/photos.php:1093 msgid "Photo not available" msgstr "Bilden är inte tillgänglig" -#: mod/photos.php:1109 +#: mod/photos.php:1103 msgid "Do you really want to delete this photo?" msgstr "Vill du verkligen ta bort det här fotot?" -#: mod/photos.php:1110 mod/photos.php:1302 +#: mod/photos.php:1104 mod/photos.php:1296 msgid "Delete Photo" msgstr "Ta bort bild" -#: mod/photos.php:1200 +#: mod/photos.php:1196 msgid "View photo" msgstr "Visa fotot" -#: mod/photos.php:1202 +#: mod/photos.php:1198 msgid "Edit photo" msgstr "Hantera bild" -#: mod/photos.php:1203 +#: mod/photos.php:1199 msgid "Delete photo" msgstr "Ta bort fotot" -#: mod/photos.php:1204 +#: mod/photos.php:1200 msgid "Use as profile photo" msgstr "Använd som ett profilfoto" -#: mod/photos.php:1211 +#: mod/photos.php:1207 msgid "Private Photo" msgstr "Privat foto" -#: mod/photos.php:1217 +#: mod/photos.php:1213 msgid "View Full Size" msgstr "Visa fullstor" -#: mod/photos.php:1270 +#: mod/photos.php:1264 msgid "Tags: " msgstr "Taggar: " -#: mod/photos.php:1273 +#: mod/photos.php:1267 msgid "[Select tags to remove]" msgstr "[Välj taggar att ta bort]" -#: mod/photos.php:1288 +#: mod/photos.php:1282 msgid "New album name" msgstr "Nytt album med namn" -#: mod/photos.php:1289 +#: mod/photos.php:1283 msgid "Caption" msgstr "Caption" -#: mod/photos.php:1290 +#: mod/photos.php:1284 msgid "Add a Tag" msgstr "Lägg till tagg" -#: mod/photos.php:1290 +#: mod/photos.php:1284 msgid "" "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" msgstr "Exempel: @adam, @Anna_Andersson, @johan@exempel.com, #Stockholm, #camping" -#: mod/photos.php:1291 +#: mod/photos.php:1285 msgid "Do not rotate" msgstr "Rotera inte" -#: mod/photos.php:1292 +#: mod/photos.php:1286 msgid "Rotate CW (right)" msgstr "Rotera medurs (höger)" -#: mod/photos.php:1293 +#: mod/photos.php:1287 msgid "Rotate CCW (left)" msgstr "Rotera Moturs (vänster)" -#: mod/photos.php:1339 mod/photos.php:1395 mod/photos.php:1469 -#: src/Module/Contact.php:544 src/Module/Item/Compose.php:148 -#: src/Object/Post.php:962 +#: mod/photos.php:1333 mod/photos.php:1389 mod/photos.php:1463 +#: src/Module/Contact.php:544 src/Module/Item/Compose.php:160 +#: src/Object/Post.php:989 msgid "This is you" msgstr "Det här är du" -#: mod/photos.php:1341 mod/photos.php:1397 mod/photos.php:1471 -#: src/Object/Post.php:498 src/Object/Post.php:964 +#: mod/photos.php:1335 mod/photos.php:1391 mod/photos.php:1465 +#: src/Object/Post.php:532 src/Object/Post.php:991 msgid "Comment" msgstr "Kommentera" -#: mod/photos.php:1430 src/Content/Conversation.php:615 -#: src/Object/Post.php:227 +#: mod/photos.php:1424 src/Content/Conversation.php:629 +#: src/Object/Post.php:256 msgid "Select" msgstr "Välj" -#: mod/photos.php:1431 mod/settings.php:596 src/Content/Conversation.php:616 +#: mod/photos.php:1425 mod/settings.php:350 src/Content/Conversation.php:630 #: src/Module/Admin/Users/Active.php:139 #: src/Module/Admin/Users/Blocked.php:140 src/Module/Admin/Users/Index.php:153 msgid "Delete" msgstr "Ta bort" -#: mod/photos.php:1492 src/Object/Post.php:349 +#: mod/photos.php:1486 src/Object/Post.php:379 msgid "Like" msgstr "Gilla" -#: mod/photos.php:1493 src/Object/Post.php:349 +#: mod/photos.php:1487 src/Object/Post.php:379 msgid "I like this (toggle)" msgstr "Jag gillar det här (växla)" -#: mod/photos.php:1494 src/Object/Post.php:350 +#: mod/photos.php:1488 src/Object/Post.php:380 msgid "Dislike" msgstr "Ogilla" -#: mod/photos.php:1496 src/Object/Post.php:350 +#: mod/photos.php:1490 src/Object/Post.php:380 msgid "I don't like this (toggle)" msgstr "Jag ogillar det här (växla)" -#: mod/photos.php:1518 +#: mod/photos.php:1512 msgid "Map" msgstr "Karta" -#: mod/photos.php:1581 +#: mod/photos.php:1575 msgid "View Album" msgstr "Titta i album" -#: mod/ping.php:275 -msgid "{0} wants to be your friend" -msgstr "{0} vill vara din vän" - -#: mod/ping.php:292 -msgid "{0} requested registration" -msgstr "{0} bad om registrering" - -#: mod/ping.php:305 -#, php-format -msgid "{0} and %d others requested registration" -msgstr "{0} och %d andra bad om registrering" - -#: mod/redir.php:49 mod/redir.php:102 +#: mod/redir.php:51 mod/redir.php:104 msgid "Bad Request." msgstr "Dålig begäran." -#: mod/redir.php:55 mod/redir.php:129 src/Module/Contact/Advanced.php:70 +#: mod/redir.php:57 mod/redir.php:131 src/Module/Contact/Advanced.php:70 #: src/Module/Contact/Advanced.php:109 src/Module/Contact/Contacts.php:55 #: src/Module/Contact/Conversations.php:78 #: src/Module/Contact/Conversations.php:83 @@ -1142,36 +1133,36 @@ msgstr "Dålig begäran." msgid "Contact not found." msgstr "Kontakten hittades inte." -#: mod/removeme.php:63 src/Navigation/Notifications/Repository/Notify.php:473 +#: mod/removeme.php:65 src/Navigation/Notifications/Repository/Notify.php:483 msgid "[Friendica System Notify]" msgstr "[System-avisering för Friendica]" -#: mod/removeme.php:63 +#: mod/removeme.php:65 msgid "User deleted their account" msgstr "Användaren tog bort sitt konto" -#: mod/removeme.php:64 +#: mod/removeme.php:66 msgid "" "On your Friendica node an user deleted their account. Please ensure that " "their data is removed from the backups." msgstr "" -#: mod/removeme.php:65 +#: mod/removeme.php:67 #, php-format msgid "The user id is %d" msgstr "ID för användaren är %d" -#: mod/removeme.php:99 mod/removeme.php:102 +#: mod/removeme.php:101 mod/removeme.php:104 msgid "Remove My Account" msgstr "Ta bort mitt konto" -#: mod/removeme.php:100 +#: mod/removeme.php:102 msgid "" "This will completely remove your account. Once this has been done it is not " "recoverable." msgstr "Detta kommer att ta bort kontot helt och hållet. Efter att det är gjort går det inte att återställa." -#: mod/removeme.php:101 +#: mod/removeme.php:103 msgid "Please enter your password for verification:" msgstr "Ange lösenordet igen för säkerhets skull:" @@ -1179,82 +1170,22 @@ msgstr "Ange lösenordet igen för säkerhets skull:" msgid "Resubscribing to OStatus contacts" msgstr "" -#: mod/repair_ostatus.php:46 src/Module/Debug/ActivityPubConversion.php:130 -#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:97 +#: mod/repair_ostatus.php:46 src/Module/Debug/ActivityPubConversion.php:134 +#: src/Module/Debug/Babel.php:293 src/Module/Security/TwoFactor/Verify.php:98 msgid "Error" msgid_plural "Errors" msgstr[0] "Fel" msgstr[1] "Fel" -#: mod/settings.php:128 +#: mod/settings.php:122 msgid "Failed to connect with email account using the settings provided." -msgstr "" +msgstr "Kunde inte ansluta till e-postkontot med aktuella inställningar" -#: mod/settings.php:158 -msgid "Contact CSV file upload error" -msgstr "" - -#: mod/settings.php:177 -msgid "Importing Contacts done" -msgstr "" - -#: mod/settings.php:190 -msgid "Relocate message has been send to your contacts" -msgstr "" - -#: mod/settings.php:202 -msgid "Passwords do not match." -msgstr "Lösenorden matchar inte." - -#: mod/settings.php:210 src/Console/User.php:210 -msgid "Password update failed. Please try again." -msgstr "Det blev fel när lösenordet skulle ändras. Försök igen." - -#: mod/settings.php:213 src/Console/User.php:213 -msgid "Password changed." -msgstr "Lösenordet har ändrats." - -#: mod/settings.php:216 -msgid "Password unchanged." -msgstr "Lösenordet oändrat." - -#: mod/settings.php:304 -msgid "Please use a shorter name." -msgstr "Vänligen ange ett kortare namn." - -#: mod/settings.php:307 -msgid "Name too short." -msgstr "Namnet för kort." - -#: mod/settings.php:316 -msgid "Wrong Password." -msgstr "Fel lösenord." - -#: mod/settings.php:321 -msgid "Invalid email." -msgstr "Ogiltig e-postadress." - -#: mod/settings.php:327 -msgid "Cannot change to that email." -msgstr "Kan inte byta till den e-postadressen." - -#: mod/settings.php:368 -msgid "Private forum has no privacy permissions. Using default privacy group." -msgstr "" - -#: mod/settings.php:371 -msgid "Private forum has no privacy permissions and no default privacy group." -msgstr "" - -#: mod/settings.php:390 -msgid "Settings were not updated." -msgstr "Inställningarna uppdaterades inte." - -#: mod/settings.php:431 +#: mod/settings.php:175 msgid "Connected Apps" msgstr "Anslutna appar" -#: mod/settings.php:432 src/Module/Admin/Blocklist/Contact.php:106 +#: mod/settings.php:176 src/Module/Admin/Blocklist/Contact.php:106 #: src/Module/Admin/Users/Active.php:129 #: src/Module/Admin/Users/Blocked.php:130 src/Module/Admin/Users/Create.php:71 #: src/Module/Admin/Users/Deleted.php:88 src/Module/Admin/Users/Index.php:142 @@ -1263,94 +1194,104 @@ msgstr "Anslutna appar" msgid "Name" msgstr "Namn" -#: mod/settings.php:433 src/Content/Nav.php:212 +#: mod/settings.php:177 src/Content/Nav.php:212 msgid "Home Page" msgstr "Hemsida" -#: mod/settings.php:434 src/Module/Admin/Queue.php:78 +#: mod/settings.php:178 src/Module/Admin/Queue.php:78 msgid "Created" msgstr "Skapades" -#: mod/settings.php:435 +#: mod/settings.php:179 msgid "Remove authorization" msgstr "Ta bort autentisering" -#: mod/settings.php:461 mod/settings.php:493 mod/settings.php:524 -#: mod/settings.php:598 mod/settings.php:735 -#: src/Module/Admin/Addons/Index.php:69 src/Module/Admin/Features.php:87 -#: src/Module/Admin/Logs/Settings.php:81 src/Module/Admin/Site.php:501 -#: src/Module/Admin/Themes/Index.php:113 src/Module/Admin/Tos.php:83 +#: mod/settings.php:205 mod/settings.php:237 mod/settings.php:268 +#: mod/settings.php:352 src/Module/Admin/Addons/Index.php:69 +#: src/Module/Admin/Features.php:87 src/Module/Admin/Logs/Settings.php:81 +#: src/Module/Admin/Site.php:434 src/Module/Admin/Themes/Index.php:113 +#: src/Module/Admin/Tos.php:83 src/Module/Settings/Account.php:559 #: src/Module/Settings/Delegation.php:170 src/Module/Settings/Display.php:193 msgid "Save Settings" msgstr "Spara inställningar" -#: mod/settings.php:469 +#: mod/settings.php:213 msgid "Addon Settings" -msgstr "" +msgstr "Inställningar för Tillägg" -#: mod/settings.php:470 +#: mod/settings.php:214 msgid "No Addon settings configured" -msgstr "" +msgstr "Inga inställningar för Tillägg har gjorts" -#: mod/settings.php:491 +#: mod/settings.php:235 msgid "Additional Features" msgstr "Ytterligare funktioner" -#: mod/settings.php:529 +#: mod/settings.php:273 msgid "Diaspora (Socialhome, Hubzilla)" msgstr "Diaspora (Socialhome, Hubzilla)" -#: mod/settings.php:529 mod/settings.php:530 +#: mod/settings.php:273 mod/settings.php:274 msgid "enabled" msgstr "aktiverad" -#: mod/settings.php:529 mod/settings.php:530 +#: mod/settings.php:273 mod/settings.php:274 msgid "disabled" msgstr "inaktiverad" -#: mod/settings.php:529 mod/settings.php:530 +#: mod/settings.php:273 mod/settings.php:274 #, php-format msgid "Built-in support for %s connectivity is %s" -msgstr "" +msgstr "Inbyggt stöd för %s kommunikation är %s" -#: mod/settings.php:530 +#: mod/settings.php:274 msgid "OStatus (GNU Social)" msgstr "OStatus (GNU Social)" -#: mod/settings.php:556 +#: mod/settings.php:300 msgid "Email access is disabled on this site." msgstr "E-poståtkomst är inaktiverat på den här sidan." -#: mod/settings.php:561 mod/settings.php:596 +#: mod/settings.php:305 mod/settings.php:350 msgid "None" msgstr "Ingen" -#: mod/settings.php:567 src/Module/BaseSettings.php:78 +#: mod/settings.php:311 src/Module/BaseSettings.php:78 msgid "Social Networks" msgstr "Sociala nätverk" -#: mod/settings.php:572 +#: mod/settings.php:316 msgid "General Social Media Settings" msgstr "Generella inställningar för sociala medier" -#: mod/settings.php:573 -msgid "Accept only top level posts by contacts you follow" +#: mod/settings.php:319 +msgid "Followed content scope" msgstr "" -#: mod/settings.php:573 +#: mod/settings.php:321 msgid "" -"The system does an auto completion of threads when a comment arrives. This " -"has got the side effect that you can receive posts that had been started by " -"a non-follower but had been commented by someone you follow. This setting " -"deactivates this behaviour. When activated, you strictly only will receive " -"posts from people you really do follow." +"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 "" -#: mod/settings.php:574 +#: mod/settings.php:323 +msgid "Only conversations my follows started" +msgstr "" + +#: mod/settings.php:324 +msgid "Conversations my follows started or commented on (default)" +msgstr "" + +#: mod/settings.php:325 +msgid "Any conversation my follows interacted with, including likes" +msgstr "" + +#: mod/settings.php:328 msgid "Enable Content Warning" msgstr "Aktivera innehållsvarning" -#: mod/settings.php:574 +#: mod/settings.php:328 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 " @@ -1358,627 +1299,131 @@ msgid "" " affect any other content filtering you eventually set up." msgstr "" -#: mod/settings.php:575 +#: mod/settings.php:329 msgid "Enable intelligent shortening" msgstr "Aktivera intelligent förkortning" -#: mod/settings.php:575 +#: mod/settings.php:329 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 "" -#: mod/settings.php:576 +#: mod/settings.php:330 msgid "Enable simple text shortening" msgstr "" -#: mod/settings.php:576 +#: mod/settings.php:330 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 "" -#: mod/settings.php:577 +#: mod/settings.php:331 msgid "Attach the link title" msgstr "" -#: mod/settings.php:577 +#: mod/settings.php:331 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 "" -#: mod/settings.php:578 +#: mod/settings.php:332 msgid "Your legacy ActivityPub/GNU Social account" msgstr "" -#: mod/settings.php:578 +#: mod/settings.php:332 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 "" -#: mod/settings.php:581 +#: mod/settings.php:335 msgid "Repair OStatus subscriptions" msgstr "Reparera OStatus-prenumerationer" -#: mod/settings.php:585 +#: mod/settings.php:339 msgid "Email/Mailbox Setup" msgstr "" -#: mod/settings.php:586 +#: mod/settings.php:340 msgid "" "If you wish to communicate with email contacts using this service " "(optional), please specify how to connect to your mailbox." -msgstr "" +msgstr "För att kommunicera via e-post med denna tjänst (valfritt), vänligen ange anslutningssätt till ditt e-postkonto." -#: mod/settings.php:587 +#: mod/settings.php:341 msgid "Last successful email check:" msgstr "" -#: mod/settings.php:589 +#: mod/settings.php:343 msgid "IMAP server name:" msgstr "Namn på IMAP-server:" -#: mod/settings.php:590 +#: mod/settings.php:344 msgid "IMAP port:" msgstr "Port för IMAP:" -#: mod/settings.php:591 +#: mod/settings.php:345 msgid "Security:" msgstr "Säkerhet:" -#: mod/settings.php:592 +#: mod/settings.php:346 msgid "Email login name:" msgstr "Inloggningsnamn för e-post:" -#: mod/settings.php:593 +#: mod/settings.php:347 msgid "Email password:" msgstr "Lösenord för e-post:" -#: mod/settings.php:594 +#: mod/settings.php:348 msgid "Reply-to address:" msgstr "Svara till-adress:" -#: mod/settings.php:595 +#: mod/settings.php:349 msgid "Send public posts to all email contacts:" msgstr "Skicka publika inlägg till alla e-postkontakter:" -#: mod/settings.php:596 +#: mod/settings.php:350 msgid "Action after import:" msgstr "Åtgärd efter importering:" -#: mod/settings.php:596 src/Content/Nav.php:280 +#: mod/settings.php:350 src/Content/Nav.php:280 msgid "Mark as seen" msgstr "Markera som läst" -#: mod/settings.php:596 +#: mod/settings.php:350 msgid "Move to folder" msgstr "Flytta till mapp" -#: mod/settings.php:597 +#: mod/settings.php:351 msgid "Move to folder:" msgstr "Flytta till mapp:" -#: mod/settings.php:611 -msgid "Unable to find your profile. Please contact your admin." -msgstr "Kunde inte hitta din profil. Vänligen kontakta din admin." - -#: mod/settings.php:649 src/Content/Widget.php:526 -msgid "Account Types" -msgstr "Typer av konton" - -#: mod/settings.php:650 -msgid "Personal Page Subtypes" -msgstr "" - -#: mod/settings.php:651 -msgid "Community Forum Subtypes" -msgstr "" - -#: mod/settings.php:658 src/Module/Admin/BaseUsers.php:107 -msgid "Personal Page" -msgstr "Personlig sida" - -#: mod/settings.php:659 -msgid "Account for a personal profile." -msgstr "Konto för personlig profil." - -#: mod/settings.php:662 src/Module/Admin/BaseUsers.php:108 -msgid "Organisation Page" -msgstr "Sida för organisation" - -#: mod/settings.php:663 -msgid "" -"Account for an organisation that automatically approves contact requests as " -"\"Followers\"." -msgstr "" - -#: mod/settings.php:666 src/Module/Admin/BaseUsers.php:109 -msgid "News Page" -msgstr "" - -#: mod/settings.php:667 -msgid "" -"Account for a news reflector that automatically approves contact requests as" -" \"Followers\"." -msgstr "" - -#: mod/settings.php:670 src/Module/Admin/BaseUsers.php:110 -msgid "Community Forum" -msgstr "" - -#: mod/settings.php:671 -msgid "Account for community discussions." -msgstr "" - -#: mod/settings.php:674 src/Module/Admin/BaseUsers.php:100 -msgid "Normal Account Page" -msgstr "Normal konto-sida" - -#: mod/settings.php:675 -msgid "" -"Account for a regular personal profile that requires manual approval of " -"\"Friends\" and \"Followers\"." -msgstr "" - -#: mod/settings.php:678 src/Module/Admin/BaseUsers.php:101 -msgid "Soapbox Page" -msgstr "" - -#: mod/settings.php:679 -msgid "" -"Account for a public profile that automatically approves contact requests as" -" \"Followers\"." -msgstr "" - -#: mod/settings.php:682 src/Module/Admin/BaseUsers.php:102 -msgid "Public Forum" -msgstr "Publikt forum" - -#: mod/settings.php:683 -msgid "Automatically approves all contact requests." -msgstr "Godkänner automatiskt alla kontaktförfrågningar." - -#: mod/settings.php:686 src/Module/Admin/BaseUsers.php:103 -msgid "Automatic Friend Page" -msgstr "" - -#: mod/settings.php:687 -msgid "" -"Account for a popular profile that automatically approves contact requests " -"as \"Friends\"." -msgstr "" - -#: mod/settings.php:690 -msgid "Private Forum [Experimental]" -msgstr "Privat forum [Experimentiell]" - -#: mod/settings.php:691 -msgid "Requires manual approval of contact requests." -msgstr "" - -#: mod/settings.php:702 -msgid "OpenID:" -msgstr "OpenID:" - -#: mod/settings.php:702 -msgid "(Optional) Allow this OpenID to login to this account." -msgstr "(Valfritt) Tillåt detta OpenID för att logga in till det här kontot." - -#: mod/settings.php:710 -msgid "Publish your profile in your local site directory?" -msgstr "" - -#: mod/settings.php:710 -#, 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:716 -#, php-format -msgid "" -"Your profile will also be published in the global friendica directories " -"(e.g. %s)." -msgstr "" - -#: mod/settings.php:722 -#, php-format -msgid "Your Identity Address is '%s' or '%s'." -msgstr "" - -#: mod/settings.php:733 -msgid "Account Settings" -msgstr "Kontoinställningar" - -#: mod/settings.php:741 -msgid "Password Settings" -msgstr "Lösenordsinställningar" - -#: mod/settings.php:742 src/Module/Register.php:162 -msgid "New Password:" -msgstr "Nytt lösenord" - -#: mod/settings.php:742 -msgid "" -"Allowed characters are a-z, A-Z, 0-9 and special characters except white " -"spaces, accentuated letters and colon (:)." -msgstr "" - -#: mod/settings.php:743 src/Module/Register.php:163 -msgid "Confirm:" -msgstr "Bekräfta (repetera):" - -#: mod/settings.php:743 -msgid "Leave password fields blank unless changing" -msgstr "Lämna fältet tomt om du inte vill byta lösenord" - -#: mod/settings.php:744 -msgid "Current Password:" -msgstr "Nuvarande lösenord:" - -#: mod/settings.php:744 -msgid "Your current password to confirm the changes" -msgstr "Ditt nuvarande lösenord för att bekräfta ändringar" - -#: mod/settings.php:745 -msgid "Password:" -msgstr "Lösenord:" - -#: mod/settings.php:745 -msgid "Your current password to confirm the changes of the email address" -msgstr "" - -#: mod/settings.php:748 -msgid "Delete OpenID URL" -msgstr "" - -#: mod/settings.php:750 -msgid "Basic Settings" -msgstr "Grundläggande inställningar" - -#: mod/settings.php:751 src/Module/Profile/Profile.php:144 -msgid "Full Name:" -msgstr "Fullständigt namn:" - -#: mod/settings.php:752 -msgid "Email Address:" -msgstr "E-postadress:" - -#: mod/settings.php:753 -msgid "Your Timezone:" -msgstr "Tidszon:" - -#: mod/settings.php:754 -msgid "Your Language:" -msgstr "Ditt språk:" - -#: mod/settings.php:754 -msgid "" -"Set the language we use to show you friendica interface and to send you " -"emails" -msgstr "" - -#: mod/settings.php:755 -msgid "Default Post Location:" -msgstr "Default Post Location:" - -#: mod/settings.php:756 -msgid "Use Browser Location:" -msgstr "Använd webbläsarens positionering:" - -#: mod/settings.php:758 -msgid "Security and Privacy Settings" -msgstr "Inställningar för säkerhet och sekretess" - -#: mod/settings.php:760 -msgid "Maximum Friend Requests/Day:" -msgstr "Maximalt antal kontaktförfrågningar per dygn:" - -#: mod/settings.php:760 mod/settings.php:770 -msgid "(to prevent spam abuse)" -msgstr "(för att motverka spam)" - -#: mod/settings.php:762 -msgid "Allow your profile to be searchable globally?" -msgstr "Tillåta att din profil ska vara sökbar globalt?" - -#: mod/settings.php:762 -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 "" - -#: mod/settings.php:763 -msgid "Hide your contact/friend list from viewers of your profile?" -msgstr "" - -#: mod/settings.php:763 -msgid "" -"A list of your contacts is displayed on your profile page. Activate this " -"option to disable the display of your contact list." -msgstr "" - -#: mod/settings.php:764 -msgid "Hide your profile details from anonymous viewers?" -msgstr "Göm dina profildetaljer från anonyma tittare?" - -#: mod/settings.php:764 -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:765 -msgid "Make public posts unlisted" -msgstr "" - -#: mod/settings.php:765 -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 "" - -#: mod/settings.php:766 -msgid "Make all posted pictures accessible" -msgstr "" - -#: mod/settings.php:766 -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 "" - -#: mod/settings.php:767 -msgid "Allow friends to post to your profile page?" -msgstr "Tillåta vänner att göra inlägg på din profilsida?" - -#: mod/settings.php:767 -msgid "" -"Your contacts may write posts on your profile wall. These posts will be " -"distributed to your contacts" -msgstr "" - -#: mod/settings.php:768 -msgid "Allow friends to tag your posts?" -msgstr "Tillåt vänner att tagga dina inlägg?" - -#: mod/settings.php:768 -msgid "Your contacts can add additional tags to your posts." -msgstr "Dina kontakter kan lägga till ytterligare taggar till dina inlägg." - -#: mod/settings.php:769 -msgid "Permit unknown people to send you private mail?" -msgstr "Ge okända personer tillstånd att skicka privata mail till dig?" - -#: mod/settings.php:769 -msgid "" -"Friendica network users may send you private messages even if they are not " -"in your contact list." -msgstr "" - -#: mod/settings.php:770 -msgid "Maximum private messages per day from unknown people:" -msgstr "" - -#: mod/settings.php:772 -msgid "Default Post Permissions" -msgstr "Standardåtkomst för inlägg" - -#: mod/settings.php:776 -msgid "Expiration settings" -msgstr "" - -#: mod/settings.php:777 -msgid "Automatically expire posts after this many days:" -msgstr "" - -#: mod/settings.php:777 -msgid "If empty, posts will not expire. Expired posts will be deleted" -msgstr "" - -#: mod/settings.php:778 -msgid "Expire posts" -msgstr "" - -#: mod/settings.php:778 -msgid "When activated, posts and comments will be expired." -msgstr "" - -#: mod/settings.php:779 -msgid "Expire personal notes" -msgstr "" - -#: mod/settings.php:779 -msgid "" -"When activated, the personal notes on your profile page will be expired." -msgstr "" - -#: mod/settings.php:780 -msgid "Expire starred posts" -msgstr "" - -#: mod/settings.php:780 -msgid "" -"Starring posts keeps them from being expired. That behaviour is overwritten " -"by this setting." -msgstr "" - -#: mod/settings.php:781 -msgid "Expire photos" -msgstr "" - -#: mod/settings.php:781 -msgid "When activated, photos will be expired." -msgstr "" - -#: mod/settings.php:782 -msgid "Only expire posts by others" -msgstr "" - -#: mod/settings.php:782 -msgid "" -"When activated, your own posts never expire. Then the settings above are " -"only valid for posts you received." -msgstr "" - -#: mod/settings.php:785 -msgid "Notification Settings" -msgstr "Aviseringsinställningar" - -#: mod/settings.php:786 -msgid "Send a notification email when:" -msgstr "Skicka ett aviseringsmail när:" - -#: mod/settings.php:787 -msgid "You receive an introduction" -msgstr "En kontaktförfrågan anländer" - -#: mod/settings.php:788 -msgid "Your introductions are confirmed" -msgstr "Dina förfrågningar godkänns" - -#: mod/settings.php:789 -msgid "Someone writes on your profile wall" -msgstr "Någon gör inlägg på din profilsida" - -#: mod/settings.php:790 -msgid "Someone writes a followup comment" -msgstr "Någon gör ett inlägg i samma tråd som du" - -#: mod/settings.php:791 -msgid "You receive a private message" -msgstr "Du får personliga meddelanden" - -#: mod/settings.php:792 -msgid "You receive a friend suggestion" -msgstr "Du tar emot ett vän-förslag" - -#: mod/settings.php:793 -msgid "You are tagged in a post" -msgstr "Du är taggad i ett inlägg" - -#: mod/settings.php:794 -msgid "You are poked/prodded/etc. in a post" -msgstr "" - -#: mod/settings.php:796 -msgid "Create a desktop notification when:" -msgstr "Skapa en skrivbordsavisering när:" - -#: mod/settings.php:797 -msgid "Someone liked your content" -msgstr "Någon gillade ditt innehåll" - -#: mod/settings.php:798 -msgid "Someone shared your content" -msgstr "Någon delade ditt innehåll" - -#: mod/settings.php:800 -msgid "Activate desktop notifications" -msgstr "Aktivera skrivbordsaviseringar" - -#: mod/settings.php:800 -msgid "Show desktop popup on new notifications" -msgstr "" - -#: mod/settings.php:802 -msgid "Text-only notification emails" -msgstr "" - -#: mod/settings.php:804 -msgid "Send text only notification emails, without the html part" -msgstr "" - -#: mod/settings.php:806 -msgid "Show detailled notifications" -msgstr "Visa detaljerade aviseringar" - -#: mod/settings.php:808 -msgid "" -"Per default, notifications are condensed to a single notification per item. " -"When enabled every notification is displayed." -msgstr "" - -#: mod/settings.php:810 -msgid "Show notifications of ignored contacts" -msgstr "" - -#: mod/settings.php:812 -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 "" - -#: mod/settings.php:814 -msgid "Advanced Account/Page Type Settings" -msgstr "" - -#: mod/settings.php:815 -msgid "Change the behaviour of this account for special situations" -msgstr "" - -#: mod/settings.php:818 -msgid "Import Contacts" -msgstr "Importera kontakter" - -#: mod/settings.php:819 -msgid "" -"Upload a CSV file that contains the handle of your followed accounts in the " -"first column you exported from the old account." -msgstr "" - -#: mod/settings.php:820 -msgid "Upload File" -msgstr "Ladda upp fil" - -#: mod/settings.php:822 -msgid "Relocate" -msgstr "Omlokalisera" - -#: mod/settings.php:823 -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 "Om du har flyttat den här profilen från en annan server och några av dina kontakter inte får dina uppdateringar, försök att trycka på den här knappen." - -#: mod/settings.php:824 -msgid "Resend relocate message to contacts" -msgstr "" - #: mod/suggest.php:44 msgid "" "No suggestions available. If this is a new site, please try again in 24 " "hours." msgstr "" -#: mod/suggest.php:55 src/Content/Widget.php:79 view/theme/vier/theme.php:175 +#: mod/suggest.php:55 src/Content/Widget.php:83 view/theme/vier/theme.php:175 msgid "Friend Suggestions" msgstr "Vän-förslag" -#: mod/tagger.php:78 src/Content/Item.php:346 src/Model/Item.php:2629 +#: mod/tagger.php:78 src/Content/Item.php:342 src/Model/Item.php:2728 msgid "photo" msgstr "foto" -#: mod/tagger.php:78 src/Content/Item.php:341 src/Content/Item.php:350 +#: mod/tagger.php:78 src/Content/Item.php:337 src/Content/Item.php:346 msgid "status" msgstr "status" -#: mod/tagger.php:111 src/Content/Item.php:360 +#: mod/tagger.php:111 src/Content/Item.php:356 #, php-format msgid "%1$s tagged %2$s's %3$s with %4$s" msgstr "%1$s taggade %2$ss %3$s med %4$s" @@ -1992,7 +1437,7 @@ msgid "Select a tag to remove: " msgstr "Välj vilken tagg som ska tas bort: " #: mod/tagrm.php:126 src/Module/Settings/Delegation.php:179 -#: src/Module/Settings/TwoFactor/Trusted.php:140 +#: src/Module/Settings/TwoFactor/Trusted.php:142 msgid "Remove" msgstr "Ta bort" @@ -2041,7 +1486,7 @@ msgid "" "select \"Export account\"" msgstr "För att exportera ditt konto, gå till \"Inställningar->Exportera din personliga data\" och välj \"Exportera konto\"" -#: mod/unfollow.php:65 mod/unfollow.php:135 +#: mod/unfollow.php:65 mod/unfollow.php:134 msgid "You aren't following this contact." msgstr "Du följer inte den här kontakten." @@ -2053,44 +1498,38 @@ msgstr "Avföljning stöds för närvarande inte av ditt nätverk." msgid "Disconnect/Unfollow" msgstr "Koppla ur/Avfölj" -#: mod/unfollow.php:146 -msgid "" -"Unable to unfollow this contact, please retry in a few minutes or contact " -"your administrator." -msgstr "" - -#: mod/unfollow.php:148 +#: mod/unfollow.php:143 msgid "Contact was successfully unfollowed" msgstr "Avföljningen av kontakten lyckades" -#: mod/unfollow.php:152 +#: mod/unfollow.php:146 msgid "Unable to unfollow this contact, please contact your administrator" msgstr "" -#: mod/wall_attach.php:39 mod/wall_attach.php:46 mod/wall_attach.php:77 -#: mod/wall_upload.php:53 mod/wall_upload.php:63 mod/wall_upload.php:99 -#: mod/wall_upload.php:150 mod/wall_upload.php:153 +#: mod/wall_attach.php:40 mod/wall_attach.php:46 mod/wall_attach.php:75 +#: mod/wall_upload.php:54 mod/wall_upload.php:63 mod/wall_upload.php:97 +#: mod/wall_upload.php:148 mod/wall_upload.php:150 msgid "Invalid request." msgstr "Ogiltig förfrågning." -#: mod/wall_attach.php:95 +#: mod/wall_attach.php:93 msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" msgstr "" -#: mod/wall_attach.php:95 +#: mod/wall_attach.php:93 msgid "Or - did you try to upload an empty file?" msgstr "Eller - provade du att ladda upp en tom fil?" -#: mod/wall_attach.php:106 +#: mod/wall_attach.php:104 #, php-format msgid "File exceeds size limit of %s" -msgstr "" +msgstr "Filen överstiger maxstorleken %s" -#: mod/wall_attach.php:121 +#: mod/wall_attach.php:119 msgid "File upload failed." msgstr "Uppladdning av filen misslyckades." -#: mod/wall_upload.php:221 src/Model/Photo.php:1049 +#: mod/wall_upload.php:218 src/Model/Photo.php:1085 msgid "Wall Photos" msgstr "Loggbilder" @@ -2114,80 +1553,80 @@ msgid "" "your site allow private mail from unknown senders." msgstr "" -#: src/App.php:463 +#: src/App.php:473 msgid "No system theme config value set." msgstr "" -#: src/App.php:583 +#: src/App.php:594 msgid "Apologies but the website is unavailable at the moment." msgstr "Ursäkta, men hemsidan är inte tillgänglig för tillfället. " -#: src/App/Page.php:250 +#: src/App/Page.php:276 msgid "Delete this item?" msgstr "Ta bort?" -#: src/App/Page.php:251 +#: src/App/Page.php:277 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:321 +#: src/App/Page.php:347 msgid "toggle mobile" msgstr "växla mobil" -#: src/App/Router.php:275 +#: src/App/Router.php:282 #, php-format msgid "Method not allowed for this module. Allowed method(s): %s" msgstr "" -#: src/App/Router.php:277 src/Module/HTTPException/PageNotFound.php:33 +#: src/App/Router.php:284 src/Module/HTTPException/PageNotFound.php:49 msgid "Page not found." msgstr "Sidan hittades inte." -#: src/App/Router.php:305 +#: src/App/Router.php:312 msgid "You must be logged in to use addons. " msgstr "Du måste vara inloggad för att använda insticksprogram." -#: src/BaseModule.php:377 +#: src/BaseModule.php:392 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:404 +#: src/BaseModule.php:419 msgid "All contacts" msgstr "Alla kontakter" -#: src/BaseModule.php:409 src/Content/Widget.php:231 src/Core/ACL.php:193 -#: src/Module/Contact.php:367 src/Module/PermissionTooltip.php:98 -#: src/Module/PermissionTooltip.php:120 +#: src/BaseModule.php:424 src/Content/Widget.php:235 src/Core/ACL.php:194 +#: src/Module/Contact.php:367 src/Module/PermissionTooltip.php:122 +#: src/Module/PermissionTooltip.php:144 msgid "Followers" msgstr "Följare" -#: src/BaseModule.php:414 src/Content/Widget.php:232 +#: src/BaseModule.php:429 src/Content/Widget.php:236 #: src/Module/Contact.php:368 msgid "Following" msgstr "Följer" -#: src/BaseModule.php:419 src/Content/Widget.php:233 +#: src/BaseModule.php:434 src/Content/Widget.php:237 #: src/Module/Contact.php:369 msgid "Mutual friends" msgstr "Gemensamma vänner" -#: src/BaseModule.php:427 +#: src/BaseModule.php:442 msgid "Common" msgstr "Vanlig" -#: src/Console/Addon.php:177 src/Console/Addon.php:202 +#: src/Console/Addon.php:175 src/Console/Addon.php:199 msgid "Addon not found" msgstr "Insticksprogrammet hittades inte" -#: src/Console/Addon.php:181 +#: src/Console/Addon.php:179 msgid "Addon already enabled" msgstr "Insticksprogrammet är redan aktiverat" -#: src/Console/Addon.php:206 +#: src/Console/Addon.php:203 msgid "Addon already disabled" msgstr "Insticksprogrammet är redan inaktiverat" @@ -2211,6 +1650,95 @@ msgstr "" msgid "The contact has been blocked from the node" msgstr "" +#: src/Console/MergeContacts.php:74 +#, php-format +msgid "%d %s, %d duplicates." +msgstr "" + +#: src/Console/MergeContacts.php:77 +#, php-format +msgid "uri-id is empty for contact %s." +msgstr "" + +#: src/Console/MergeContacts.php:90 +#, php-format +msgid "No valid first countact found for uri-id %d." +msgstr "" + +#: src/Console/MergeContacts.php:101 +#, php-format +msgid "Wrong duplicate found for uri-id %d in %d (url: %s != %s)." +msgstr "" + +#: src/Console/MergeContacts.php:105 +#, php-format +msgid "Wrong duplicate found for uri-id %d in %d (nurl: %s != %s)." +msgstr "" + +#: src/Console/MergeContacts.php:141 +#, php-format +msgid "Deletion of id %d failed" +msgstr "" + +#: src/Console/MergeContacts.php:143 +#, php-format +msgid "Deletion of id %d was successful" +msgstr "" + +#: src/Console/MergeContacts.php:149 +#, php-format +msgid "Updating \"%s\" in \"%s\" from %d to %d" +msgstr "" + +#: src/Console/MergeContacts.php:151 +msgid " - found" +msgstr "- hittad" + +#: src/Console/MergeContacts.php:158 +msgid " - failed" +msgstr "- misslyckad" + +#: src/Console/MergeContacts.php:160 +msgid " - success" +msgstr "- framgång" + +#: src/Console/MergeContacts.php:164 +msgid " - deleted" +msgstr "- borttagen" + +#: src/Console/MergeContacts.php:167 +msgid " - done" +msgstr "- klar" + +#: 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." @@ -2240,6 +1768,14 @@ msgstr "Ange smeknamn för användaren:" msgid "Enter new password: " msgstr "Ange nytt lösenord:" +#: src/Console/User.php:210 src/Module/Settings/Account.php:74 +msgid "Password update failed. Please try again." +msgstr "Det blev fel när lösenordet skulle ändras. Försök igen." + +#: src/Console/User.php:213 src/Module/Settings/Account.php:77 +msgid "Password changed." +msgstr "Lösenordet har ändrats." + #: src/Console/User.php:237 msgid "Enter user name: " msgstr "Ange användarnamn:" @@ -2313,78 +1849,78 @@ msgstr "Varje vecka" msgid "Monthly" msgstr "Varje månad" -#: src/Content/ContactSelector.php:123 +#: src/Content/ContactSelector.php:126 msgid "DFRN" msgstr "DFRN" -#: src/Content/ContactSelector.php:124 +#: src/Content/ContactSelector.php:127 msgid "OStatus" msgstr "OStatus" -#: src/Content/ContactSelector.php:125 +#: src/Content/ContactSelector.php:128 msgid "RSS/Atom" msgstr "RSS/Atom" -#: src/Content/ContactSelector.php:126 src/Module/Admin/Users/Active.php:129 +#: src/Content/ContactSelector.php:129 src/Module/Admin/Users/Active.php:129 #: src/Module/Admin/Users/Blocked.php:130 src/Module/Admin/Users/Create.php:73 #: src/Module/Admin/Users/Deleted.php:88 src/Module/Admin/Users/Index.php:142 #: src/Module/Admin/Users/Index.php:162 src/Module/Admin/Users/Pending.php:104 msgid "Email" msgstr "E-postadress" -#: src/Content/ContactSelector.php:127 src/Module/Debug/Babel.php:307 +#: src/Content/ContactSelector.php:130 src/Module/Debug/Babel.php:307 msgid "Diaspora" msgstr "Diaspora" -#: src/Content/ContactSelector.php:128 +#: src/Content/ContactSelector.php:131 msgid "Zot!" msgstr "Zot!" -#: src/Content/ContactSelector.php:129 +#: src/Content/ContactSelector.php:132 msgid "LinkedIn" msgstr "LinkedIn" -#: src/Content/ContactSelector.php:130 +#: src/Content/ContactSelector.php:133 msgid "XMPP/IM" msgstr "XMPP/IM" -#: src/Content/ContactSelector.php:131 +#: src/Content/ContactSelector.php:134 msgid "MySpace" msgstr "MySpace" -#: src/Content/ContactSelector.php:132 +#: src/Content/ContactSelector.php:135 msgid "Google+" msgstr "Google+" -#: src/Content/ContactSelector.php:133 +#: src/Content/ContactSelector.php:136 msgid "pump.io" msgstr "pump.io" -#: src/Content/ContactSelector.php:134 +#: src/Content/ContactSelector.php:137 msgid "Twitter" msgstr "Twitter" -#: src/Content/ContactSelector.php:135 +#: src/Content/ContactSelector.php:138 msgid "Discourse" msgstr "Discourse" -#: src/Content/ContactSelector.php:136 +#: src/Content/ContactSelector.php:139 msgid "Diaspora Connector" msgstr "" -#: src/Content/ContactSelector.php:137 +#: src/Content/ContactSelector.php:140 msgid "GNU Social Connector" msgstr "" -#: src/Content/ContactSelector.php:138 +#: src/Content/ContactSelector.php:141 msgid "ActivityPub" msgstr "ActivityPub" -#: src/Content/ContactSelector.php:139 +#: src/Content/ContactSelector.php:142 msgid "pnut" msgstr "pnut" -#: src/Content/ContactSelector.php:175 +#: src/Content/ContactSelector.php:178 #, php-format msgid "%s (via %s)" msgstr "" @@ -2415,7 +1951,7 @@ msgid "%s attends maybe." msgstr "%s deltar kanske." #: src/Content/Conversation.php:222 src/Content/Conversation.php:260 -#: src/Content/Conversation.php:849 +#: src/Content/Conversation.php:873 #, php-format msgid "%s reshared this." msgstr "" @@ -2488,8 +2024,8 @@ msgstr "" msgid "Visible to everybody" msgstr "Synlig för alla" -#: src/Content/Conversation.php:308 src/Module/Item/Compose.php:159 -#: src/Object/Post.php:975 +#: src/Content/Conversation.php:308 src/Module/Item/Compose.php:171 +#: src/Object/Post.php:1002 msgid "Please enter a image/video/audio/webpage URL:" msgstr "Vänligen fyll i URL till en bild/video/ljudklipp/hemsida:" @@ -2509,109 +2045,117 @@ msgstr "Var är du just nu?" msgid "Delete item(s)?" msgstr "Ta bort?" -#: src/Content/Conversation.php:322 +#: src/Content/Conversation.php:324 src/Module/Item/Compose.php:143 +msgid "Created at" +msgstr "" + +#: src/Content/Conversation.php:334 msgid "New Post" msgstr "Nytt inlägg" -#: src/Content/Conversation.php:325 src/Object/Post.php:481 +#: src/Content/Conversation.php:337 msgid "Share" msgstr "Publicera" -#: src/Content/Conversation.php:336 src/Module/Item/Compose.php:156 -#: src/Object/Post.php:972 +#: src/Content/Conversation.php:348 src/Module/Item/Compose.php:168 +#: src/Object/Post.php:999 msgid "Image" msgstr "Bild" -#: src/Content/Conversation.php:339 +#: src/Content/Conversation.php:351 msgid "Video" msgstr "Video" -#: src/Content/Conversation.php:352 src/Module/Item/Compose.php:172 +#: src/Content/Conversation.php:364 src/Module/Item/Compose.php:184 msgid "Scheduled at" msgstr "Schemalades vid" -#: src/Content/Conversation.php:651 src/Object/Post.php:454 -#: src/Object/Post.php:455 +#: src/Content/Conversation.php:657 src/Object/Post.php:244 +msgid "Pinned item" +msgstr "" + +#: src/Content/Conversation.php:673 src/Object/Post.php:486 +#: src/Object/Post.php:487 #, php-format msgid "View %s's profile @ %s" msgstr "Visa profilen som tillhör %s @ %s" -#: src/Content/Conversation.php:664 src/Object/Post.php:442 +#: src/Content/Conversation.php:686 src/Object/Post.php:474 msgid "Categories:" msgstr "Kategorier:" -#: src/Content/Conversation.php:665 src/Object/Post.php:443 +#: src/Content/Conversation.php:687 src/Object/Post.php:475 msgid "Filed under:" msgstr "Sparad under:" -#: src/Content/Conversation.php:673 src/Object/Post.php:468 +#: src/Content/Conversation.php:695 src/Object/Post.php:500 #, php-format msgid "%s from %s" msgstr "%s från %s" -#: src/Content/Conversation.php:688 +#: src/Content/Conversation.php:711 msgid "View in context" msgstr "Visa i sitt sammanhang" -#: src/Content/Conversation.php:753 +#: src/Content/Conversation.php:776 msgid "remove" msgstr "ta bort" -#: src/Content/Conversation.php:757 +#: src/Content/Conversation.php:780 msgid "Delete Selected Items" msgstr "Ta bort valda föremål" -#: src/Content/Conversation.php:821 src/Content/Conversation.php:824 -#: src/Content/Conversation.php:827 src/Content/Conversation.php:830 +#: src/Content/Conversation.php:845 src/Content/Conversation.php:848 +#: src/Content/Conversation.php:851 src/Content/Conversation.php:854 #, php-format msgid "You had been addressed (%s)." msgstr "" -#: src/Content/Conversation.php:833 +#: src/Content/Conversation.php:857 #, php-format msgid "You are following %s." msgstr "Du följer %s." -#: src/Content/Conversation.php:836 +#: src/Content/Conversation.php:860 msgid "Tagged" msgstr "Taggad" -#: src/Content/Conversation.php:851 +#: src/Content/Conversation.php:875 msgid "Reshared" msgstr "Delad igen" -#: src/Content/Conversation.php:851 +#: src/Content/Conversation.php:875 #, php-format msgid "Reshared by %s <%s>" msgstr "Delad igen av %s <%s>" -#: src/Content/Conversation.php:854 +#: src/Content/Conversation.php:878 #, php-format msgid "%s is participating in this thread." msgstr "%s deltar i den här tråden." -#: src/Content/Conversation.php:857 +#: src/Content/Conversation.php:881 msgid "Stored" msgstr "Lagrad" -#: src/Content/Conversation.php:860 +#: src/Content/Conversation.php:884 msgid "Global" msgstr "Global" -#: src/Content/Conversation.php:863 +#: src/Content/Conversation.php:887 msgid "Relayed" msgstr "Fördröjd" -#: src/Content/Conversation.php:863 +#: src/Content/Conversation.php:887 #, php-format msgid "Relayed by %s <%s>" msgstr "Fördröjdes av %s <%s>" -#: src/Content/Conversation.php:866 +#: src/Content/Conversation.php:890 msgid "Fetched" msgstr "Hämtad" -#: src/Content/Conversation.php:866 +#: src/Content/Conversation.php:890 #, php-format msgid "Fetched because of %s <%s>" msgstr "Hämtades på grund av %s <%s>" @@ -2663,125 +2207,137 @@ msgid "" "mentioned in replies." msgstr "" -#: src/Content/Feature.php:111 +#: 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 "" -#: src/Content/Feature.php:112 +#: src/Content/Feature.php:113 msgid "Post Categories" msgstr "" -#: src/Content/Feature.php:112 +#: src/Content/Feature.php:113 msgid "Add categories to your posts" msgstr "Lägg till kategorier till dina inlägg" -#: src/Content/Feature.php:117 +#: src/Content/Feature.php:118 msgid "Advanced Profile Settings" msgstr "Avancerade profil-inställningar" -#: src/Content/Feature.php:118 +#: src/Content/Feature.php:119 msgid "List Forums" msgstr "Lista forum" -#: src/Content/Feature.php:118 +#: src/Content/Feature.php:119 msgid "Show visitors public community forums at the Advanced Profile Page" msgstr "" -#: src/Content/Feature.php:119 +#: src/Content/Feature.php:120 msgid "Tag Cloud" msgstr "Taggmoln" -#: src/Content/Feature.php:119 +#: src/Content/Feature.php:120 msgid "Provide a personal tag cloud on your profile page" msgstr "" -#: src/Content/Feature.php:120 +#: src/Content/Feature.php:121 msgid "Display Membership Date" msgstr "Visa datum för medlemskap" -#: src/Content/Feature.php:120 +#: src/Content/Feature.php:121 msgid "Display membership date in profile" msgstr "Visa datum för medlemskapet i profilen" -#: src/Content/ForumManager.php:145 src/Content/Nav.php:239 -#: src/Content/Text/HTML.php:896 src/Content/Widget.php:523 +#: src/Content/ForumManager.php:151 src/Content/Nav.php:239 +#: src/Content/Text/HTML.php:903 src/Content/Widget.php:524 msgid "Forums" msgstr "Forum" -#: src/Content/ForumManager.php:147 +#: src/Content/ForumManager.php:153 msgid "External link to forum" msgstr "Extern länk till forum" -#: src/Content/ForumManager.php:150 src/Content/Widget.php:502 +#: src/Content/ForumManager.php:156 src/Content/Widget.php:503 msgid "show less" msgstr "visa mindre" -#: src/Content/ForumManager.php:151 src/Content/Widget.php:404 -#: src/Content/Widget.php:503 +#: src/Content/ForumManager.php:157 src/Content/Widget.php:405 +#: src/Content/Widget.php:504 msgid "show more" msgstr "visa mer" -#: src/Content/Item.php:305 +#: src/Content/Item.php:301 #, php-format msgid "%1$s poked %2$s" msgstr "%1$s puffade %2$s" -#: src/Content/Item.php:338 src/Model/Item.php:2627 +#: src/Content/Item.php:334 src/Model/Item.php:2726 msgid "event" msgstr "händelse" -#: src/Content/Item.php:442 view/theme/frio/theme.php:254 +#: src/Content/Item.php:422 view/theme/frio/theme.php:254 msgid "Follow Thread" msgstr "Följ tråd" -#: src/Content/Item.php:443 src/Model/Contact.php:1061 +#: src/Content/Item.php:423 src/Model/Contact.php:1108 msgid "View Status" msgstr "Visa status" -#: src/Content/Item.php:444 src/Content/Item.php:466 src/Model/Contact.php:995 -#: src/Model/Contact.php:1053 src/Model/Contact.php:1062 -#: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:225 +#: src/Content/Item.php:424 src/Content/Item.php:446 +#: src/Model/Contact.php:1042 src/Model/Contact.php:1100 +#: src/Model/Contact.php:1109 src/Module/Directory.php:158 +#: src/Module/Settings/Profile/Index.php:225 msgid "View Profile" msgstr "Visa profil" -#: src/Content/Item.php:445 src/Model/Contact.php:1063 +#: src/Content/Item.php:425 src/Model/Contact.php:1110 msgid "View Photos" msgstr "Visa foton" -#: src/Content/Item.php:446 src/Model/Contact.php:1054 -#: src/Model/Contact.php:1064 +#: src/Content/Item.php:426 src/Model/Contact.php:1101 +#: src/Model/Contact.php:1111 msgid "Network Posts" msgstr "Nätverksinlägg" -#: src/Content/Item.php:447 src/Model/Contact.php:1055 -#: src/Model/Contact.php:1065 +#: src/Content/Item.php:427 src/Model/Contact.php:1102 +#: src/Model/Contact.php:1112 msgid "View Contact" msgstr "Visa kontakt" -#: src/Content/Item.php:448 src/Model/Contact.php:1066 +#: src/Content/Item.php:428 src/Model/Contact.php:1113 msgid "Send PM" msgstr "Skicka privat meddelande" -#: src/Content/Item.php:449 src/Module/Admin/Blocklist/Contact.php:100 +#: src/Content/Item.php:429 src/Module/Admin/Blocklist/Contact.php:100 #: src/Module/Admin/Users/Active.php:140 src/Module/Admin/Users/Index.php:154 #: src/Module/Contact.php:398 src/Module/Contact/Profile.php:348 #: src/Module/Contact/Profile.php:449 msgid "Block" msgstr "Blockera" -#: src/Content/Item.php:450 src/Module/Contact.php:399 +#: src/Content/Item.php:430 src/Module/Contact.php:399 #: src/Module/Contact/Profile.php:349 src/Module/Contact/Profile.php:457 #: src/Module/Notifications/Introductions.php:132 #: src/Module/Notifications/Introductions.php:204 -#: src/Module/Notifications/Notification.php:61 +#: src/Module/Notifications/Notification.php:88 msgid "Ignore" msgstr "Ignorera" -#: src/Content/Item.php:454 src/Object/Post.php:429 +#: src/Content/Item.php:434 src/Object/Post.php:455 msgid "Languages" msgstr "Språk" -#: src/Content/Item.php:458 src/Model/Contact.php:1067 +#: src/Content/Item.php:438 src/Model/Contact.php:1114 msgid "Poke" msgstr "Peta" @@ -2797,7 +2353,7 @@ msgstr "Gå tillbaka" msgid "Clear notifications" msgstr "Rensa aviseringar" -#: src/Content/Nav.php:96 src/Content/Text/HTML.php:883 +#: src/Content/Nav.php:96 src/Content/Text/HTML.php:890 msgid "@name, !forum, #tags, content" msgstr "@namn, !forum, #taggar, innehåll" @@ -2820,7 +2376,7 @@ msgstr "Logga in" #: src/Content/Nav.php:190 src/Module/BaseProfile.php:56 #: src/Module/Contact.php:433 src/Module/Contact/Profile.php:380 -#: src/Module/Settings/TwoFactor/Index.php:112 view/theme/frio/theme.php:225 +#: src/Module/Settings/TwoFactor/Index.php:115 view/theme/frio/theme.php:225 msgid "Status" msgstr "Status" @@ -2881,7 +2437,7 @@ msgstr "Skapa ett konto" #: src/Content/Nav.php:222 src/Module/Help.php:67 #: src/Module/Settings/TwoFactor/AppSpecific.php:127 -#: src/Module/Settings/TwoFactor/Index.php:111 +#: src/Module/Settings/TwoFactor/Index.php:114 #: src/Module/Settings/TwoFactor/Recovery.php:105 #: src/Module/Settings/TwoFactor/Verify.php:145 view/theme/vier/theme.php:217 msgid "Help" @@ -2899,8 +2455,8 @@ msgstr "Apps" msgid "Addon applications, utilities, games" msgstr "" -#: src/Content/Nav.php:230 src/Content/Text/HTML.php:881 -#: src/Module/Admin/Logs/View.php:86 src/Module/Search/Index.php:96 +#: src/Content/Nav.php:230 src/Content/Text/HTML.php:888 +#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:112 msgid "Search" msgstr "Sök" @@ -2908,17 +2464,17 @@ msgstr "Sök" msgid "Search site content" msgstr "Sök innehåll på sidan" -#: src/Content/Nav.php:233 src/Content/Text/HTML.php:890 +#: src/Content/Nav.php:233 src/Content/Text/HTML.php:897 msgid "Full Text" msgstr "Fullständig text" -#: src/Content/Nav.php:234 src/Content/Text/HTML.php:891 +#: src/Content/Nav.php:234 src/Content/Text/HTML.php:898 #: src/Content/Widget/TagCloud.php:68 msgid "Tags" msgstr "Taggar" #: src/Content/Nav.php:235 src/Content/Nav.php:294 -#: src/Content/Text/HTML.php:892 src/Module/BaseProfile.php:125 +#: src/Content/Text/HTML.php:899 src/Module/BaseProfile.php:125 #: src/Module/BaseProfile.php:128 src/Module/Contact.php:370 #: src/Module/Contact.php:464 view/theme/frio/theme.php:236 msgid "Contacts" @@ -2945,7 +2501,7 @@ msgstr "Medlemskatalog" msgid "People directory" msgstr "" -#: src/Content/Nav.php:263 src/Module/BaseAdmin.php:85 +#: src/Content/Nav.php:263 src/Module/BaseAdmin.php:88 msgid "Information" msgstr "Information" @@ -2954,7 +2510,7 @@ msgid "Information about this friendica instance" msgstr "Information om den här friendica-instansen" #: src/Content/Nav.php:266 src/Module/Admin/Tos.php:76 -#: src/Module/BaseAdmin.php:96 src/Module/Register.php:176 +#: src/Module/BaseAdmin.php:99 src/Module/Register.php:176 #: src/Module/Tos.php:87 msgid "Terms of Service" msgstr "Villkor för användning" @@ -3026,7 +2582,7 @@ msgstr "Kontoinställningar" msgid "Manage/edit friends and contacts" msgstr "Hantera/redigera vänner och kontakter" -#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:126 +#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:129 msgid "Admin" msgstr "Administratör" @@ -3042,11 +2598,11 @@ msgstr "Navigering" msgid "Site map" msgstr "Karta över webbplatsen" -#: src/Content/OEmbed.php:298 +#: src/Content/OEmbed.php:299 msgid "Embedding disabled" msgstr "Funktionen bädda in är avstängd" -#: src/Content/OEmbed.php:416 +#: src/Content/OEmbed.php:417 msgid "Embedded content" msgstr "Inbäddat innehåll" @@ -3066,177 +2622,181 @@ msgstr "nästa" msgid "last" msgstr "sista" -#: src/Content/Text/BBCode.php:987 src/Content/Text/BBCode.php:1781 -#: src/Content/Text/BBCode.php:1782 +#: src/Content/Text/BBCode.php:990 src/Content/Text/BBCode.php:1808 +#: src/Content/Text/BBCode.php:1809 msgid "Image/photo" msgstr "Bild/foto" -#: src/Content/Text/BBCode.php:1160 +#: src/Content/Text/BBCode.php:1163 #, php-format msgid "%2$s %3$s" msgstr "%2$s %3$s" -#: src/Content/Text/BBCode.php:1185 src/Model/Item.php:3158 -#: src/Model/Item.php:3164 src/Model/Item.php:3165 +#: src/Content/Text/BBCode.php:1188 src/Model/Item.php:3301 +#: src/Model/Item.php:3307 src/Model/Item.php:3308 msgid "Link to source" msgstr "Länk till källa" -#: src/Content/Text/BBCode.php:1699 src/Content/Text/HTML.php:933 +#: src/Content/Text/BBCode.php:1726 src/Content/Text/HTML.php:940 msgid "Click to open/close" msgstr "Klicka för att öppna/stänga" -#: src/Content/Text/BBCode.php:1730 +#: src/Content/Text/BBCode.php:1757 msgid "$1 wrote:" msgstr "$1 skrev:" -#: src/Content/Text/BBCode.php:1786 src/Content/Text/BBCode.php:1787 +#: src/Content/Text/BBCode.php:1813 src/Content/Text/BBCode.php:1814 msgid "Encrypted content" msgstr "Krypterat innehåll" -#: src/Content/Text/BBCode.php:2002 +#: src/Content/Text/BBCode.php:2032 msgid "Invalid source protocol" msgstr "Ogiltigt källprotokoll" -#: src/Content/Text/BBCode.php:2017 +#: src/Content/Text/BBCode.php:2047 msgid "Invalid link protocol" -msgstr "Ogiltigt källprotokoll" +msgstr "Ogiltigt länkprotokoll" -#: src/Content/Text/HTML.php:797 +#: src/Content/Text/HTML.php:805 msgid "Loading more entries..." msgstr "Laddar fler poster..." -#: src/Content/Text/HTML.php:798 +#: src/Content/Text/HTML.php:806 msgid "The end" msgstr "Slut" -#: src/Content/Text/HTML.php:875 src/Content/Widget/VCard.php:103 -#: src/Model/Profile.php:454 +#: src/Content/Text/HTML.php:882 src/Content/Widget/VCard.php:109 +#: src/Model/Profile.php:457 msgid "Follow" msgstr "Följ" -#: src/Content/Widget.php:49 +#: src/Content/Widget.php:51 msgid "Add New Contact" msgstr "Lägg till kontakt" -#: src/Content/Widget.php:50 +#: src/Content/Widget.php:52 msgid "Enter address or web location" msgstr "Fyll i adress eller plats på internet" -#: src/Content/Widget.php:51 +#: src/Content/Widget.php:53 msgid "Example: bob@example.com, http://example.com/barbara" msgstr "Exempel: adam@exempel.com, http://exempel.com/bertil" -#: src/Content/Widget.php:53 +#: src/Content/Widget.php:55 msgid "Connect" msgstr "Skicka kontaktförfrågan" -#: src/Content/Widget.php:68 +#: src/Content/Widget.php:72 #, php-format msgid "%d invitation available" msgid_plural "%d invitations available" msgstr[0] "%d inbjudning tillgänglig" msgstr[1] "%d inbjudningar tillgängliga" -#: src/Content/Widget.php:74 view/theme/vier/theme.php:170 +#: src/Content/Widget.php:78 view/theme/vier/theme.php:170 msgid "Find People" msgstr "Hitta personer" -#: src/Content/Widget.php:75 view/theme/vier/theme.php:171 +#: src/Content/Widget.php:79 view/theme/vier/theme.php:171 msgid "Enter name or interest" msgstr "Ange namn eller intresse" -#: src/Content/Widget.php:77 view/theme/vier/theme.php:173 +#: src/Content/Widget.php:81 view/theme/vier/theme.php:173 msgid "Examples: Robert Morgenstein, Fishing" msgstr "Exempel: Robert Morgenstein, Fiskning" -#: src/Content/Widget.php:78 src/Module/Contact.php:391 -#: src/Module/Directory.php:96 view/theme/vier/theme.php:174 +#: src/Content/Widget.php:82 src/Module/Contact.php:391 +#: src/Module/Directory.php:97 view/theme/vier/theme.php:174 msgid "Find" msgstr "Sök" -#: src/Content/Widget.php:80 view/theme/vier/theme.php:176 +#: src/Content/Widget.php:84 view/theme/vier/theme.php:176 msgid "Similar Interests" msgstr "Liknande intressen" -#: src/Content/Widget.php:81 view/theme/vier/theme.php:177 +#: src/Content/Widget.php:85 view/theme/vier/theme.php:177 msgid "Random Profile" msgstr "Slumpmässig profil" -#: src/Content/Widget.php:82 view/theme/vier/theme.php:178 +#: src/Content/Widget.php:86 view/theme/vier/theme.php:178 msgid "Invite Friends" msgstr "Bjud in folk du känner" -#: src/Content/Widget.php:83 src/Module/Directory.php:88 +#: src/Content/Widget.php:87 src/Module/Directory.php:89 #: view/theme/vier/theme.php:179 msgid "Global Directory" msgstr "Medlemskatalog för flera sajter (global)" -#: src/Content/Widget.php:85 view/theme/vier/theme.php:181 +#: src/Content/Widget.php:89 view/theme/vier/theme.php:181 msgid "Local Directory" msgstr "Lokal-mapp" -#: src/Content/Widget.php:207 src/Model/Group.php:507 +#: src/Content/Widget.php:211 src/Model/Group.php:583 #: src/Module/Contact.php:354 src/Module/Welcome.php:76 msgid "Groups" msgstr "Grupper" -#: src/Content/Widget.php:209 +#: src/Content/Widget.php:213 msgid "Everyone" msgstr "Alla" -#: src/Content/Widget.php:238 +#: src/Content/Widget.php:242 msgid "Relationships" msgstr "Relationer" -#: src/Content/Widget.php:240 src/Module/Contact.php:306 +#: src/Content/Widget.php:244 src/Module/Contact.php:306 #: src/Module/Group.php:293 msgid "All Contacts" msgstr "Alla kontakter" -#: src/Content/Widget.php:279 +#: src/Content/Widget.php:283 msgid "Protocols" -msgstr "Protokoller" +msgstr "Protokoll" -#: src/Content/Widget.php:281 +#: src/Content/Widget.php:285 msgid "All Protocols" -msgstr "Alla protokoller" +msgstr "Alla protokoll" -#: src/Content/Widget.php:309 +#: src/Content/Widget.php:313 msgid "Saved Folders" msgstr "Sparade mappar" -#: src/Content/Widget.php:311 src/Content/Widget.php:345 +#: src/Content/Widget.php:315 src/Content/Widget.php:346 msgid "Everything" msgstr "Allting" -#: src/Content/Widget.php:343 +#: src/Content/Widget.php:344 msgid "Categories" msgstr "Kategorier" -#: src/Content/Widget.php:400 +#: src/Content/Widget.php:401 #, php-format msgid "%d contact in common" msgid_plural "%d contacts in common" msgstr[0] "%d gemensam kontakt" msgstr[1] "%d gemensamma kontakter" -#: src/Content/Widget.php:496 +#: src/Content/Widget.php:497 msgid "Archives" msgstr "Arkiv" -#: src/Content/Widget.php:520 +#: src/Content/Widget.php:521 msgid "Persons" msgstr "Personer" -#: src/Content/Widget.php:521 +#: src/Content/Widget.php:522 msgid "Organisations" msgstr "Organisationer" -#: src/Content/Widget.php:522 src/Model/Contact.php:1494 +#: src/Content/Widget.php:523 src/Model/Contact.php:1538 msgid "News" msgstr "Nyheter" -#: src/Content/Widget.php:527 src/Module/Admin/BaseUsers.php:51 +#: src/Content/Widget.php:527 src/Module/Settings/Account.php:455 +msgid "Account Types" +msgstr "Typer av konton" + +#: src/Content/Widget.php:528 src/Module/Admin/BaseUsers.php:51 msgid "All" msgstr "Alla" @@ -3286,68 +2846,69 @@ msgstr[1] "Trendande taggar (de senaste %d timmarna)" msgid "More Trending Tags" msgstr "Fler trendande taggar" -#: src/Content/Widget/VCard.php:96 src/Model/Profile.php:373 +#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:376 #: src/Module/Contact/Profile.php:371 src/Module/Profile/Profile.php:176 msgid "XMPP:" msgstr "XMPP:" -#: src/Content/Widget/VCard.php:97 src/Model/Profile.php:374 +#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:377 #: src/Module/Contact/Profile.php:373 src/Module/Profile/Profile.php:180 msgid "Matrix:" msgstr "Matrix:" -#: src/Content/Widget/VCard.php:101 src/Model/Profile.php:466 +#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:469 #: src/Module/Notifications/Introductions.php:199 msgid "Network:" msgstr "Nätverk:" -#: src/Content/Widget/VCard.php:105 src/Model/Profile.php:456 +#: src/Content/Widget/VCard.php:111 src/Model/Profile.php:459 msgid "Unfollow" msgstr "Avfölj" -#: src/Core/ACL.php:164 src/Module/Profile/Profile.php:242 +#: src/Core/ACL.php:165 src/Module/Profile/Profile.php:242 msgid "Yourself" msgstr "Du själv" -#: src/Core/ACL.php:200 src/Module/PermissionTooltip.php:104 -#: src/Module/PermissionTooltip.php:126 +#: src/Core/ACL.php:201 src/Module/PermissionTooltip.php:128 +#: src/Module/PermissionTooltip.php:150 msgid "Mutuals" msgstr "Ömsesidiga" -#: src/Core/ACL.php:292 +#: src/Core/ACL.php:293 msgid "Post to Email" msgstr "" -#: src/Core/ACL.php:319 +#: src/Core/ACL.php:320 src/Module/PermissionTooltip.php:85 +#: src/Module/PermissionTooltip.php:197 msgid "Public" msgstr "Publik" -#: src/Core/ACL.php:320 +#: src/Core/ACL.php:321 msgid "" "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/Core/ACL.php:321 +#: src/Core/ACL.php:322 src/Module/PermissionTooltip.php:93 msgid "Limited/Private" msgstr "Begränsad/Privat" -#: src/Core/ACL.php:322 +#: src/Core/ACL.php:323 msgid "" "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/Core/ACL.php:323 +#: src/Core/ACL.php:324 msgid "Show to:" msgstr "Visa till:" -#: src/Core/ACL.php:324 +#: src/Core/ACL.php:325 msgid "Except to:" msgstr "Förutom till:" -#: src/Core/ACL.php:327 +#: src/Core/ACL.php:328 msgid "Connectors" msgstr "" @@ -3662,207 +3223,207 @@ msgstr "Databas används redan." msgid "Could not connect to database." msgstr "Kunde inte ansluta till databasen." -#: src/Core/L10n.php:377 src/Model/Event.php:425 +#: src/Core/L10n.php:399 src/Model/Event.php:424 #: src/Module/Settings/Display.php:182 msgid "Monday" msgstr "måndag" -#: src/Core/L10n.php:377 src/Model/Event.php:426 +#: src/Core/L10n.php:399 src/Model/Event.php:425 msgid "Tuesday" msgstr "tisdag" -#: src/Core/L10n.php:377 src/Model/Event.php:427 +#: src/Core/L10n.php:399 src/Model/Event.php:426 msgid "Wednesday" msgstr "onsdag" -#: src/Core/L10n.php:377 src/Model/Event.php:428 +#: src/Core/L10n.php:399 src/Model/Event.php:427 msgid "Thursday" msgstr "torsdag" -#: src/Core/L10n.php:377 src/Model/Event.php:429 +#: src/Core/L10n.php:399 src/Model/Event.php:428 msgid "Friday" msgstr "fredag" -#: src/Core/L10n.php:377 src/Model/Event.php:430 +#: src/Core/L10n.php:399 src/Model/Event.php:429 msgid "Saturday" msgstr "lördag" -#: src/Core/L10n.php:377 src/Model/Event.php:424 +#: src/Core/L10n.php:399 src/Model/Event.php:423 #: src/Module/Settings/Display.php:182 msgid "Sunday" msgstr "söndag" -#: src/Core/L10n.php:381 src/Model/Event.php:445 +#: src/Core/L10n.php:403 src/Model/Event.php:444 msgid "January" msgstr "januari" -#: src/Core/L10n.php:381 src/Model/Event.php:446 +#: src/Core/L10n.php:403 src/Model/Event.php:445 msgid "February" msgstr "februari" -#: src/Core/L10n.php:381 src/Model/Event.php:447 +#: src/Core/L10n.php:403 src/Model/Event.php:446 msgid "March" msgstr "mars" -#: src/Core/L10n.php:381 src/Model/Event.php:448 +#: src/Core/L10n.php:403 src/Model/Event.php:447 msgid "April" msgstr "april" -#: src/Core/L10n.php:381 src/Core/L10n.php:401 src/Model/Event.php:436 +#: src/Core/L10n.php:403 src/Core/L10n.php:422 src/Model/Event.php:435 msgid "May" msgstr "maj" -#: src/Core/L10n.php:381 src/Model/Event.php:449 +#: src/Core/L10n.php:403 src/Model/Event.php:448 msgid "June" msgstr "juni" -#: src/Core/L10n.php:381 src/Model/Event.php:450 +#: src/Core/L10n.php:403 src/Model/Event.php:449 msgid "July" msgstr "juli" -#: src/Core/L10n.php:381 src/Model/Event.php:451 +#: src/Core/L10n.php:403 src/Model/Event.php:450 msgid "August" msgstr "augusti" -#: src/Core/L10n.php:381 src/Model/Event.php:452 +#: src/Core/L10n.php:403 src/Model/Event.php:451 msgid "September" msgstr "september" -#: src/Core/L10n.php:381 src/Model/Event.php:453 +#: src/Core/L10n.php:403 src/Model/Event.php:452 msgid "October" msgstr "oktober" -#: src/Core/L10n.php:381 src/Model/Event.php:454 +#: src/Core/L10n.php:403 src/Model/Event.php:453 msgid "November" msgstr "november" -#: src/Core/L10n.php:381 src/Model/Event.php:455 +#: src/Core/L10n.php:403 src/Model/Event.php:454 msgid "December" msgstr "december" -#: src/Core/L10n.php:397 src/Model/Event.php:417 +#: src/Core/L10n.php:418 src/Model/Event.php:416 msgid "Mon" msgstr "Mån" -#: src/Core/L10n.php:397 src/Model/Event.php:418 +#: src/Core/L10n.php:418 src/Model/Event.php:417 msgid "Tue" msgstr "Tis" -#: src/Core/L10n.php:397 src/Model/Event.php:419 +#: src/Core/L10n.php:418 src/Model/Event.php:418 msgid "Wed" msgstr "Ons" -#: src/Core/L10n.php:397 src/Model/Event.php:420 +#: src/Core/L10n.php:418 src/Model/Event.php:419 msgid "Thu" msgstr "Tor" -#: src/Core/L10n.php:397 src/Model/Event.php:421 +#: src/Core/L10n.php:418 src/Model/Event.php:420 msgid "Fri" msgstr "Fre" -#: src/Core/L10n.php:397 src/Model/Event.php:422 +#: src/Core/L10n.php:418 src/Model/Event.php:421 msgid "Sat" msgstr "Lör" -#: src/Core/L10n.php:397 src/Model/Event.php:416 +#: src/Core/L10n.php:418 src/Model/Event.php:415 msgid "Sun" msgstr "Sön" -#: src/Core/L10n.php:401 src/Model/Event.php:432 +#: src/Core/L10n.php:422 src/Model/Event.php:431 msgid "Jan" msgstr "Jan" -#: src/Core/L10n.php:401 src/Model/Event.php:433 +#: src/Core/L10n.php:422 src/Model/Event.php:432 msgid "Feb" msgstr "Feb" -#: src/Core/L10n.php:401 src/Model/Event.php:434 +#: src/Core/L10n.php:422 src/Model/Event.php:433 msgid "Mar" msgstr "Mar" -#: src/Core/L10n.php:401 src/Model/Event.php:435 +#: src/Core/L10n.php:422 src/Model/Event.php:434 msgid "Apr" msgstr "Apr" -#: src/Core/L10n.php:401 src/Model/Event.php:437 +#: src/Core/L10n.php:422 src/Model/Event.php:436 msgid "Jun" msgstr "Jun" -#: src/Core/L10n.php:401 src/Model/Event.php:438 +#: src/Core/L10n.php:422 src/Model/Event.php:437 msgid "Jul" msgstr "Jul" -#: src/Core/L10n.php:401 src/Model/Event.php:439 +#: src/Core/L10n.php:422 src/Model/Event.php:438 msgid "Aug" msgstr "Aug" -#: src/Core/L10n.php:401 +#: src/Core/L10n.php:422 msgid "Sep" msgstr "Sep" -#: src/Core/L10n.php:401 src/Model/Event.php:441 +#: src/Core/L10n.php:422 src/Model/Event.php:440 msgid "Oct" msgstr "Okt" -#: src/Core/L10n.php:401 src/Model/Event.php:442 +#: src/Core/L10n.php:422 src/Model/Event.php:441 msgid "Nov" msgstr "Nov" -#: src/Core/L10n.php:401 src/Model/Event.php:443 +#: src/Core/L10n.php:422 src/Model/Event.php:442 msgid "Dec" msgstr "Dec" -#: src/Core/L10n.php:420 +#: src/Core/L10n.php:441 msgid "poke" msgstr "peta" -#: src/Core/L10n.php:420 +#: src/Core/L10n.php:441 msgid "poked" msgstr "petad" -#: src/Core/L10n.php:421 +#: src/Core/L10n.php:442 msgid "ping" msgstr "ping" -#: src/Core/L10n.php:421 +#: src/Core/L10n.php:442 msgid "pinged" msgstr "pingad" -#: src/Core/L10n.php:422 +#: src/Core/L10n.php:443 msgid "prod" msgstr "prod" -#: src/Core/L10n.php:422 +#: src/Core/L10n.php:443 msgid "prodded" msgstr "proddad" -#: src/Core/L10n.php:423 +#: src/Core/L10n.php:444 msgid "slap" msgstr "smiska" -#: src/Core/L10n.php:423 +#: src/Core/L10n.php:444 msgid "slapped" msgstr "" -#: src/Core/L10n.php:424 +#: src/Core/L10n.php:445 msgid "finger" msgstr "finger" -#: src/Core/L10n.php:424 +#: src/Core/L10n.php:445 msgid "fingered" msgstr "fingrad" -#: src/Core/L10n.php:425 +#: src/Core/L10n.php:446 msgid "rebuff" msgstr "" -#: src/Core/L10n.php:425 +#: src/Core/L10n.php:446 msgid "rebuffed" msgstr "" #: src/Core/Renderer.php:89 src/Core/Renderer.php:118 #: src/Core/Renderer.php:145 src/Core/Renderer.php:179 -#: src/Render/FriendicaSmartyEngine.php:56 +#: src/Render/FriendicaSmartyEngine.php:69 msgid "" "Friendica can't display this page at the moment, please contact the " "administrator." @@ -3945,35 +3506,35 @@ msgid "" "\t\t\t\t\tThe friendica database was successfully updated from %s to %s." msgstr "" -#: src/Core/UserImport.php:125 +#: src/Core/UserImport.php:126 msgid "Error decoding account file" msgstr "" -#: src/Core/UserImport.php:131 +#: src/Core/UserImport.php:132 msgid "Error! No version data in file! This is not a Friendica account file?" msgstr "" -#: src/Core/UserImport.php:139 +#: src/Core/UserImport.php:140 #, php-format msgid "User '%s' already exists on this server!" msgstr "Användaren '%s' existerar redan i den här servern!" -#: src/Core/UserImport.php:175 +#: src/Core/UserImport.php:176 msgid "User creation error" msgstr "Fel uppstod när användaren skulle skapas" -#: src/Core/UserImport.php:220 +#: src/Core/UserImport.php:221 #, php-format msgid "%d contact not imported" msgid_plural "%d contacts not imported" msgstr[0] "%d kontakt importerades inte" msgstr[1] "%d kontakterna importerades inte" -#: src/Core/UserImport.php:273 +#: src/Core/UserImport.php:274 msgid "User profile creation error" msgstr "" -#: src/Core/UserImport.php:326 +#: src/Core/UserImport.php:327 msgid "Done. You can now login with your username and password" msgstr "Färdig. Du kan nu logga in med ditt användarnamn och lösenord" @@ -4003,7 +3564,7 @@ msgstr "" msgid "There are no tables on MyISAM or InnoDB with the Antelope file format." msgstr "" -#: src/Database/DBStructure.php:158 +#: src/Database/DBStructure.php:157 #, php-format msgid "" "\n" @@ -4011,20 +3572,20 @@ msgid "" "%s\n" msgstr "" -#: src/Database/DBStructure.php:161 +#: src/Database/DBStructure.php:160 msgid "Errors encountered performing database changes: " msgstr "" -#: src/Database/DBStructure.php:549 +#: src/Database/DBStructure.php:563 msgid "Another database update is currently running." msgstr "" -#: src/Database/DBStructure.php:553 +#: src/Database/DBStructure.php:567 #, php-format msgid "%s: Database update" msgstr "%s: Uppdatering av databas" -#: src/Database/DBStructure.php:803 +#: src/Database/DBStructure.php:817 #, php-format msgid "%s: updating %s table." msgstr "" @@ -4055,81 +3616,81 @@ msgstr "Internt server-fel" msgid "Legacy module file not found: %s" msgstr "" -#: src/Model/Contact.php:1057 src/Model/Contact.php:1069 +#: src/Model/Contact.php:1104 src/Model/Contact.php:1116 msgid "UnFollow" msgstr "Avfölj" -#: src/Model/Contact.php:1075 src/Module/Admin/Users/Pending.php:107 +#: src/Model/Contact.php:1122 src/Module/Admin/Users/Pending.php:107 #: src/Module/Notifications/Introductions.php:130 #: src/Module/Notifications/Introductions.php:202 msgid "Approve" msgstr "Godkänn" -#: src/Model/Contact.php:1490 +#: src/Model/Contact.php:1534 msgid "Organisation" msgstr "Organisation" -#: src/Model/Contact.php:1498 +#: src/Model/Contact.php:1542 msgid "Forum" msgstr "Forum" -#: src/Model/Contact.php:2426 +#: src/Model/Contact.php:2625 msgid "Disallowed profile URL." msgstr "Otillåten profil-URL." -#: src/Model/Contact.php:2431 src/Module/Friendica.php:81 +#: src/Model/Contact.php:2630 src/Module/Friendica.php:81 msgid "Blocked domain" -msgstr "" +msgstr "Blockerad domän" -#: src/Model/Contact.php:2436 +#: src/Model/Contact.php:2635 msgid "Connect URL missing." msgstr "" -#: src/Model/Contact.php:2445 +#: src/Model/Contact.php:2644 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "" -#: src/Model/Contact.php:2482 +#: src/Model/Contact.php:2686 msgid "The profile address specified does not provide adequate information." msgstr "Angiven profiladress ger inte tillräcklig information." -#: src/Model/Contact.php:2484 +#: src/Model/Contact.php:2688 msgid "No compatible communication protocols or feeds were discovered." -msgstr "" +msgstr "Inga kompatibla kommunikationsprotokoll eller flöden hittades." -#: src/Model/Contact.php:2487 +#: src/Model/Contact.php:2691 msgid "An author or name was not found." msgstr "En författare eller namnet hittades inte." -#: src/Model/Contact.php:2490 +#: src/Model/Contact.php:2694 msgid "No browser URL could be matched to this address." msgstr "" -#: src/Model/Contact.php:2493 +#: src/Model/Contact.php:2697 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "" -#: src/Model/Contact.php:2494 +#: src/Model/Contact.php:2698 msgid "Use mailto: in front of address to force email check." msgstr "" -#: src/Model/Contact.php:2500 +#: src/Model/Contact.php:2704 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "" -#: src/Model/Contact.php:2505 +#: src/Model/Contact.php:2709 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "Begränsad profil. Den här personen kommer inte att kunna ta emot personliga meddelanden från dig." -#: src/Model/Contact.php:2564 +#: src/Model/Contact.php:2768 msgid "Unable to retrieve contact information." msgstr "Det gick inte att komma åt kontaktinformationen." @@ -4137,41 +3698,41 @@ msgstr "Det gick inte att komma åt kontaktinformationen." msgid "l F d, Y \\@ g:i A \\G\\M\\TP (e)" msgstr "" -#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:464 +#: src/Model/Event.php:73 src/Model/Event.php:90 src/Model/Event.php:463 #: src/Model/Event.php:897 msgid "Starts:" msgstr "Börjar:" -#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:465 +#: src/Model/Event.php:76 src/Model/Event.php:96 src/Model/Event.php:464 #: src/Model/Event.php:901 msgid "Finishes:" msgstr "Slutar:" -#: src/Model/Event.php:414 +#: src/Model/Event.php:413 msgid "all-day" msgstr "hela dagen" -#: src/Model/Event.php:440 +#: src/Model/Event.php:439 msgid "Sept" msgstr "Sept" -#: src/Model/Event.php:462 +#: src/Model/Event.php:461 msgid "No events to display" msgstr "Inga evenemang att visa" -#: src/Model/Event.php:578 +#: src/Model/Event.php:577 msgid "l, F j" msgstr "l, F j" -#: src/Model/Event.php:609 +#: src/Model/Event.php:608 msgid "Edit event" msgstr "Redigera evenemang" -#: src/Model/Event.php:610 +#: src/Model/Event.php:609 msgid "Duplicate event" msgstr "Fördubbla evenemanget" -#: src/Model/Event.php:611 +#: src/Model/Event.php:610 msgid "Delete event" msgstr "Ta bort evenemanget" @@ -4195,370 +3756,395 @@ msgstr "Visa karta" msgid "Hide map" msgstr "Göm karta" -#: src/Model/Event.php:1009 +#: src/Model/Event.php:1010 #, php-format msgid "%s's birthday" msgstr "%s's födelsedag" -#: src/Model/Event.php:1010 +#: src/Model/Event.php:1011 #, php-format msgid "Happy Birthday %s" msgstr "Grattis på födelsedagen %s" -#: src/Model/Group.php:94 +#: 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:423 +#: src/Model/Group.php:499 msgid "Default privacy group for new contacts" msgstr "" -#: src/Model/Group.php:455 +#: src/Model/Group.php:531 msgid "Everybody" msgstr "Alla" -#: src/Model/Group.php:474 +#: src/Model/Group.php:550 msgid "edit" msgstr "redigera" -#: src/Model/Group.php:506 +#: src/Model/Group.php:582 msgid "add" msgstr "lägg till" -#: src/Model/Group.php:511 +#: src/Model/Group.php:587 msgid "Edit group" msgstr "Redigera gruppen" -#: src/Model/Group.php:512 src/Module/Group.php:194 +#: src/Model/Group.php:588 src/Module/Group.php:194 msgid "Contacts not in any group" msgstr "Kontakterna finns inte i någon av grupperna" -#: src/Model/Group.php:514 +#: src/Model/Group.php:590 msgid "Create a new group" msgstr "Skapa ny grupp" -#: src/Model/Group.php:515 src/Module/Group.php:179 src/Module/Group.php:202 +#: src/Model/Group.php:591 src/Module/Group.php:179 src/Module/Group.php:202 #: src/Module/Group.php:277 msgid "Group Name: " msgstr "Gruppens namn: " -#: src/Model/Group.php:516 +#: src/Model/Group.php:592 msgid "Edit groups" msgstr "Redigera grupper" -#: src/Model/Item.php:1680 +#: src/Model/Item.php:1823 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "Upptäckte språken i det här inlägget:\\n%s" -#: src/Model/Item.php:2631 +#: src/Model/Item.php:2730 msgid "activity" msgstr "aktivitet" -#: src/Model/Item.php:2633 +#: src/Model/Item.php:2732 msgid "comment" msgstr "kommentar" -#: src/Model/Item.php:2636 +#: src/Model/Item.php:2735 msgid "post" msgstr "inlägg" -#: src/Model/Item.php:2773 +#: src/Model/Item.php:2851 #, php-format msgid "Content warning: %s" msgstr "Innehållsvarning: %s" -#: src/Model/Item.php:3123 +#: src/Model/Item.php:3210 msgid "bytes" msgstr "bytes" -#: src/Model/Item.php:3152 src/Model/Item.php:3153 +#: src/Model/Item.php:3244 +#, php-format +msgid "%s (%d%s, %d votes)" +msgstr "" + +#: src/Model/Item.php:3246 +#, php-format +msgid "%s (%d votes)" +msgstr "" + +#: src/Model/Item.php:3251 +#, php-format +msgid "%d voters. Poll end: %s" +msgstr "" + +#: src/Model/Item.php:3253 +#, php-format +msgid "%d voters." +msgstr "" + +#: src/Model/Item.php:3255 +#, php-format +msgid "Poll end: %s" +msgstr "Omröstningen slut om: %s" + +#: src/Model/Item.php:3289 src/Model/Item.php:3290 msgid "View on separate page" msgstr "Visa på en separat sida" -#: src/Model/Mail.php:134 src/Model/Mail.php:266 +#: src/Model/Mail.php:137 src/Model/Mail.php:265 msgid "[no subject]" msgstr "[ingen rubrik]" -#: src/Model/Profile.php:356 src/Module/Profile/Profile.php:256 +#: src/Model/Profile.php:359 src/Module/Profile/Profile.php:256 #: src/Module/Profile/Profile.php:258 msgid "Edit profile" msgstr "Redigera profil" -#: src/Model/Profile.php:358 +#: src/Model/Profile.php:361 msgid "Change profile photo" msgstr "Byt profilbild" -#: src/Model/Profile.php:371 src/Module/Directory.php:152 +#: src/Model/Profile.php:374 src/Module/Directory.php:153 #: src/Module/Profile/Profile.php:184 msgid "Homepage:" msgstr "Hemsida:" -#: src/Model/Profile.php:372 src/Module/Contact/Profile.php:375 +#: src/Model/Profile.php:375 src/Module/Contact/Profile.php:375 #: src/Module/Notifications/Introductions.php:187 msgid "About:" msgstr "Om:" -#: src/Model/Profile.php:458 +#: src/Model/Profile.php:461 msgid "Atom feed" msgstr "Atom-flöde" -#: src/Model/Profile.php:502 +#: src/Model/Profile.php:505 msgid "F d" msgstr "F d" -#: src/Model/Profile.php:566 src/Model/Profile.php:650 +#: src/Model/Profile.php:569 src/Model/Profile.php:653 msgid "[today]" msgstr "[idag]" -#: src/Model/Profile.php:575 +#: src/Model/Profile.php:578 msgid "Birthday Reminders" msgstr "Födelsedagspåminnelser" -#: src/Model/Profile.php:576 +#: src/Model/Profile.php:579 msgid "Birthdays this week:" msgstr "Födelsedagar denna vecka:" -#: src/Model/Profile.php:599 +#: src/Model/Profile.php:602 msgid "g A l F d" msgstr "g A l F d" -#: src/Model/Profile.php:637 +#: src/Model/Profile.php:640 msgid "[No description]" msgstr "[Ingen beskrivning]" -#: src/Model/Profile.php:663 +#: src/Model/Profile.php:666 msgid "Event Reminders" msgstr "Evenemangspåminnare" -#: src/Model/Profile.php:664 +#: src/Model/Profile.php:667 msgid "Upcoming events the next 7 days:" msgstr "Evenemang som kommer de kommande 7 dagarna:" -#: src/Model/Profile.php:852 +#: src/Model/Profile.php:855 #, php-format msgid "OpenWebAuth: %1$s welcomes %2$s" msgstr "OpenWebAuth: %1$s välkomnar %2$s" -#: src/Model/Profile.php:984 +#: src/Model/Profile.php:981 msgid "Hometown:" msgstr "Hemstad:" -#: src/Model/Profile.php:985 +#: src/Model/Profile.php:982 msgid "Marital Status:" msgstr "Civilstånd:" -#: src/Model/Profile.php:986 +#: src/Model/Profile.php:983 msgid "With:" msgstr "Med:" -#: src/Model/Profile.php:987 +#: src/Model/Profile.php:984 msgid "Since:" msgstr "Sedan:" -#: src/Model/Profile.php:988 +#: src/Model/Profile.php:985 msgid "Sexual Preference:" msgstr "Sexualitet" -#: src/Model/Profile.php:989 +#: src/Model/Profile.php:986 msgid "Political Views:" msgstr "Politisk åskådning:" -#: src/Model/Profile.php:990 +#: src/Model/Profile.php:987 msgid "Religious Views:" msgstr "Religion:" -#: src/Model/Profile.php:991 +#: src/Model/Profile.php:988 msgid "Likes:" -msgstr "" +msgstr "Gillar:" -#: src/Model/Profile.php:992 +#: src/Model/Profile.php:989 msgid "Dislikes:" -msgstr "" +msgstr "Ogillar:" -#: src/Model/Profile.php:993 +#: src/Model/Profile.php:990 msgid "Title/Description:" msgstr "Titel/Beskrivning:" -#: src/Model/Profile.php:994 src/Module/Admin/Summary.php:233 +#: src/Model/Profile.php:991 src/Module/Admin/Summary.php:234 msgid "Summary" msgstr "Sammanfattning" -#: src/Model/Profile.php:995 +#: src/Model/Profile.php:992 msgid "Musical interests" msgstr "Musik" -#: src/Model/Profile.php:996 +#: src/Model/Profile.php:993 msgid "Books, literature" msgstr "Böcker, litteratur" -#: src/Model/Profile.php:997 +#: src/Model/Profile.php:994 msgid "Television" msgstr "TV" -#: src/Model/Profile.php:998 +#: src/Model/Profile.php:995 msgid "Film/dance/culture/entertainment" msgstr "Film/Dans/Kultur/Nöje" -#: src/Model/Profile.php:999 +#: src/Model/Profile.php:996 msgid "Hobbies/Interests" msgstr "Hobbys/Intressen" -#: src/Model/Profile.php:1000 +#: src/Model/Profile.php:997 msgid "Love/romance" msgstr "Kärlek/Romantik" -#: src/Model/Profile.php:1001 +#: src/Model/Profile.php:998 msgid "Work/employment" msgstr "Arbete" -#: src/Model/Profile.php:1002 +#: src/Model/Profile.php:999 msgid "School/education" msgstr "Skola/Utbildning" -#: src/Model/Profile.php:1003 +#: src/Model/Profile.php:1000 msgid "Contact information and Social Networks" msgstr "Kontaktuppgifter och sociala nätverk" -#: src/Model/User.php:208 src/Model/User.php:1056 +#: src/Model/User.php:212 src/Model/User.php:1058 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "SERIOUS ERROR: Generation of security keys failed." -#: src/Model/User.php:568 src/Model/User.php:601 +#: src/Model/User.php:570 src/Model/User.php:603 msgid "Login failed" msgstr "Inloggningen misslyckades" -#: src/Model/User.php:633 +#: src/Model/User.php:635 msgid "Not enough information to authenticate" msgstr "Inte tillräckligt med information för att autentisera" -#: src/Model/User.php:728 +#: src/Model/User.php:730 msgid "Password can't be empty" msgstr "Lösenordet kan inte vara tomt" -#: src/Model/User.php:747 +#: src/Model/User.php:749 msgid "Empty passwords are not allowed." msgstr "Tomma lösenord är inte tillåtna." -#: src/Model/User.php:751 +#: src/Model/User.php:753 msgid "" "The new password has been exposed in a public data dump, please choose " "another." msgstr "" -#: src/Model/User.php:757 +#: src/Model/User.php:759 msgid "" "The password can't contain accentuated letters, white spaces or colons (:)" msgstr "" -#: src/Model/User.php:936 +#: src/Model/User.php:938 msgid "Passwords do not match. Password unchanged." msgstr "Lösenorden skiljer sig åt. Lösenordet ändras inte." -#: src/Model/User.php:943 +#: src/Model/User.php:945 msgid "An invitation is required." msgstr "En inbjudning krävs." -#: src/Model/User.php:947 +#: src/Model/User.php:949 msgid "Invitation could not be verified." msgstr "Inbjudningen kunde inte bekräftas." -#: src/Model/User.php:955 +#: src/Model/User.php:957 msgid "Invalid OpenID url" msgstr "Ogiltig OpenID-URL" -#: src/Model/User.php:968 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 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:968 src/Security/Authentication.php:235 +#: src/Model/User.php:970 src/Security/Authentication.php:240 msgid "The error message was:" msgstr "Felmeddelandet var:" -#: src/Model/User.php:974 +#: src/Model/User.php:976 msgid "Please enter the required information." msgstr "Fyll i alla obligatoriska fält." -#: src/Model/User.php:988 +#: src/Model/User.php:990 #, 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:995 +#: src/Model/User.php:997 #, php-format msgid "Username should be at least %s character." msgid_plural "Username should be at least %s characters." msgstr[0] "Användarnamnet bör ha åtminstone %s tecken." msgstr[1] "Användarnamn borde ha åtminstone %s tecken." -#: src/Model/User.php:999 +#: src/Model/User.php:1001 #, 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:1007 +#: src/Model/User.php:1009 msgid "That doesn't appear to be your full (First Last) name." msgstr "Du verkar inte ha angett ditt fullständiga namn." -#: src/Model/User.php:1012 +#: src/Model/User.php:1014 msgid "Your email domain is not among those allowed on this site." msgstr "Din e-postdomän är inte tillåten på den här webbplatsen." -#: src/Model/User.php:1016 +#: src/Model/User.php:1018 msgid "Not a valid email address." msgstr "Ogiltig e-postadress." -#: src/Model/User.php:1019 +#: src/Model/User.php:1021 msgid "The nickname was blocked from registration by the nodes admin." msgstr "" -#: src/Model/User.php:1023 src/Model/User.php:1031 +#: src/Model/User.php:1025 src/Model/User.php:1033 msgid "Cannot use that email." msgstr "Otillåten e-postadress." -#: src/Model/User.php:1038 +#: src/Model/User.php:1040 msgid "Your nickname can only contain a-z, 0-9 and _." msgstr "" -#: src/Model/User.php:1046 src/Model/User.php:1103 +#: src/Model/User.php:1048 src/Model/User.php:1105 msgid "Nickname is already registered. Please choose another." msgstr "Användarnamnet är upptaget. Välj ett annat." -#: src/Model/User.php:1090 src/Model/User.php:1094 +#: src/Model/User.php:1092 src/Model/User.php:1096 msgid "An error occurred during registration. Please try again." msgstr "Något gick fel vid registreringen. Försök igen." -#: src/Model/User.php:1117 +#: src/Model/User.php:1119 msgid "An error occurred creating your default profile. Please try again." msgstr "Det blev fel när din standardprofil skulle skapas. Prova igen." -#: src/Model/User.php:1124 +#: src/Model/User.php:1126 msgid "An error occurred creating your self contact. Please try again." msgstr "" -#: src/Model/User.php:1129 +#: src/Model/User.php:1131 msgid "Friends" msgstr "Vänner" -#: src/Model/User.php:1133 +#: src/Model/User.php:1135 msgid "" "An error occurred creating your default contact group. Please try again." msgstr "" -#: src/Model/User.php:1171 +#: src/Model/User.php:1174 msgid "Profile Photos" msgstr "Profilbilder" -#: src/Model/User.php:1365 +#: src/Model/User.php:1367 #, php-format msgid "" "\n" @@ -4566,7 +4152,7 @@ msgid "" "\t\t\tthe administrator of %2$s has set up an account for you." msgstr "" -#: src/Model/User.php:1368 +#: src/Model/User.php:1370 #, php-format msgid "" "\n" @@ -4598,12 +4184,12 @@ msgid "" "\t\tThank you and welcome to %4$s." msgstr "" -#: src/Model/User.php:1401 src/Model/User.php:1508 +#: src/Model/User.php:1403 src/Model/User.php:1510 #, php-format msgid "Registration details for %s" msgstr "Registreringsdetaljer för 1%s" -#: src/Model/User.php:1421 +#: src/Model/User.php:1423 #, php-format msgid "" "\n" @@ -4618,12 +4204,12 @@ msgid "" "\t\t" msgstr "" -#: src/Model/User.php:1440 +#: src/Model/User.php:1442 #, php-format msgid "Registration at %s" msgstr "" -#: src/Model/User.php:1464 +#: src/Model/User.php:1466 #, php-format msgid "" "\n" @@ -4632,7 +4218,7 @@ msgid "" "\t\t\t" msgstr "" -#: src/Model/User.php:1472 +#: src/Model/User.php:1474 #, php-format msgid "" "\n" @@ -4693,10 +4279,10 @@ msgstr "Aktivera" #: src/Module/Admin/Blocklist/Contact.php:94 #: src/Module/Admin/Blocklist/Server/Add.php:89 #: src/Module/Admin/Blocklist/Server/Index.php:78 -#: src/Module/Admin/Federation.php:159 src/Module/Admin/Item/Delete.php:64 -#: src/Module/Admin/Logs/Settings.php:79 src/Module/Admin/Logs/View.php:83 -#: src/Module/Admin/Queue.php:72 src/Module/Admin/Site.php:498 -#: src/Module/Admin/Storage.php:138 src/Module/Admin/Summary.php:232 +#: src/Module/Admin/Federation.php:196 src/Module/Admin/Item/Delete.php:64 +#: src/Module/Admin/Logs/Settings.php:79 src/Module/Admin/Logs/View.php:84 +#: src/Module/Admin/Queue.php:72 src/Module/Admin/Site.php:431 +#: src/Module/Admin/Storage.php:138 src/Module/Admin/Summary.php:233 #: src/Module/Admin/Themes/Details.php:90 #: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:75 #: src/Module/Admin/Users/Active.php:136 @@ -4707,7 +4293,7 @@ msgid "Administration" msgstr "Administration" #: src/Module/Admin/Addons/Details.php:112 -#: src/Module/Admin/Addons/Index.php:68 src/Module/BaseAdmin.php:93 +#: src/Module/Admin/Addons/Index.php:68 src/Module/BaseAdmin.php:96 #: src/Module/BaseSettings.php:85 msgid "Addons" msgstr "Insticksprogram" @@ -4763,11 +4349,11 @@ msgstr "Lista över aktiva konton" #: src/Module/Admin/BaseUsers.php:67 src/Module/Contact.php:314 #: src/Module/Contact.php:374 msgid "Pending" -msgstr "" +msgstr "Väntande" #: src/Module/Admin/BaseUsers.php:70 msgid "List of pending registrations" -msgstr "" +msgstr "Lista över väntande registreringar" #: src/Module/Admin/BaseUsers.php:75 src/Module/Contact.php:322 #: src/Module/Contact.php:375 @@ -4784,12 +4370,44 @@ msgstr "Ta bort" #: src/Module/Admin/BaseUsers.php:86 msgid "List of pending user deletions" +msgstr "Lista över väntande borttagningar av användare" + +#: src/Module/Admin/BaseUsers.php:100 src/Module/Settings/Account.php:493 +msgid "Normal Account Page" +msgstr "Normal konto-sida" + +#: src/Module/Admin/BaseUsers.php:101 src/Module/Settings/Account.php:500 +msgid "Soapbox Page" +msgstr "" + +#: src/Module/Admin/BaseUsers.php:102 src/Module/Settings/Account.php:507 +msgid "Public Forum" +msgstr "Publikt forum" + +#: src/Module/Admin/BaseUsers.php:103 src/Module/Settings/Account.php:514 +msgid "Automatic Friend Page" msgstr "" #: src/Module/Admin/BaseUsers.php:104 msgid "Private Forum" msgstr "Privat forum" +#: src/Module/Admin/BaseUsers.php:107 src/Module/Settings/Account.php:465 +msgid "Personal Page" +msgstr "Personlig sida" + +#: src/Module/Admin/BaseUsers.php:108 src/Module/Settings/Account.php:472 +msgid "Organisation Page" +msgstr "Sida för organisation" + +#: src/Module/Admin/BaseUsers.php:109 src/Module/Settings/Account.php:479 +msgid "News Page" +msgstr "" + +#: src/Module/Admin/BaseUsers.php:110 src/Module/Settings/Account.php:486 +msgid "Community Forum" +msgstr "" + #: src/Module/Admin/BaseUsers.php:111 msgid "Relay" msgstr "Fördröj" @@ -5105,29 +4723,65 @@ msgstr "Lås-funktion %s" msgid "Manage Additional Features" msgstr "Hantera ytterligare funktioner" -#: src/Module/Admin/Federation.php:56 +#: src/Module/Admin/Federation.php:65 msgid "Other" msgstr "Annat" -#: src/Module/Admin/Federation.php:118 src/Module/Admin/Federation.php:348 +#: src/Module/Admin/Federation.php:136 src/Module/Admin/Federation.php:385 msgid "unknown" msgstr "okänd" -#: src/Module/Admin/Federation.php:154 +#: src/Module/Admin/Federation.php:169 +#, php-format +msgid "%s total systems" +msgstr "%s totala system" + +#: src/Module/Admin/Federation.php:170 +#, php-format +msgid "%s active users last month" +msgstr "%s aktiva användare senaste månaden" + +#: src/Module/Admin/Federation.php:171 +#, php-format +msgid "%s active users last six months" +msgstr "%s aktiva användare senaste 6 månaderna" + +#: src/Module/Admin/Federation.php:172 +#, php-format +msgid "%s registered users" +msgstr "%s registrerade användare" + +#: src/Module/Admin/Federation.php:173 +#, php-format +msgid "%s locally created posts and comments" +msgstr "%s lokalt skapade postningar och kommentarer" + +#: src/Module/Admin/Federation.php:176 +#, php-format +msgid "%s posts per user" +msgstr "%s postningar per användare" + +#: src/Module/Admin/Federation.php:181 +#, php-format +msgid "%s users per system" +msgstr "%s användare per system" + +#: src/Module/Admin/Federation.php:191 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:160 src/Module/BaseAdmin.php:87 +#: src/Module/Admin/Federation.php:197 src/Module/BaseAdmin.php:90 msgid "Federation Statistics" msgstr "" -#: src/Module/Admin/Federation.php:164 +#: src/Module/Admin/Federation.php:201 #, php-format msgid "" -"Currently this node is aware of %d nodes with %d registered users from the " +"Currently this node is aware of %s nodes (%s active users last month, %s " +"active users last six months, %s registered users in total) from the " "following platforms:" msgstr "" @@ -5135,7 +4789,7 @@ msgstr "" msgid "Item marked for deletion." msgstr "Objektet är markerat för borttagning." -#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:106 +#: src/Module/Admin/Item/Delete.php:65 src/Module/BaseAdmin.php:109 msgid "Delete Item" msgstr "Ta bort objekt" @@ -5164,7 +4818,7 @@ msgstr "GUID" msgid "The GUID of the item you want to delete." msgstr "Objektets GUID som du vill ta bort." -#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:116 +#: src/Module/Admin/Item/Source.php:57 src/Module/BaseAdmin.php:119 msgid "Item Source" msgstr "Objektets källa" @@ -5209,7 +4863,7 @@ msgstr "Nämn" msgid "Implicit Mention" msgstr "" -#: src/Module/Admin/Item/Source.php:73 src/Module/Admin/Logs/View.php:98 +#: src/Module/Admin/Item/Source.php:73 src/Module/Admin/Logs/View.php:99 #: src/Module/Debug/ActivityPubConversion.php:62 msgid "Source" msgstr "Källa" @@ -5227,8 +4881,8 @@ msgstr "" msgid "PHP log currently disabled." msgstr "" -#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:108 -#: src/Module/BaseAdmin.php:109 +#: src/Module/Admin/Logs/Settings.php:80 src/Module/BaseAdmin.php:111 +#: src/Module/BaseAdmin.php:112 msgid "Logs" msgstr "Loggar" @@ -5281,68 +4935,68 @@ msgid "" "is readable." msgstr "" -#: src/Module/Admin/Logs/View.php:84 src/Module/BaseAdmin.php:110 +#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:113 msgid "View Logs" msgstr "Visa loggar" -#: src/Module/Admin/Logs/View.php:87 +#: src/Module/Admin/Logs/View.php:88 msgid "Search in logs" msgstr "Sök i loggar" -#: src/Module/Admin/Logs/View.php:88 +#: src/Module/Admin/Logs/View.php:89 #: src/Module/Notifications/Notifications.php:139 msgid "Show all" msgstr "Visa alla" -#: src/Module/Admin/Logs/View.php:89 +#: src/Module/Admin/Logs/View.php:90 msgid "Date" msgstr "Datum" -#: src/Module/Admin/Logs/View.php:90 +#: src/Module/Admin/Logs/View.php:91 msgid "Level" msgstr "Nivå" -#: src/Module/Admin/Logs/View.php:91 +#: src/Module/Admin/Logs/View.php:92 msgid "Context" msgstr "Sammanhang" -#: src/Module/Admin/Logs/View.php:93 +#: src/Module/Admin/Logs/View.php:94 msgid "ALL" msgstr "ALLA" -#: src/Module/Admin/Logs/View.php:94 +#: src/Module/Admin/Logs/View.php:95 msgid "View details" msgstr "Visa detaljer" -#: src/Module/Admin/Logs/View.php:95 +#: src/Module/Admin/Logs/View.php:96 msgid "Click to view details" msgstr "Klicka för att visa detaljer" -#: src/Module/Admin/Logs/View.php:97 +#: src/Module/Admin/Logs/View.php:98 msgid "Data" msgstr "Data" -#: src/Module/Admin/Logs/View.php:99 +#: src/Module/Admin/Logs/View.php:100 msgid "File" msgstr "Fil" -#: src/Module/Admin/Logs/View.php:100 +#: src/Module/Admin/Logs/View.php:101 msgid "Line" msgstr "Rad" -#: src/Module/Admin/Logs/View.php:101 +#: src/Module/Admin/Logs/View.php:102 msgid "Function" msgstr "Funktion" -#: src/Module/Admin/Logs/View.php:102 +#: src/Module/Admin/Logs/View.php:103 msgid "UID" msgstr "UID" -#: src/Module/Admin/Logs/View.php:103 +#: src/Module/Admin/Logs/View.php:104 msgid "Process ID" msgstr "" -#: src/Module/Admin/Logs/View.php:104 +#: src/Module/Admin/Logs/View.php:105 msgid "Close" msgstr "Stäng" @@ -5382,461 +5036,459 @@ msgstr "Jobb-parametrar" msgid "Priority" msgstr "Prioritet" -#: src/Module/Admin/Site.php:71 -msgid "Can not parse base url. Must have at least ://" -msgstr "" - -#: src/Module/Admin/Site.php:125 -msgid "Relocation started. Could take a while to complete." -msgstr "" - -#: src/Module/Admin/Site.php:403 src/Module/Settings/Display.php:138 +#: src/Module/Admin/Site.php:336 src/Module/Settings/Display.php:138 msgid "No special theme for mobile devices" msgstr "Inget speciellt tema för mobil-enheter" -#: src/Module/Admin/Site.php:420 src/Module/Settings/Display.php:148 +#: src/Module/Admin/Site.php:353 src/Module/Settings/Display.php:148 #, php-format msgid "%s - (Experimental)" msgstr "%s - (Experimentell)" -#: src/Module/Admin/Site.php:432 +#: src/Module/Admin/Site.php:365 msgid "No community page for local users" msgstr "Ingen gemenskapssida för lokala användare" -#: src/Module/Admin/Site.php:433 +#: src/Module/Admin/Site.php:366 msgid "No community page" msgstr "Ingen gemenskapssida" -#: src/Module/Admin/Site.php:434 +#: src/Module/Admin/Site.php:367 msgid "Public postings from users of this site" msgstr "" -#: src/Module/Admin/Site.php:435 +#: src/Module/Admin/Site.php:368 msgid "Public postings from the federated network" msgstr "" -#: src/Module/Admin/Site.php:436 +#: src/Module/Admin/Site.php:369 msgid "Public postings from local users and the federated network" msgstr "" -#: src/Module/Admin/Site.php:442 +#: src/Module/Admin/Site.php:375 msgid "Multi user instance" msgstr "Instans för flertalet användare" -#: src/Module/Admin/Site.php:469 +#: src/Module/Admin/Site.php:402 msgid "Closed" msgstr "Stängd" -#: src/Module/Admin/Site.php:470 +#: src/Module/Admin/Site.php:403 msgid "Requires approval" msgstr "Kräver godkännande" -#: src/Module/Admin/Site.php:471 +#: src/Module/Admin/Site.php:404 msgid "Open" msgstr "Öppen" -#: src/Module/Admin/Site.php:475 src/Module/Install.php:222 +#: src/Module/Admin/Site.php:408 src/Module/Install.php:222 msgid "No SSL policy, links will track page SSL state" msgstr "" -#: src/Module/Admin/Site.php:476 src/Module/Install.php:223 +#: src/Module/Admin/Site.php:409 src/Module/Install.php:223 msgid "Force all links to use SSL" msgstr "Tvinga alla länkar att använda SSL" -#: src/Module/Admin/Site.php:477 src/Module/Install.php:224 +#: src/Module/Admin/Site.php:410 src/Module/Install.php:224 msgid "Self-signed certificate, use SSL for local links only (discouraged)" msgstr "" -#: src/Module/Admin/Site.php:481 +#: src/Module/Admin/Site.php:414 msgid "Don't check" msgstr "Kolla inte" -#: src/Module/Admin/Site.php:482 +#: src/Module/Admin/Site.php:415 msgid "check the stable version" msgstr "kolla den stabila versionen" -#: src/Module/Admin/Site.php:483 +#: src/Module/Admin/Site.php:416 msgid "check the development version" msgstr "kolla utvecklingsversionen" -#: src/Module/Admin/Site.php:487 +#: src/Module/Admin/Site.php:420 msgid "none" msgstr "ingen" -#: src/Module/Admin/Site.php:488 +#: src/Module/Admin/Site.php:421 msgid "Local contacts" msgstr "Lokala kontakter " -#: src/Module/Admin/Site.php:489 +#: src/Module/Admin/Site.php:422 msgid "Interactors" msgstr "" -#: src/Module/Admin/Site.php:499 src/Module/BaseAdmin.php:90 +#: src/Module/Admin/Site.php:432 src/Module/BaseAdmin.php:93 msgid "Site" msgstr "Sida" -#: src/Module/Admin/Site.php:500 +#: src/Module/Admin/Site.php:433 msgid "General Information" msgstr "Generell information" -#: src/Module/Admin/Site.php:502 +#: src/Module/Admin/Site.php:435 msgid "Republish users to directory" msgstr "" -#: src/Module/Admin/Site.php:503 src/Module/Register.php:152 +#: src/Module/Admin/Site.php:436 src/Module/Register.php:152 msgid "Registration" msgstr "Registrering" -#: src/Module/Admin/Site.php:504 +#: src/Module/Admin/Site.php:437 msgid "File upload" msgstr "Fil-uppladdning" -#: src/Module/Admin/Site.php:505 +#: src/Module/Admin/Site.php:438 msgid "Policies" msgstr "Policyer" -#: src/Module/Admin/Site.php:507 +#: src/Module/Admin/Site.php:440 msgid "Auto Discovered Contact Directory" msgstr "" -#: src/Module/Admin/Site.php:508 +#: src/Module/Admin/Site.php:441 msgid "Performance" msgstr "Prestanda" -#: src/Module/Admin/Site.php:509 +#: src/Module/Admin/Site.php:442 msgid "Worker" msgstr "Arbetare" -#: src/Module/Admin/Site.php:510 +#: src/Module/Admin/Site.php:443 msgid "Message Relay" msgstr "Meddelandefördröjning" -#: src/Module/Admin/Site.php:511 +#: src/Module/Admin/Site.php:444 msgid "" "Use the command \"console relay\" in the command line to add or remove " "relays." msgstr "" -#: src/Module/Admin/Site.php:512 +#: src/Module/Admin/Site.php:445 msgid "The system is not subscribed to any relays at the moment." msgstr "" -#: src/Module/Admin/Site.php:513 +#: src/Module/Admin/Site.php:446 msgid "The system is currently subscribed to the following relays:" msgstr "" -#: src/Module/Admin/Site.php:515 -msgid "Relocate Instance" -msgstr "Omlokalisera instansen" - -#: src/Module/Admin/Site.php:516 -msgid "" -"Warning! Advanced function. Could make this server " -"unreachable." +#: src/Module/Admin/Site.php:448 +msgid "Relocate Node" msgstr "" -#: src/Module/Admin/Site.php:520 +#: src/Module/Admin/Site.php:449 +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:450 +msgid "(Friendica directory)# bin/console relocate https://newdomain.com" +msgstr "" + +#: src/Module/Admin/Site.php:454 msgid "Site name" msgstr "Namn på sida" -#: src/Module/Admin/Site.php:521 +#: src/Module/Admin/Site.php:455 msgid "Sender Email" msgstr "Sändare av e-post" -#: src/Module/Admin/Site.php:521 +#: src/Module/Admin/Site.php:455 msgid "" "The email address your server shall use to send notification emails from." msgstr "" -#: src/Module/Admin/Site.php:522 +#: src/Module/Admin/Site.php:456 msgid "Name of the system actor" msgstr "" -#: src/Module/Admin/Site.php:522 +#: src/Module/Admin/Site.php:456 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:523 +#: src/Module/Admin/Site.php:457 msgid "Banner/Logo" msgstr "Banderoll/Logga" -#: src/Module/Admin/Site.php:524 +#: src/Module/Admin/Site.php:458 msgid "Email Banner/Logo" msgstr "E-postbanderoll/logga" -#: src/Module/Admin/Site.php:525 +#: src/Module/Admin/Site.php:459 msgid "Shortcut icon" msgstr "Genvägsikon" -#: src/Module/Admin/Site.php:525 +#: src/Module/Admin/Site.php:459 msgid "Link to an icon that will be used for browsers." msgstr "" -#: src/Module/Admin/Site.php:526 +#: src/Module/Admin/Site.php:460 msgid "Touch icon" msgstr "" -#: src/Module/Admin/Site.php:526 +#: src/Module/Admin/Site.php:460 msgid "Link to an icon that will be used for tablets and mobiles." msgstr "" -#: src/Module/Admin/Site.php:527 +#: src/Module/Admin/Site.php:461 msgid "Additional Info" msgstr "Ytterligare info" -#: src/Module/Admin/Site.php:527 +#: src/Module/Admin/Site.php:461 #, 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:528 +#: src/Module/Admin/Site.php:462 msgid "System language" msgstr "Systemets språk" -#: src/Module/Admin/Site.php:529 +#: src/Module/Admin/Site.php:463 msgid "System theme" msgstr "Systemets tema" -#: src/Module/Admin/Site.php:529 +#: src/Module/Admin/Site.php:463 +#, php-format msgid "" -"Default system theme - may be over-ridden by user profiles - Change default theme settings" +"Default system theme - may be over-ridden by user profiles - Change default theme settings" msgstr "" -#: src/Module/Admin/Site.php:530 +#: src/Module/Admin/Site.php:464 msgid "Mobile system theme" msgstr "" -#: src/Module/Admin/Site.php:530 +#: src/Module/Admin/Site.php:464 msgid "Theme for mobile devices" msgstr "Tema för mobilenheter" -#: src/Module/Admin/Site.php:531 src/Module/Install.php:232 +#: src/Module/Admin/Site.php:465 src/Module/Install.php:232 msgid "SSL link policy" msgstr "Policy för SSL-länk" -#: src/Module/Admin/Site.php:531 src/Module/Install.php:234 +#: src/Module/Admin/Site.php:465 src/Module/Install.php:234 msgid "Determines whether generated links should be forced to use SSL" msgstr "Avgör huruvida genererade länkar ska tvingas att använda SSL eller inte" -#: src/Module/Admin/Site.php:532 +#: src/Module/Admin/Site.php:466 msgid "Force SSL" msgstr "Tvinga SSL" -#: src/Module/Admin/Site.php:532 +#: src/Module/Admin/Site.php:466 msgid "" "Force all Non-SSL requests to SSL - Attention: on some systems it could lead" " to endless loops." msgstr "" -#: src/Module/Admin/Site.php:533 +#: src/Module/Admin/Site.php:467 msgid "Show help entry from navigation menu" msgstr "" -#: src/Module/Admin/Site.php:533 +#: src/Module/Admin/Site.php:467 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:534 +#: src/Module/Admin/Site.php:468 msgid "Single user instance" msgstr "" -#: src/Module/Admin/Site.php:534 +#: src/Module/Admin/Site.php:468 msgid "Make this instance multi-user or single-user for the named user" msgstr "" -#: src/Module/Admin/Site.php:536 +#: src/Module/Admin/Site.php:470 msgid "Maximum image size" msgstr "Maximal bildstorlek" -#: src/Module/Admin/Site.php:536 +#: src/Module/Admin/Site.php:470 msgid "" "Maximum size in bytes of uploaded images. Default is 0, which means no " "limits." msgstr "" -#: src/Module/Admin/Site.php:537 +#: src/Module/Admin/Site.php:471 msgid "Maximum image length" msgstr "Maximal bildlängd" -#: src/Module/Admin/Site.php:537 +#: src/Module/Admin/Site.php:471 msgid "" "Maximum length in pixels of the longest side of uploaded images. Default is " "-1, which means no limits." msgstr "" -#: src/Module/Admin/Site.php:538 +#: src/Module/Admin/Site.php:472 msgid "JPEG image quality" msgstr "Kvalité för JPEG-bilden" -#: src/Module/Admin/Site.php:538 +#: src/Module/Admin/Site.php:472 msgid "" "Uploaded JPEGS will be saved at this quality setting [0-100]. Default is " "100, which is full quality." msgstr "" -#: src/Module/Admin/Site.php:540 +#: src/Module/Admin/Site.php:474 msgid "Register policy" msgstr "Registrera policy" -#: src/Module/Admin/Site.php:541 +#: src/Module/Admin/Site.php:475 msgid "Maximum Daily Registrations" msgstr "Maximala registreringar varje dag" -#: src/Module/Admin/Site.php:541 +#: src/Module/Admin/Site.php:475 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 "" -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:476 msgid "Register text" msgstr "Registrera text" -#: src/Module/Admin/Site.php:542 +#: src/Module/Admin/Site.php:476 msgid "" "Will be displayed prominently on the registration page. You can use BBCode " "here." msgstr "" -#: src/Module/Admin/Site.php:543 +#: src/Module/Admin/Site.php:477 msgid "Forbidden Nicknames" msgstr "Förbjudna smeknamn" -#: src/Module/Admin/Site.php:543 +#: src/Module/Admin/Site.php:477 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:544 +#: src/Module/Admin/Site.php:478 msgid "Accounts abandoned after x days" msgstr "Konton som övergavs efter x dagar" -#: src/Module/Admin/Site.php:544 +#: src/Module/Admin/Site.php:478 msgid "" "Will not waste system resources polling external sites for abandonded " "accounts. Enter 0 for no time limit." msgstr "" -#: src/Module/Admin/Site.php:545 +#: src/Module/Admin/Site.php:479 msgid "Allowed friend domains" msgstr "Tillåtna vän-domäner" -#: src/Module/Admin/Site.php:545 +#: src/Module/Admin/Site.php:479 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:546 +#: src/Module/Admin/Site.php:480 msgid "Allowed email domains" msgstr "Tillåtna e-postdomäner" -#: src/Module/Admin/Site.php:546 +#: src/Module/Admin/Site.php:480 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:547 +#: src/Module/Admin/Site.php:481 msgid "No OEmbed rich content" msgstr "" -#: src/Module/Admin/Site.php:547 +#: src/Module/Admin/Site.php:481 msgid "" "Don't show the rich content (e.g. embedded PDF), except from the domains " "listed below." msgstr "" -#: src/Module/Admin/Site.php:548 +#: src/Module/Admin/Site.php:482 msgid "Trusted third-party domains" msgstr "" -#: src/Module/Admin/Site.php:548 +#: src/Module/Admin/Site.php:482 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:549 +#: src/Module/Admin/Site.php:483 msgid "Block public" msgstr "Blockera publik" -#: src/Module/Admin/Site.php:549 +#: src/Module/Admin/Site.php:483 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:550 +#: src/Module/Admin/Site.php:484 msgid "Force publish" msgstr "Tvinga publicering" -#: src/Module/Admin/Site.php:550 +#: src/Module/Admin/Site.php:484 msgid "" "Check to force all profiles on this site to be listed in the site directory." msgstr "" -#: src/Module/Admin/Site.php:550 +#: src/Module/Admin/Site.php:484 msgid "Enabling this may violate privacy laws like the GDPR" msgstr "" -#: src/Module/Admin/Site.php:551 +#: src/Module/Admin/Site.php:485 msgid "Global directory URL" msgstr "" -#: src/Module/Admin/Site.php:551 +#: src/Module/Admin/Site.php:485 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:552 +#: src/Module/Admin/Site.php:486 msgid "Private posts by default for new users" msgstr "Privata inlägg som standard för nya användare" -#: src/Module/Admin/Site.php:552 +#: src/Module/Admin/Site.php:486 msgid "" "Set default post permissions for all new members to the default privacy " "group rather than public." msgstr "" -#: src/Module/Admin/Site.php:553 +#: src/Module/Admin/Site.php:487 msgid "Don't include post content in email notifications" msgstr "Inkludera inte inläggets innehåll i aviseringar för e-post" -#: src/Module/Admin/Site.php:553 +#: src/Module/Admin/Site.php:487 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:554 +#: src/Module/Admin/Site.php:488 msgid "Disallow public access to addons listed in the apps menu." msgstr "" -#: src/Module/Admin/Site.php:554 +#: src/Module/Admin/Site.php:488 msgid "" "Checking this box will restrict addons listed in the apps menu to members " "only." msgstr "" -#: src/Module/Admin/Site.php:555 +#: src/Module/Admin/Site.php:489 msgid "Don't embed private images in posts" msgstr "" -#: src/Module/Admin/Site.php:555 +#: src/Module/Admin/Site.php:489 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 " @@ -5844,11 +5496,11 @@ msgid "" "while." msgstr "" -#: src/Module/Admin/Site.php:556 +#: src/Module/Admin/Site.php:490 msgid "Explicit Content" msgstr "" -#: src/Module/Admin/Site.php:556 +#: src/Module/Admin/Site.php:490 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 " @@ -5857,247 +5509,257 @@ msgid "" "will be shown at the user registration page." msgstr "" -#: src/Module/Admin/Site.php:557 +#: src/Module/Admin/Site.php:491 msgid "Proxify external content" msgstr "" -#: src/Module/Admin/Site.php:557 +#: src/Module/Admin/Site.php:491 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:558 +#: src/Module/Admin/Site.php:492 msgid "Cache contact avatars" msgstr "" -#: src/Module/Admin/Site.php:558 +#: src/Module/Admin/Site.php:492 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:559 +#: src/Module/Admin/Site.php:493 msgid "Allow Users to set remote_self" msgstr "" -#: src/Module/Admin/Site.php:559 +#: src/Module/Admin/Site.php:493 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:560 +#: src/Module/Admin/Site.php:494 msgid "Enable multiple registrations" msgstr "" -#: src/Module/Admin/Site.php:560 +#: src/Module/Admin/Site.php:494 msgid "Enable users to register additional accounts for use as pages." msgstr "" -#: src/Module/Admin/Site.php:561 +#: src/Module/Admin/Site.php:495 msgid "Enable OpenID" msgstr "" -#: src/Module/Admin/Site.php:561 +#: src/Module/Admin/Site.php:495 msgid "Enable OpenID support for registration and logins." msgstr "" -#: src/Module/Admin/Site.php:562 +#: src/Module/Admin/Site.php:496 msgid "Enable Fullname check" msgstr "" -#: src/Module/Admin/Site.php:562 +#: src/Module/Admin/Site.php:496 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:563 +#: src/Module/Admin/Site.php:497 msgid "Community pages for visitors" msgstr "" -#: src/Module/Admin/Site.php:563 +#: src/Module/Admin/Site.php:497 msgid "" "Which community pages should be available for visitors. Local users always " "see both pages." msgstr "" -#: src/Module/Admin/Site.php:564 +#: src/Module/Admin/Site.php:498 msgid "Posts per user on community page" msgstr "" -#: src/Module/Admin/Site.php:564 +#: src/Module/Admin/Site.php:498 msgid "" "The maximum number of posts per user on the community page. (Not valid for " "\"Global Community\")" msgstr "" -#: src/Module/Admin/Site.php:566 +#: src/Module/Admin/Site.php:500 msgid "Enable Mail support" msgstr "" -#: src/Module/Admin/Site.php:566 +#: src/Module/Admin/Site.php:500 msgid "" "Enable built-in mail support to poll IMAP folders and to reply via mail." msgstr "" -#: src/Module/Admin/Site.php:567 +#: src/Module/Admin/Site.php:501 msgid "" "Mail support can't be enabled because the PHP IMAP module is not installed." msgstr "" -#: src/Module/Admin/Site.php:568 +#: src/Module/Admin/Site.php:502 msgid "Enable OStatus support" msgstr "" -#: src/Module/Admin/Site.php:568 +#: src/Module/Admin/Site.php:502 msgid "" "Enable built-in OStatus (StatusNet, GNU Social etc.) compatibility. All " "communications in OStatus are public." msgstr "" -#: src/Module/Admin/Site.php:570 +#: src/Module/Admin/Site.php:504 msgid "" "Diaspora support can't be enabled because Friendica was installed into a sub" " directory." msgstr "" -#: src/Module/Admin/Site.php:571 +#: src/Module/Admin/Site.php:505 msgid "Enable Diaspora support" msgstr "Aktivera Diaspora-support" -#: src/Module/Admin/Site.php:571 +#: src/Module/Admin/Site.php:505 msgid "" "Enable built-in Diaspora network compatibility for communicating with " "diaspora servers." msgstr "" -#: src/Module/Admin/Site.php:572 +#: src/Module/Admin/Site.php:506 msgid "Verify SSL" msgstr "Bekräfta SSL" -#: src/Module/Admin/Site.php:572 +#: src/Module/Admin/Site.php:506 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:573 +#: src/Module/Admin/Site.php:507 msgid "Proxy user" msgstr "Proxy-användare" -#: src/Module/Admin/Site.php:574 +#: src/Module/Admin/Site.php:507 +msgid "User name for the proxy server." +msgstr "" + +#: src/Module/Admin/Site.php:508 msgid "Proxy URL" msgstr "URL för proxy" -#: src/Module/Admin/Site.php:575 +#: src/Module/Admin/Site.php:508 +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:509 msgid "Network timeout" msgstr "Tidsgräns för nätverket" -#: src/Module/Admin/Site.php:575 +#: src/Module/Admin/Site.php:509 msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." msgstr "Värdet är i sekunder. Ställ in det till 0 för obegränsat (rekommenderas inte)." -#: src/Module/Admin/Site.php:576 +#: src/Module/Admin/Site.php:510 msgid "Maximum Load Average" msgstr "" -#: src/Module/Admin/Site.php:576 +#: src/Module/Admin/Site.php:510 #, php-format msgid "" "Maximum system load before delivery and poll processes are deferred - " "default %d." msgstr "" -#: src/Module/Admin/Site.php:577 +#: src/Module/Admin/Site.php:511 msgid "Minimal Memory" msgstr "" -#: src/Module/Admin/Site.php:577 +#: src/Module/Admin/Site.php:511 msgid "" "Minimal free memory in MB for the worker. Needs access to /proc/meminfo - " "default 0 (deactivated)." msgstr "" -#: src/Module/Admin/Site.php:578 +#: src/Module/Admin/Site.php:512 msgid "Periodically optimize tables" msgstr "" -#: src/Module/Admin/Site.php:578 +#: src/Module/Admin/Site.php:512 msgid "Periodically optimize tables like the cache and the workerqueue" msgstr "" -#: src/Module/Admin/Site.php:580 +#: src/Module/Admin/Site.php:514 msgid "Discover followers/followings from contacts" msgstr "" -#: src/Module/Admin/Site.php:580 +#: src/Module/Admin/Site.php:514 msgid "" "If enabled, contacts are checked for their followers and following contacts." msgstr "" -#: src/Module/Admin/Site.php:581 +#: src/Module/Admin/Site.php:515 msgid "None - deactivated" msgstr "" -#: src/Module/Admin/Site.php:582 +#: src/Module/Admin/Site.php:516 msgid "" "Local contacts - contacts of our local contacts are discovered for their " "followers/followings." msgstr "" -#: src/Module/Admin/Site.php:583 +#: src/Module/Admin/Site.php:517 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:585 +#: src/Module/Admin/Site.php:519 msgid "Synchronize the contacts with the directory server" msgstr "" -#: src/Module/Admin/Site.php:585 +#: src/Module/Admin/Site.php:519 msgid "" "if enabled, the system will check periodically for new contacts on the " "defined directory server." msgstr "" -#: src/Module/Admin/Site.php:587 +#: src/Module/Admin/Site.php:521 msgid "Days between requery" msgstr "" -#: src/Module/Admin/Site.php:587 +#: src/Module/Admin/Site.php:521 msgid "Number of days after which a server is requeried for his contacts." msgstr "" -#: src/Module/Admin/Site.php:588 +#: src/Module/Admin/Site.php:522 msgid "Discover contacts from other servers" msgstr "" -#: src/Module/Admin/Site.php:588 +#: src/Module/Admin/Site.php:522 msgid "" "Periodically query other servers for contacts. The system queries Friendica," " Mastodon and Hubzilla servers." msgstr "" -#: src/Module/Admin/Site.php:589 +#: src/Module/Admin/Site.php:523 msgid "Search the local directory" msgstr "" -#: src/Module/Admin/Site.php:589 +#: src/Module/Admin/Site.php:523 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:591 +#: src/Module/Admin/Site.php:525 msgid "Publish server information" msgstr "" -#: src/Module/Admin/Site.php:591 +#: src/Module/Admin/Site.php:525 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 " @@ -6105,50 +5767,50 @@ msgid "" " href=\"http://the-federation.info/\">the-federation.info for details." msgstr "" -#: src/Module/Admin/Site.php:593 +#: src/Module/Admin/Site.php:527 msgid "Check upstream version" msgstr "" -#: src/Module/Admin/Site.php:593 +#: src/Module/Admin/Site.php:527 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:594 +#: src/Module/Admin/Site.php:528 msgid "Suppress Tags" msgstr "" -#: src/Module/Admin/Site.php:594 +#: src/Module/Admin/Site.php:528 msgid "Suppress showing a list of hashtags at the end of the posting." msgstr "" -#: src/Module/Admin/Site.php:595 +#: src/Module/Admin/Site.php:529 msgid "Clean database" msgstr "" -#: src/Module/Admin/Site.php:595 +#: src/Module/Admin/Site.php:529 msgid "" "Remove old remote items, orphaned database records and old content from some" " other helper tables." msgstr "" -#: src/Module/Admin/Site.php:596 +#: src/Module/Admin/Site.php:530 msgid "Lifespan of remote items" msgstr "" -#: src/Module/Admin/Site.php:596 +#: src/Module/Admin/Site.php:530 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:597 +#: src/Module/Admin/Site.php:531 msgid "Lifespan of unclaimed items" msgstr "" -#: src/Module/Admin/Site.php:597 +#: src/Module/Admin/Site.php:531 msgid "" "When the database cleanup is enabled, this defines the days after which " "unclaimed remote items (mostly content from the relay) will be deleted. " @@ -6156,144 +5818,134 @@ msgid "" "items if set to 0." msgstr "" -#: src/Module/Admin/Site.php:598 +#: src/Module/Admin/Site.php:532 msgid "Lifespan of raw conversation data" msgstr "" -#: src/Module/Admin/Site.php:598 +#: src/Module/Admin/Site.php:532 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:599 +#: src/Module/Admin/Site.php:533 msgid "Maximum numbers of comments per post" msgstr "" -#: src/Module/Admin/Site.php:599 +#: src/Module/Admin/Site.php:533 msgid "How much comments should be shown for each post? Default value is 100." msgstr "" -#: src/Module/Admin/Site.php:600 +#: src/Module/Admin/Site.php:534 msgid "Maximum numbers of comments per post on the display page" msgstr "" -#: src/Module/Admin/Site.php:600 +#: src/Module/Admin/Site.php:534 msgid "" "How many comments should be shown on the single view for each post? Default " "value is 1000." msgstr "" -#: src/Module/Admin/Site.php:601 +#: src/Module/Admin/Site.php:535 msgid "Temp path" msgstr "Tillfällig genväg" -#: src/Module/Admin/Site.php:601 +#: src/Module/Admin/Site.php:535 msgid "" "If you have a restricted system where the webserver can't access the system " "temp path, enter another path here." msgstr "" -#: src/Module/Admin/Site.php:602 +#: src/Module/Admin/Site.php:536 msgid "Only search in tags" msgstr "Sök endast i taggar" -#: src/Module/Admin/Site.php:602 +#: src/Module/Admin/Site.php:536 msgid "On large systems the text search can slow down the system extremely." msgstr "" -#: src/Module/Admin/Site.php:604 -msgid "New base url" -msgstr "" - -#: src/Module/Admin/Site.php:604 -msgid "" -"Change base url for this server. Sends relocate message to all Friendica and" -" Diaspora* contacts of all users." -msgstr "" - -#: src/Module/Admin/Site.php:606 +#: src/Module/Admin/Site.php:538 msgid "Maximum number of parallel workers" msgstr "" -#: src/Module/Admin/Site.php:606 +#: src/Module/Admin/Site.php:538 #, 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:607 +#: src/Module/Admin/Site.php:539 msgid "Enable fastlane" msgstr "" -#: src/Module/Admin/Site.php:607 +#: src/Module/Admin/Site.php:539 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:609 +#: src/Module/Admin/Site.php:541 msgid "Direct relay transfer" msgstr "" -#: src/Module/Admin/Site.php:609 +#: src/Module/Admin/Site.php:541 msgid "" "Enables the direct transfer to other servers without using the relay servers" msgstr "" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 msgid "Relay scope" msgstr "" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 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:610 src/Module/Contact/Profile.php:273 -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Admin/Site.php:542 src/Module/Contact/Profile.php:273 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Disabled" msgstr "" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 msgid "all" msgstr "" -#: src/Module/Admin/Site.php:610 +#: src/Module/Admin/Site.php:542 msgid "tags" msgstr "" -#: src/Module/Admin/Site.php:611 +#: src/Module/Admin/Site.php:543 msgid "Server tags" msgstr "" -#: src/Module/Admin/Site.php:611 +#: src/Module/Admin/Site.php:543 msgid "Comma separated list of tags for the \"tags\" subscription." msgstr "" -#: src/Module/Admin/Site.php:612 +#: src/Module/Admin/Site.php:544 msgid "Deny Server tags" msgstr "" -#: src/Module/Admin/Site.php:612 +#: src/Module/Admin/Site.php:544 msgid "Comma separated list of tags that are rejected." msgstr "" -#: src/Module/Admin/Site.php:613 +#: src/Module/Admin/Site.php:545 msgid "Allow user tags" msgstr "" -#: src/Module/Admin/Site.php:613 +#: src/Module/Admin/Site.php:545 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:616 +#: src/Module/Admin/Site.php:548 msgid "Start Relocation" msgstr "" @@ -6319,7 +5971,7 @@ msgstr "" msgid "Storage Configuration" msgstr "" -#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:91 +#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:94 msgid "Storage" msgstr "" @@ -6343,12 +5995,12 @@ msgstr "" msgid "Database (legacy)" msgstr "" -#: src/Module/Admin/Summary.php:53 +#: src/Module/Admin/Summary.php:54 #, php-format msgid "Template engine (%s) error: %s" msgstr "" -#: src/Module/Admin/Summary.php:57 +#: src/Module/Admin/Summary.php:58 #, php-format msgid "" "Your DB still runs with MyISAM tables. You should change the engine type to " @@ -6359,7 +6011,7 @@ msgid "" " an automatic conversion.
" msgstr "" -#: src/Module/Admin/Summary.php:62 +#: src/Module/Admin/Summary.php:63 #, php-format msgid "" "Your DB still runs with InnoDB tables in the Antelope file format. You " @@ -6370,7 +6022,7 @@ msgid "" " installation for an automatic conversion.
" msgstr "" -#: src/Module/Admin/Summary.php:72 +#: src/Module/Admin/Summary.php:73 #, php-format msgid "" "Your table_definition_cache is too low (%d). This can lead to the database " @@ -6378,39 +6030,39 @@ msgid "" " to %d. See here for more information.
" msgstr "" -#: src/Module/Admin/Summary.php:82 +#: src/Module/Admin/Summary.php:83 #, 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:91 +#: src/Module/Admin/Summary.php:92 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 "" -#: src/Module/Admin/Summary.php:95 +#: src/Module/Admin/Summary.php:96 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:100 +#: src/Module/Admin/Summary.php:101 msgid "The worker was never executed. Please check your database structure!" msgstr "" -#: src/Module/Admin/Summary.php:102 +#: src/Module/Admin/Summary.php:103 #, php-format msgid "" "The last worker execution was on %s UTC. This is older than one hour. Please" " check your crontab settings." msgstr "" -#: src/Module/Admin/Summary.php:107 +#: src/Module/Admin/Summary.php:108 #, php-format msgid "" "Friendica's configuration now is stored in config/local.config.php, please " @@ -6419,7 +6071,7 @@ msgid "" "help with the transition." msgstr "" -#: src/Module/Admin/Summary.php:111 +#: src/Module/Admin/Summary.php:112 #, php-format msgid "" "Friendica's configuration now is stored in config/local.config.php, please " @@ -6428,7 +6080,7 @@ msgid "" "page for help with the transition." msgstr "" -#: src/Module/Admin/Summary.php:117 +#: src/Module/Admin/Summary.php:118 #, php-format msgid "" "%s is not reachable on your system. This is a severe " @@ -6436,83 +6088,83 @@ msgid "" "href=\"%s\">the installation page for help." msgstr "" -#: src/Module/Admin/Summary.php:135 +#: src/Module/Admin/Summary.php:136 #, php-format msgid "The logfile '%s' is not usable. No logging possible (error: '%s')" msgstr "" -#: src/Module/Admin/Summary.php:149 +#: src/Module/Admin/Summary.php:150 #, php-format msgid "" "The debug logfile '%s' is not usable. No logging possible (error: '%s')" msgstr "" -#: src/Module/Admin/Summary.php:165 +#: src/Module/Admin/Summary.php:166 #, 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:173 +#: src/Module/Admin/Summary.php:174 #, 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:181 +#: src/Module/Admin/Summary.php:182 #, 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:188 +#: src/Module/Admin/Summary.php:189 msgid "Normal Account" msgstr "Vanligt konto" -#: src/Module/Admin/Summary.php:189 +#: src/Module/Admin/Summary.php:190 msgid "Automatic Follower Account" msgstr "" -#: src/Module/Admin/Summary.php:190 +#: src/Module/Admin/Summary.php:191 msgid "Public Forum Account" msgstr "" -#: src/Module/Admin/Summary.php:191 +#: src/Module/Admin/Summary.php:192 msgid "Automatic Friend Account" msgstr "Konto med automatiskt godkännande av vänner." -#: src/Module/Admin/Summary.php:192 +#: src/Module/Admin/Summary.php:193 msgid "Blog Account" msgstr "Blogg-konto" -#: src/Module/Admin/Summary.php:193 +#: src/Module/Admin/Summary.php:194 msgid "Private Forum Account" msgstr "" -#: src/Module/Admin/Summary.php:213 +#: src/Module/Admin/Summary.php:214 msgid "Message queues" msgstr "Meddelandeköer" -#: src/Module/Admin/Summary.php:219 +#: src/Module/Admin/Summary.php:220 msgid "Server Settings" msgstr "" -#: src/Module/Admin/Summary.php:235 +#: src/Module/Admin/Summary.php:236 msgid "Registered users" msgstr "Registrerade användare" -#: src/Module/Admin/Summary.php:237 +#: src/Module/Admin/Summary.php:238 msgid "Pending registrations" msgstr "Väntande registreringar" -#: src/Module/Admin/Summary.php:238 +#: src/Module/Admin/Summary.php:239 msgid "Version" msgstr "Version" -#: src/Module/Admin/Summary.php:242 +#: src/Module/Admin/Summary.php:243 msgid "Active addons" msgstr "" @@ -6536,11 +6188,11 @@ msgid "Screenshot" msgstr "Skärmdump" #: src/Module/Admin/Themes/Details.php:91 -#: src/Module/Admin/Themes/Index.php:112 src/Module/BaseAdmin.php:94 +#: src/Module/Admin/Themes/Index.php:112 src/Module/BaseAdmin.php:97 msgid "Themes" msgstr "Teman" -#: src/Module/Admin/Themes/Embed.php:79 +#: src/Module/Admin/Themes/Embed.php:80 msgid "Unknown theme." msgstr "" @@ -6740,7 +6392,7 @@ msgid "Permanent deletion" msgstr "" #: src/Module/Admin/Users/Index.php:150 src/Module/Admin/Users/Index.php:160 -#: src/Module/BaseAdmin.php:92 +#: src/Module/BaseAdmin.php:95 msgid "Users" msgstr "Användare" @@ -6812,11 +6464,6 @@ msgstr "" msgid "Only starting posts can be muted" msgstr "" -#: src/Module/Api/Mastodon/Statuses/Pin.php:50 -#: src/Module/Api/Mastodon/Statuses/Unpin.php:50 -msgid "Only starting posts can be pinned" -msgstr "" - #: src/Module/Api/Mastodon/Statuses/Reblog.php:53 #, php-format msgid "Posts from %s can't be shared" @@ -6847,93 +6494,93 @@ msgstr "Inga installerade applikationer." msgid "Applications" msgstr "Applikationer" -#: src/Module/Attach.php:49 src/Module/Attach.php:61 +#: src/Module/Attach.php:50 src/Module/Attach.php:62 msgid "Item was not found." msgstr "Objektet hittades inte." -#: src/Module/BaseAdmin.php:54 src/Module/BaseAdmin.php:58 +#: src/Module/BaseAdmin.php:57 src/Module/BaseAdmin.php:61 msgid "Please login to continue." msgstr "Vänligen logga in för att fortsätta." -#: src/Module/BaseAdmin.php:63 +#: src/Module/BaseAdmin.php:66 msgid "You don't have access to administration pages." msgstr "" -#: src/Module/BaseAdmin.php:67 +#: src/Module/BaseAdmin.php:70 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/BaseAdmin.php:89 msgid "Overview" msgstr "" -#: src/Module/BaseAdmin.php:89 +#: src/Module/BaseAdmin.php:92 msgid "Configuration" msgstr "" -#: src/Module/BaseAdmin.php:95 src/Module/BaseSettings.php:63 +#: src/Module/BaseAdmin.php:98 src/Module/BaseSettings.php:63 msgid "Additional features" msgstr "Ytterligare funktioner" -#: src/Module/BaseAdmin.php:98 +#: src/Module/BaseAdmin.php:101 msgid "Database" msgstr "" -#: src/Module/BaseAdmin.php:99 +#: src/Module/BaseAdmin.php:102 msgid "DB updates" msgstr "DB-uppdateringar" -#: src/Module/BaseAdmin.php:100 +#: src/Module/BaseAdmin.php:103 msgid "Inspect Deferred Workers" msgstr "" -#: src/Module/BaseAdmin.php:101 +#: src/Module/BaseAdmin.php:104 msgid "Inspect worker Queue" msgstr "" -#: src/Module/BaseAdmin.php:103 +#: src/Module/BaseAdmin.php:106 msgid "Tools" msgstr "" -#: src/Module/BaseAdmin.php:104 +#: src/Module/BaseAdmin.php:107 msgid "Contact Blocklist" msgstr "" -#: src/Module/BaseAdmin.php:105 +#: src/Module/BaseAdmin.php:108 msgid "Server Blocklist" msgstr "" -#: src/Module/BaseAdmin.php:112 +#: src/Module/BaseAdmin.php:115 msgid "Diagnostics" msgstr "" -#: src/Module/BaseAdmin.php:113 +#: src/Module/BaseAdmin.php:116 msgid "PHP Info" msgstr "" -#: src/Module/BaseAdmin.php:114 +#: src/Module/BaseAdmin.php:117 msgid "probe address" msgstr "" -#: src/Module/BaseAdmin.php:115 +#: src/Module/BaseAdmin.php:118 msgid "check webfinger" msgstr "" -#: src/Module/BaseAdmin.php:117 +#: src/Module/BaseAdmin.php:120 msgid "Babel" msgstr "" -#: src/Module/BaseAdmin.php:118 src/Module/Debug/ActivityPubConversion.php:138 +#: src/Module/BaseAdmin.php:121 src/Module/Debug/ActivityPubConversion.php:142 msgid "ActivityPub Conversion" msgstr "" -#: src/Module/BaseAdmin.php:127 +#: src/Module/BaseAdmin.php:130 msgid "Addon Features" msgstr "" -#: src/Module/BaseAdmin.php:128 +#: src/Module/BaseAdmin.php:131 msgid "User registrations waiting for confirmation" msgstr "Användarens registreringar väntar på bekräftelse" @@ -6982,12 +6629,12 @@ msgstr "" msgid "Tips for New Members" msgstr "Tips för nya medlemmar" -#: src/Module/BaseSearch.php:68 +#: src/Module/BaseSearch.php:69 #, php-format msgid "People Search - %s" msgstr "" -#: src/Module/BaseSearch.php:78 +#: src/Module/BaseSearch.php:79 #, php-format msgid "Forum Search - %s" msgstr "" @@ -6996,8 +6643,8 @@ msgstr "" msgid "Account" msgstr "Konto" -#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:95 -#: src/Module/Settings/TwoFactor/Index.php:110 +#: src/Module/BaseSettings.php:48 src/Module/Security/TwoFactor/Verify.php:96 +#: src/Module/Settings/TwoFactor/Index.php:113 msgid "Two-factor authentication" msgstr "" @@ -7013,7 +6660,7 @@ msgstr "" msgid "Connected apps" msgstr "Anslutna appar" -#: src/Module/BaseSettings.php:106 src/Module/Settings/UserExport.php:75 +#: src/Module/BaseSettings.php:106 src/Module/Settings/UserExport.php:76 msgid "Export personal data" msgstr "Exporter personlig data" @@ -7049,7 +6696,7 @@ msgid "Only show blocked contacts" msgstr "Visa endast blockerade kontakter" #: src/Module/Contact.php:330 src/Module/Contact.php:377 -#: src/Object/Post.php:309 +#: src/Object/Post.php:339 msgid "Ignored" msgstr "Ignorerade" @@ -7081,7 +6728,7 @@ msgstr "" msgid "Search your contacts" msgstr "Sök dina kontakter" -#: src/Module/Contact.php:390 src/Module/Search/Index.php:191 +#: src/Module/Contact.php:390 src/Module/Search/Index.php:207 #, php-format msgid "Results for: %s" msgstr "" @@ -7133,11 +6780,11 @@ msgstr "du är fan till" #: src/Module/Contact.php:537 msgid "Pending outgoing contact request" -msgstr "" +msgstr "Väntande utgående kontaktbegäran" #: src/Module/Contact.php:539 msgid "Pending incoming contact request" -msgstr "" +msgstr "Väntande inkommande kontaktbegäran" #: src/Module/Contact.php:552 src/Module/Contact/Profile.php:334 #, php-format @@ -7175,32 +6822,32 @@ msgstr "Ogiltig kontakt." #: src/Module/Contact/Contacts.php:73 msgid "No known contacts." -msgstr "" +msgstr "Inga kända kontakter." #: src/Module/Contact/Contacts.php:87 src/Module/Profile/Common.php:98 msgid "No common contacts." -msgstr "" +msgstr "Inga gemensamma kontakter." #: src/Module/Contact/Contacts.php:99 src/Module/Profile/Contacts.php:96 #, php-format msgid "Follower (%s)" msgid_plural "Followers (%s)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Följare (%s)" +msgstr[1] "Följare (%s)" #: src/Module/Contact/Contacts.php:103 src/Module/Profile/Contacts.php:99 #, php-format msgid "Following (%s)" msgid_plural "Following (%s)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Följer (%s)" +msgstr[1] "Följer (%s)" #: src/Module/Contact/Contacts.php:107 src/Module/Profile/Contacts.php:102 #, php-format msgid "Mutual friend (%s)" msgid_plural "Mutual friends (%s)" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Gemensam vän (%s)" +msgstr[1] "Gemensamma vänner (%s)" #: src/Module/Contact/Contacts.php:109 src/Module/Profile/Contacts.php:104 #, php-format @@ -7232,7 +6879,7 @@ msgstr[1] "" msgid "Error while sending poke, please retry." msgstr "" -#: src/Module/Contact/Poke.php:148 src/Module/Search/Acl.php:54 +#: src/Module/Contact/Poke.php:148 src/Module/Search/Acl.php:55 msgid "You must be logged in to use this module." msgstr "" @@ -7367,11 +7014,11 @@ msgstr "" #: src/Module/Contact/Profile.php:325 msgid "Contact" -msgstr "" +msgstr "Kontakt" #: src/Module/Contact/Profile.php:329 msgid "Their personal note" -msgstr "" +msgstr "Deras personliga anteckning" #: src/Module/Contact/Profile.php:331 msgid "Edit contact notes" @@ -7446,7 +7093,7 @@ msgid "" msgstr "" #: src/Module/Contact/Profile.php:378 -#: src/Module/Settings/TwoFactor/Index.php:132 +#: src/Module/Settings/TwoFactor/Index.php:135 msgid "Actions" msgstr "" @@ -7472,7 +7119,7 @@ msgstr "" msgid "Toggle Ignored status" msgstr "" -#: src/Module/Contact/Profile.php:466 src/Module/Contact/Revoke.php:107 +#: src/Module/Contact/Profile.php:466 src/Module/Contact/Revoke.php:105 msgid "Revoke Follow" msgstr "" @@ -7480,43 +7127,32 @@ msgstr "" msgid "Revoke the follow from this contact" msgstr "" -#: src/Module/Contact/Revoke.php:59 +#: src/Module/Contact/Revoke.php:62 msgid "Unknown contact." msgstr "" -#: src/Module/Contact/Revoke.php:69 src/Module/Group.php:112 +#: src/Module/Contact/Revoke.php:72 src/Module/Group.php:112 msgid "Contact is deleted." msgstr "" -#: src/Module/Contact/Revoke.php:73 +#: src/Module/Contact/Revoke.php:76 msgid "Contact is being deleted." msgstr "" -#: src/Module/Contact/Revoke.php:87 +#: src/Module/Contact/Revoke.php:90 msgid "Follow was successfully revoked." msgstr "" -#: src/Module/Contact/Revoke.php:89 -msgid "" -"Follow was successfully revoked, however the remote contact won't be aware " -"of this revokation." -msgstr "" - -#: src/Module/Contact/Revoke.php:91 -msgid "" -"Unable to revoke follow, please try again later or contact the " -"administrator." -msgstr "" - -#: src/Module/Contact/Revoke.php:108 +#: src/Module/Contact/Revoke.php:106 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:109 +#: src/Module/Contact/Revoke.php:107 #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:53 src/Module/Register.php:130 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "Yes" msgstr "Ja" @@ -7538,18 +7174,18 @@ msgstr "" #: src/Module/Conversation/Community.php:115 msgid "Own Contacts" -msgstr "" +msgstr "Egna kontakter" #: src/Module/Conversation/Community.php:119 msgid "Include" -msgstr "" +msgstr "Inkludera" #: src/Module/Conversation/Community.php:120 msgid "Hide" -msgstr "" +msgstr "Dölj" -#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:136 -#: src/Module/Search/Index.php:178 +#: src/Module/Conversation/Community.php:137 src/Module/Search/Index.php:152 +#: src/Module/Search/Index.php:194 msgid "No results." msgstr "Inga resultat." @@ -7576,36 +7212,44 @@ msgstr "Gruppen finns inte" msgid "Group: %s" msgstr "Grupp: %s" -#: src/Module/Conversation/Network.php:253 +#: src/Module/Conversation/Network.php:255 msgid "Latest Activity" msgstr "" -#: src/Module/Conversation/Network.php:256 +#: src/Module/Conversation/Network.php:258 msgid "Sort by latest activity" msgstr "" -#: src/Module/Conversation/Network.php:261 +#: src/Module/Conversation/Network.php:263 msgid "Latest Posts" msgstr "" -#: src/Module/Conversation/Network.php:264 +#: src/Module/Conversation/Network.php:266 msgid "Sort by post received date" msgstr "" -#: src/Module/Conversation/Network.php:269 +#: src/Module/Conversation/Network.php:271 +msgid "Latest Creation" +msgstr "" + +#: src/Module/Conversation/Network.php:274 +msgid "Sort by post creation date" +msgstr "" + +#: src/Module/Conversation/Network.php:279 #: src/Module/Settings/Profile/Index.php:227 msgid "Personal" msgstr "Privat" -#: src/Module/Conversation/Network.php:272 +#: src/Module/Conversation/Network.php:282 msgid "Posts that mention or involve you" msgstr "Inlägg som nämnde eller involverade dig" -#: src/Module/Conversation/Network.php:277 src/Object/Post.php:321 +#: src/Module/Conversation/Network.php:287 src/Object/Post.php:351 msgid "Starred" msgstr "Stjärnmärkt" -#: src/Module/Conversation/Network.php:280 +#: src/Module/Conversation/Network.php:290 msgid "Favourite Posts" msgstr "Favoriserade inlägg" @@ -7628,15 +7272,15 @@ msgstr "" msgid "Activity" msgstr "" -#: src/Module/Debug/ActivityPubConversion.php:118 +#: src/Module/Debug/ActivityPubConversion.php:122 msgid "Object data" msgstr "" -#: src/Module/Debug/ActivityPubConversion.php:125 +#: src/Module/Debug/ActivityPubConversion.php:129 msgid "Result Item" msgstr "" -#: src/Module/Debug/ActivityPubConversion.php:139 +#: src/Module/Debug/ActivityPubConversion.php:143 msgid "Source activity" msgstr "" @@ -7816,12 +7460,12 @@ msgstr "" msgid "Twitter Source / Tweet URL (requires API key)" msgstr "" -#: src/Module/Debug/Feed.php:50 src/Module/Filer/SaveTag.php:46 +#: src/Module/Debug/Feed.php:51 src/Module/Filer/SaveTag.php:46 #: src/Module/Settings/Profile/Index.php:141 msgid "You must be logged in to use this module" -msgstr "" +msgstr "Du måste vara inloggad för att använda denna modul" -#: src/Module/Debug/Feed.php:75 +#: src/Module/Debug/Feed.php:76 msgid "Source URL" msgstr "" @@ -7881,15 +7525,15 @@ msgstr "" #: src/Module/Delegation.php:111 #, php-format msgid "You are now logged in as %s" -msgstr "" +msgstr "Du är nu inloggad som %s" #: src/Module/Delegation.php:143 msgid "Switch between your accounts" -msgstr "" +msgstr "Växla mellan dina konton" #: src/Module/Delegation.php:144 msgid "Manage your accounts" -msgstr "" +msgstr "Hantera dina konton" #: src/Module/Delegation.php:145 msgid "" @@ -7901,19 +7545,19 @@ msgstr "" msgid "Select an identity to manage: " msgstr "Välj vilken identitet du vill hantera: " -#: src/Module/Directory.php:74 +#: src/Module/Directory.php:75 msgid "No entries (some entries may be hidden)." msgstr "Inget att visa. (Man kan välja att inte synas här)" -#: src/Module/Directory.php:90 +#: src/Module/Directory.php:91 msgid "Find on this site" msgstr "Hitta på den här sidan" -#: src/Module/Directory.php:92 +#: src/Module/Directory.php:93 msgid "Results for:" msgstr "" -#: src/Module/Directory.php:94 +#: src/Module/Directory.php:95 msgid "Site Directory" msgstr "Medlemskatalog" @@ -8242,40 +7886,40 @@ msgid "" " administrator email. This will allow you to enter the site admin panel." msgstr "" -#: src/Module/Invite.php:56 +#: src/Module/Invite.php:57 msgid "Total invitation limit exceeded." msgstr "" -#: src/Module/Invite.php:81 +#: src/Module/Invite.php:82 #, php-format msgid "%s : Not a valid email address." msgstr "%s : Ogiltig e-postadress." -#: src/Module/Invite.php:107 +#: src/Module/Invite.php:108 msgid "Please join us on Friendica" msgstr "" -#: src/Module/Invite.php:116 +#: src/Module/Invite.php:117 msgid "Invitation limit exceeded. Please contact your site administrator." msgstr "" -#: src/Module/Invite.php:120 +#: src/Module/Invite.php:121 #, php-format msgid "%s : Message delivery failed." msgstr "%s : Meddelandet kom inte fram." -#: src/Module/Invite.php:124 +#: src/Module/Invite.php:125 #, php-format msgid "%d message sent." msgid_plural "%d messages sent." msgstr[0] "%d meddelande har skickats." msgstr[1] "%d meddelanden har skickats." -#: src/Module/Invite.php:142 +#: src/Module/Invite.php:143 msgid "You have no more invitations available" msgstr "Du har inga fler inbjudningar tillgängliga" -#: src/Module/Invite.php:149 +#: src/Module/Invite.php:150 #, php-format msgid "" "Visit %s for a list of public sites that you can join. Friendica members on " @@ -8283,14 +7927,14 @@ msgid "" " other social networks." msgstr "" -#: src/Module/Invite.php:151 +#: 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 "" -#: src/Module/Invite.php:152 +#: src/Module/Invite.php:153 #, php-format msgid "" "Friendica sites all inter-connect to create a huge privacy-enhanced social " @@ -8299,48 +7943,48 @@ msgid "" "sites you can join." msgstr "" -#: src/Module/Invite.php:156 +#: 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:159 +#: 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:158 +#: src/Module/Invite.php:159 #, php-format msgid "To accept this invitation, please visit and register at %s." msgstr "" -#: src/Module/Invite.php:166 +#: src/Module/Invite.php:167 msgid "Send invitations" msgstr "Skicka inbjudningar" -#: src/Module/Invite.php:167 +#: src/Module/Invite.php:168 msgid "Enter email addresses, one per line:" msgstr "Ange e-postadresser, en per rad:" -#: src/Module/Invite.php:171 +#: 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:173 +#: src/Module/Invite.php:174 msgid "You will need to supply this invitation code: $invite_code" msgstr "" -#: src/Module/Invite.php:173 +#: src/Module/Invite.php:174 msgid "" "Once you have registered, please connect with me via my profile page at:" msgstr "Vi kan bli kontakter via min profil. Besök min profil här när du har registrerat dig:" -#: src/Module/Invite.php:175 +#: 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" @@ -8362,19 +8006,19 @@ msgstr "" msgid "Compose new post" msgstr "" -#: src/Module/Item/Compose.php:141 +#: src/Module/Item/Compose.php:153 msgid "Visibility" msgstr "" -#: src/Module/Item/Compose.php:162 +#: src/Module/Item/Compose.php:174 msgid "Clear the location" msgstr "" -#: src/Module/Item/Compose.php:163 +#: src/Module/Item/Compose.php:175 msgid "Location services are unavailable on your device" msgstr "" -#: src/Module/Item/Compose.php:164 +#: src/Module/Item/Compose.php:176 msgid "" "Location services are disabled. Please check the website's permissions on " "your device" @@ -8395,7 +8039,7 @@ msgid "" "condition should be temporary, please come back in a few minutes." msgstr "" -#: src/Module/Manifest.php:42 +#: src/Module/Manifest.php:40 msgid "A Decentralized Social Network" msgstr "" @@ -8422,6 +8066,7 @@ msgstr "Hävdar att du vet vem han/hon är: " #: src/Module/Notifications/Introductions.php:142 #: src/Module/OAuth/Acknowledge.php:54 src/Module/Register.php:131 +#: src/Module/Settings/TwoFactor/Trusted.php:124 msgid "No" msgstr "Nej" @@ -8461,7 +8106,7 @@ msgstr "Inga presentationer." msgid "No more %s notifications." msgstr "" -#: src/Module/Notifications/Notification.php:107 +#: src/Module/Notifications/Notification.php:134 msgid "You must be logged in to show this page." msgstr "" @@ -8485,6 +8130,15 @@ msgstr "Hem-aviseringar" msgid "Show unread" msgstr "" +#: src/Module/Notifications/Ping.php:221 +msgid "{0} requested registration" +msgstr "{0} bad om registrering" + +#: src/Module/Notifications/Ping.php:232 +#, php-format +msgid "{0} and %d others requested registration" +msgstr "{0} och %d andra bad om registrering" + #: src/Module/OAuth/Acknowledge.php:50 msgid "Authorize application connection" msgstr "" @@ -8514,38 +8168,72 @@ msgstr "" msgid "Unsupported or missing grant type" msgstr "" -#: src/Module/PermissionTooltip.php:44 +#: src/Module/PermissionTooltip.php:49 #, php-format msgid "Wrong type \"%s\", expected one of: %s" msgstr "" -#: src/Module/PermissionTooltip.php:61 +#: src/Module/PermissionTooltip.php:66 msgid "Model not found" msgstr "" -#: src/Module/PermissionTooltip.php:83 +#: src/Module/PermissionTooltip.php:89 +msgid "Unlisted" +msgstr "" + +#: src/Module/PermissionTooltip.php:107 msgid "Remote privacy information not available." msgstr "Remote privacy information not available." -#: src/Module/PermissionTooltip.php:92 +#: src/Module/PermissionTooltip.php:116 msgid "Visible to:" msgstr "Synlig för:" -#: src/Module/Photo.php:123 +#: src/Module/PermissionTooltip.php:200 +#, php-format +msgid "Collection (%s)" +msgstr "" + +#: src/Module/PermissionTooltip.php:204 +#, php-format +msgid "Followers (%s)" +msgstr "" + +#: src/Module/PermissionTooltip.php:223 +#, php-format +msgid "%d more" +msgstr "" + +#: src/Module/PermissionTooltip.php:227 +#, php-format +msgid "To: %s
" +msgstr "" + +#: src/Module/PermissionTooltip.php:230 +#, php-format +msgid "CC: %s
" +msgstr "" + +#: src/Module/PermissionTooltip.php:233 +#, php-format +msgid "BCC: %s
" +msgstr "" + +#: src/Module/Photo.php:128 msgid "The Photo is not available." msgstr "" -#: src/Module/Photo.php:136 +#: src/Module/Photo.php:141 #, php-format msgid "The Photo with id %s is not available." msgstr "" -#: src/Module/Photo.php:169 +#: src/Module/Photo.php:174 #, php-format msgid "Invalid external resource with url %s." msgstr "" -#: src/Module/Photo.php:171 +#: src/Module/Photo.php:176 #, php-format msgid "Invalid photo with id %s." msgstr "" @@ -8565,6 +8253,10 @@ msgid "" "class=\"btn btn-sm pull-right\">Cancel" msgstr "" +#: src/Module/Profile/Profile.php:144 src/Module/Settings/Account.php:575 +msgid "Full Name:" +msgstr "Fullständigt namn:" + #: src/Module/Profile/Profile.php:149 msgid "Member since:" msgstr "" @@ -8607,20 +8299,20 @@ msgid "View as" msgstr "" #: src/Module/Profile/Profile.php:326 src/Module/Profile/Profile.php:329 -#: src/Module/Profile/Status.php:65 src/Module/Profile/Status.php:68 -#: src/Protocol/Feed.php:985 src/Protocol/OStatus.php:1242 +#: src/Module/Profile/Status.php:66 src/Module/Profile/Status.php:69 +#: src/Protocol/Feed.php:1018 src/Protocol/OStatus.php:1276 #, php-format msgid "%s's timeline" msgstr "" -#: src/Module/Profile/Profile.php:327 src/Module/Profile/Status.php:66 -#: src/Protocol/Feed.php:989 src/Protocol/OStatus.php:1246 +#: src/Module/Profile/Profile.php:327 src/Module/Profile/Status.php:67 +#: src/Protocol/Feed.php:1022 src/Protocol/OStatus.php:1281 #, php-format msgid "%s's posts" msgstr "" -#: src/Module/Profile/Profile.php:328 src/Module/Profile/Status.php:67 -#: src/Protocol/Feed.php:992 src/Protocol/OStatus.php:1249 +#: src/Module/Profile/Profile.php:328 src/Module/Profile/Status.php:68 +#: src/Protocol/Feed.php:1025 src/Protocol/OStatus.php:1285 #, php-format msgid "%s's comments" msgstr "" @@ -8691,10 +8383,18 @@ msgstr "" msgid "Please repeat your e-mail address:" msgstr "" +#: src/Module/Register.php:162 src/Module/Settings/Account.php:566 +msgid "New Password:" +msgstr "Nytt lösenord" + #: src/Module/Register.php:162 msgid "Leave empty for an auto generated password." msgstr "" +#: src/Module/Register.php:163 src/Module/Settings/Account.php:567 +msgid "Confirm:" +msgstr "Bekräfta (repetera):" + #: src/Module/Register.php:164 #, php-format msgid "" @@ -8812,15 +8512,15 @@ msgstr "" msgid "Your Webfinger address or profile URL:" msgstr "" -#: src/Module/Search/Index.php:53 +#: src/Module/Search/Index.php:69 msgid "Only logged in users are permitted to perform a search." msgstr "" -#: src/Module/Search/Index.php:73 +#: 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:189 +#: src/Module/Search/Index.php:205 #, php-format msgid "Items tagged with: %s" msgstr "" @@ -8883,7 +8583,11 @@ msgstr "Integritetspolicy för hemsidan" msgid "privacy policy" msgstr "integritetspolicy" -#: src/Module/Security/Logout.php:87 +#: src/Module/Security/Logout.php:83 +#: 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 "Utloggad." @@ -8909,7 +8613,7 @@ msgid "Remaining recovery codes: %d" msgstr "" #: src/Module/Security/TwoFactor/Recovery.php:77 -#: src/Module/Security/TwoFactor/Verify.php:76 +#: src/Module/Security/TwoFactor/Verify.php:77 #: src/Module/Settings/TwoFactor/Verify.php:94 msgid "Invalid code, please retry." msgstr "" @@ -8925,7 +8629,6 @@ msgid "" msgstr "" #: src/Module/Security/TwoFactor/Recovery.php:98 -#: src/Module/Security/TwoFactor/Verify.php:99 #, php-format msgid "Don’t have your phone? Enter a two-factor recovery code" msgstr "" @@ -8938,25 +8641,582 @@ msgstr "" msgid "Submit recovery code and complete login" msgstr "" -#: src/Module/Security/TwoFactor/Verify.php:96 +#: 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:89 +msgid "Couldn't save browser to Cookie." +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:119 +msgid "Trust this browser?" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:120 +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:121 +msgid "Not now" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:122 +msgid "Don't trust" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:123 +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:154 msgid "Please enter a code from your authentication app" msgstr "" -#: src/Module/Security/TwoFactor/Verify.php:101 -msgid "This is my two-factor authenticator app device" -msgstr "" - #: src/Module/Security/TwoFactor/Verify.php:102 msgid "Verify code and complete login" msgstr "" +#: src/Module/Settings/Account.php:66 +msgid "Passwords do not match." +msgstr "Lösenorden matchar inte." + +#: src/Module/Settings/Account.php:80 +msgid "Password unchanged." +msgstr "Lösenordet oändrat." + +#: src/Module/Settings/Account.php:95 +msgid "Please use a shorter name." +msgstr "Vänligen ange ett kortare namn." + +#: src/Module/Settings/Account.php:98 +msgid "Name too short." +msgstr "Namnet för kort." + +#: src/Module/Settings/Account.php:107 +msgid "Wrong Password." +msgstr "Fel lösenord." + +#: src/Module/Settings/Account.php:112 +msgid "Invalid email." +msgstr "Ogiltig e-postadress." + +#: src/Module/Settings/Account.php:118 +msgid "Cannot change to that email." +msgstr "Kan inte byta till den e-postadressen." + +#: src/Module/Settings/Account.php:148 src/Module/Settings/Account.php:200 +#: src/Module/Settings/Account.php:220 src/Module/Settings/Account.php:304 +#: src/Module/Settings/Account.php:353 +msgid "Settings were not updated." +msgstr "Inställningarna uppdaterades inte." + +#: src/Module/Settings/Account.php:365 +msgid "Contact CSV file upload error" +msgstr "" + +#: src/Module/Settings/Account.php:384 +msgid "Importing Contacts done" +msgstr "" + +#: src/Module/Settings/Account.php:397 +msgid "Relocate message has been send to your contacts" +msgstr "" + +#: src/Module/Settings/Account.php:414 +msgid "Unable to find your profile. Please contact your admin." +msgstr "Kunde inte hitta din profil. Vänligen kontakta din admin." + +#: src/Module/Settings/Account.php:456 +msgid "Personal Page Subtypes" +msgstr "" + +#: src/Module/Settings/Account.php:457 +msgid "Community Forum Subtypes" +msgstr "" + +#: src/Module/Settings/Account.php:467 +msgid "Account for a personal profile." +msgstr "Konto för personlig profil." + +#: src/Module/Settings/Account.php:474 +msgid "" +"Account for an organisation that automatically approves contact requests as " +"\"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:481 +msgid "" +"Account for a news reflector that automatically approves contact requests as" +" \"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:488 +msgid "Account for community discussions." +msgstr "" + +#: src/Module/Settings/Account.php:495 +msgid "" +"Account for a regular personal profile that requires manual approval of " +"\"Friends\" and \"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:502 +msgid "" +"Account for a public profile that automatically approves contact requests as" +" \"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:509 +msgid "Automatically approves all contact requests." +msgstr "Godkänner automatiskt alla kontaktförfrågningar." + +#: src/Module/Settings/Account.php:516 +msgid "" +"Account for a popular profile that automatically approves contact requests " +"as \"Friends\"." +msgstr "" + +#: src/Module/Settings/Account.php:521 +msgid "Private Forum [Experimental]" +msgstr "Privat forum [Experimentiell]" + +#: src/Module/Settings/Account.php:523 +msgid "Requires manual approval of contact requests." +msgstr "" + +#: src/Module/Settings/Account.php:532 +msgid "OpenID:" +msgstr "OpenID:" + +#: src/Module/Settings/Account.php:532 +msgid "(Optional) Allow this OpenID to login to this account." +msgstr "(Valfritt) Tillåt detta OpenID för att logga in till det här kontot." + +#: src/Module/Settings/Account.php:540 +msgid "Publish your profile in your local site directory?" +msgstr "" + +#: src/Module/Settings/Account.php:540 +#, 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:546 +#, php-format +msgid "" +"Your profile will also be published in the global friendica directories " +"(e.g. %s)." +msgstr "" + +#: src/Module/Settings/Account.php:556 +msgid "Account Settings" +msgstr "Kontoinställningar" + +#: src/Module/Settings/Account.php:557 +#, php-format +msgid "Your Identity Address is '%s' or '%s'." +msgstr "" + +#: src/Module/Settings/Account.php:565 +msgid "Password Settings" +msgstr "Lösenordsinställningar" + +#: src/Module/Settings/Account.php:566 +msgid "" +"Allowed characters are a-z, A-Z, 0-9 and special characters except white " +"spaces, accentuated letters and colon (:)." +msgstr "" + +#: src/Module/Settings/Account.php:567 +msgid "Leave password fields blank unless changing" +msgstr "Lämna fältet tomt om du inte vill byta lösenord" + +#: src/Module/Settings/Account.php:568 +msgid "Current Password:" +msgstr "Nuvarande lösenord:" + +#: src/Module/Settings/Account.php:568 +msgid "Your current password to confirm the changes" +msgstr "Ditt nuvarande lösenord för att bekräfta ändringar" + +#: src/Module/Settings/Account.php:569 +msgid "Password:" +msgstr "Lösenord:" + +#: 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 "Grundläggande inställningar" + +#: src/Module/Settings/Account.php:576 +msgid "Email Address:" +msgstr "E-postadress:" + +#: src/Module/Settings/Account.php:577 +msgid "Your Timezone:" +msgstr "Tidszon:" + +#: src/Module/Settings/Account.php:578 +msgid "Your Language:" +msgstr "Ditt språk:" + +#: src/Module/Settings/Account.php:578 +msgid "" +"Set the language we use to show you friendica interface and to send you " +"emails" +msgstr "" + +#: src/Module/Settings/Account.php:579 +msgid "Default Post Location:" +msgstr "Default Post Location:" + +#: src/Module/Settings/Account.php:580 +msgid "Use Browser Location:" +msgstr "Använd webbläsarens positionering:" + +#: src/Module/Settings/Account.php:582 +msgid "Security and Privacy Settings" +msgstr "Inställningar för säkerhet och sekretess" + +#: src/Module/Settings/Account.php:584 +msgid "Maximum Friend Requests/Day:" +msgstr "Maximalt antal kontaktförfrågningar per dygn:" + +#: src/Module/Settings/Account.php:584 src/Module/Settings/Account.php:594 +msgid "(to prevent spam abuse)" +msgstr "(för att motverka spam)" + +#: src/Module/Settings/Account.php:586 +msgid "Allow your profile to be searchable globally?" +msgstr "Tillåta att din profil ska vara sökbar globalt?" + +#: 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 profile details from anonymous viewers?" +msgstr "Göm dina profildetaljer från anonyma tittare?" + +#: src/Module/Settings/Account.php:588 +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 "" + +#: 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 "Tillåta vänner att göra inlägg på din profilsida?" + +#: 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 "Tillåt vänner att tagga dina inlägg?" + +#: src/Module/Settings/Account.php:592 +msgid "Your contacts can add additional tags to your posts." +msgstr "Dina kontakter kan lägga till ytterligare taggar till dina inlägg." + +#: src/Module/Settings/Account.php:593 +msgid "Permit unknown people to send you private mail?" +msgstr "Ge okända personer tillstånd att skicka privata mail till dig?" + +#: 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 "" + +#: src/Module/Settings/Account.php:596 +msgid "Default Post Permissions" +msgstr "Standardåtkomst för inlägg" + +#: 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 "" + +#: 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 "Aviseringsinställningar" + +#: src/Module/Settings/Account.php:609 +msgid "Send a notification email when:" +msgstr "Skicka ett aviseringsmail när:" + +#: src/Module/Settings/Account.php:610 +msgid "You receive an introduction" +msgstr "En kontaktförfrågan anländer" + +#: src/Module/Settings/Account.php:611 +msgid "Your introductions are confirmed" +msgstr "Dina förfrågningar godkänns" + +#: src/Module/Settings/Account.php:612 +msgid "Someone writes on your profile wall" +msgstr "Någon gör inlägg på din profilsida" + +#: src/Module/Settings/Account.php:613 +msgid "Someone writes a followup comment" +msgstr "Någon gör ett inlägg i samma tråd som du" + +#: src/Module/Settings/Account.php:614 +msgid "You receive a private message" +msgstr "Du får personliga meddelanden" + +#: src/Module/Settings/Account.php:615 +msgid "You receive a friend suggestion" +msgstr "Du tar emot ett vän-förslag" + +#: src/Module/Settings/Account.php:616 +msgid "You are tagged in a post" +msgstr "Du är taggad i ett inlägg" + +#: src/Module/Settings/Account.php:617 +msgid "You are poked/prodded/etc. in a post" +msgstr "" + +#: src/Module/Settings/Account.php:619 +msgid "Create a desktop notification when:" +msgstr "Skapa en skrivbordsavisering när:" + +#: src/Module/Settings/Account.php:620 +msgid "Someone tagged you" +msgstr "" + +#: src/Module/Settings/Account.php:621 +msgid "Someone directly commented on your post" +msgstr "" + +#: src/Module/Settings/Account.php:622 +msgid "Someone liked your content" +msgstr "Någon gillade ditt innehåll" + +#: src/Module/Settings/Account.php:622 src/Module/Settings/Account.php:623 +msgid "Can only be enabled, when the direct comment notification is enabled." +msgstr "" + +#: src/Module/Settings/Account.php:623 +msgid "Someone shared your content" +msgstr "Någon delade ditt innehåll" + +#: src/Module/Settings/Account.php:624 +msgid "Someone commented in your thread" +msgstr "" + +#: src/Module/Settings/Account.php:625 +msgid "Someone commented in a thread where you commented" +msgstr "" + +#: src/Module/Settings/Account.php:626 +msgid "Someone commented in a thread where you interacted" +msgstr "" + +#: src/Module/Settings/Account.php:628 +msgid "Activate desktop notifications" +msgstr "Aktivera skrivbordsaviseringar" + +#: src/Module/Settings/Account.php:628 +msgid "Show desktop popup on new notifications" +msgstr "" + +#: src/Module/Settings/Account.php:632 +msgid "Text-only notification emails" +msgstr "" + +#: src/Module/Settings/Account.php:634 +msgid "Send text only notification emails, without the html part" +msgstr "" + +#: src/Module/Settings/Account.php:638 +msgid "Show detailled notifications" +msgstr "Visa detaljerade aviseringar" + +#: src/Module/Settings/Account.php:640 +msgid "" +"Per default, notifications are condensed to a single notification per item. " +"When enabled every notification is displayed." +msgstr "" + +#: src/Module/Settings/Account.php:644 +msgid "Show notifications of ignored contacts" +msgstr "" + +#: src/Module/Settings/Account.php:646 +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:649 +msgid "Advanced Account/Page Type Settings" +msgstr "" + +#: src/Module/Settings/Account.php:650 +msgid "Change the behaviour of this account for special situations" +msgstr "" + +#: src/Module/Settings/Account.php:653 +msgid "Import Contacts" +msgstr "Importera kontakter" + +#: src/Module/Settings/Account.php:654 +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:655 +msgid "Upload File" +msgstr "Ladda upp fil" + +#: src/Module/Settings/Account.php:658 +msgid "Relocate" +msgstr "Omlokalisera" + +#: src/Module/Settings/Account.php:659 +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 "Om du har flyttat den här profilen från en annan server och några av dina kontakter inte får dina uppdateringar, försök att trycka på den här knappen." + +#: src/Module/Settings/Account.php:660 +msgid "Resend relocate message to contacts" +msgstr "" + #: src/Module/Settings/Delegation.php:53 msgid "Delegation successfully granted." msgstr "" @@ -9449,99 +9709,95 @@ msgstr "" msgid "Generate" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:67 +#: src/Module/Settings/TwoFactor/Index.php:68 msgid "Two-factor authentication successfully disabled." msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:93 -msgid "Wrong Password" -msgstr "Fel lösenord" - -#: src/Module/Settings/TwoFactor/Index.php:113 +#: src/Module/Settings/TwoFactor/Index.php:116 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:117 +#: src/Module/Settings/TwoFactor/Index.php:120 msgid "Authenticator app" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Configured" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:118 +#: src/Module/Settings/TwoFactor/Index.php:121 msgid "Not Configured" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:119 +#: src/Module/Settings/TwoFactor/Index.php:122 msgid "

You haven't finished configuring your authenticator app.

" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:120 +#: src/Module/Settings/TwoFactor/Index.php:123 msgid "

Your authenticator app is correctly configured.

" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:122 +#: src/Module/Settings/TwoFactor/Index.php:125 msgid "Recovery codes" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:123 +#: src/Module/Settings/TwoFactor/Index.php:126 msgid "Remaining valid codes" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:125 +#: src/Module/Settings/TwoFactor/Index.php:128 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:127 +#: src/Module/Settings/TwoFactor/Index.php:130 msgid "App-specific passwords" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:128 +#: src/Module/Settings/TwoFactor/Index.php:131 msgid "Generated app-specific passwords" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:130 +#: src/Module/Settings/TwoFactor/Index.php:133 msgid "" "

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

" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:136 msgid "Current password:" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:133 +#: src/Module/Settings/TwoFactor/Index.php:136 msgid "" "You need to provide your current password to change two-factor " "authentication settings." msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:134 +#: src/Module/Settings/TwoFactor/Index.php:137 msgid "Enable two-factor authentication" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:135 +#: src/Module/Settings/TwoFactor/Index.php:138 msgid "Disable two-factor authentication" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:136 +#: src/Module/Settings/TwoFactor/Index.php:139 msgid "Show recovery codes" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:137 +#: src/Module/Settings/TwoFactor/Index.php:140 msgid "Manage app-specific passwords" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:138 +#: src/Module/Settings/TwoFactor/Index.php:141 msgid "Manage trusted browsers" msgstr "" -#: src/Module/Settings/TwoFactor/Index.php:139 +#: src/Module/Settings/TwoFactor/Index.php:142 msgid "Finish app configuration" msgstr "" @@ -9584,34 +9840,38 @@ msgstr "" msgid "Trusted browser successfully removed." msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:133 +#: src/Module/Settings/TwoFactor/Trusted.php:134 msgid "Two-factor Trusted Browsers" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:134 +#: src/Module/Settings/TwoFactor/Trusted.php:135 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:135 +#: src/Module/Settings/TwoFactor/Trusted.php:136 msgid "Device" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:136 +#: src/Module/Settings/TwoFactor/Trusted.php:137 msgid "OS" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:138 +#: src/Module/Settings/TwoFactor/Trusted.php:139 msgid "Trusted" msgstr "" -#: src/Module/Settings/TwoFactor/Trusted.php:139 -msgid "Last Use" +#: src/Module/Settings/TwoFactor/Trusted.php:140 +msgid "Created At" msgstr "" #: src/Module/Settings/TwoFactor/Trusted.php:141 +msgid "Last Use" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:143 msgid "Remove All" msgstr "" @@ -9660,32 +9920,32 @@ msgstr "" msgid "Verify code and enable two-factor authentication" msgstr "" -#: src/Module/Settings/UserExport.php:67 +#: src/Module/Settings/UserExport.php:68 msgid "Export account" msgstr "Exportera konto" -#: src/Module/Settings/UserExport.php:67 +#: src/Module/Settings/UserExport.php:68 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 "" -#: src/Module/Settings/UserExport.php:68 +#: src/Module/Settings/UserExport.php:69 msgid "Export all" msgstr "Exportera allt" -#: src/Module/Settings/UserExport.php:68 +#: src/Module/Settings/UserExport.php:69 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:69 +#: src/Module/Settings/UserExport.php:70 msgid "Export Contacts to CSV" msgstr "" -#: src/Module/Settings/UserExport.php:69 +#: src/Module/Settings/UserExport.php:70 msgid "" "Export the list of the accounts you are following as CSV file. Compatible to" " e.g. Mastodon." @@ -9900,43 +10160,51 @@ msgid "" " features and resources." msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:89 +#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:134 +msgid "{0} wants to follow you" +msgstr "" + +#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:136 +msgid "{0} has started following you" +msgstr "" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:91 #, php-format msgid "%s liked %s's post" msgstr "%sgillade %s's inlägg" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:101 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:103 #, php-format msgid "%s disliked %s's post" msgstr "%s gillade inte %s's inlägg" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:113 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:115 #, php-format msgid "%s is attending %s's event" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:125 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:127 #, php-format msgid "%s is not attending %s's event" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:137 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:139 #, php-format msgid "%s may attending %s's event" msgstr "" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:167 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:169 #, php-format msgid "%s is now friends with %s" msgstr "%s är nu vänner med %s" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:334 -#: src/Navigation/Notifications/Factory/FormattedNotification.php:372 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:336 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:374 #, php-format msgid "%s commented on %s's post" msgstr "%s kommenterade på %s's inlägg" -#: src/Navigation/Notifications/Factory/FormattedNotification.php:371 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:373 #, php-format msgid "%s created a new post" msgstr "%s skapade ett nytt inlägg" @@ -9953,326 +10221,330 @@ msgstr "Vän- eller kontaktförfrågan" msgid "New Follower" msgstr "En som vill följa dig" -#: src/Navigation/Notifications/Factory/Notification.php:93 +#: src/Navigation/Notifications/Factory/Notification.php:134 #, php-format msgid "%1$s wants to follow you" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:95 +#: src/Navigation/Notifications/Factory/Notification.php:136 #, php-format -msgid "%1$s had started following you" +msgid "%1$s has started following you" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:149 +#: src/Navigation/Notifications/Factory/Notification.php:200 #, php-format -msgid "%1$s liked your comment %2$s" +msgid "%1$s liked your comment on %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:152 +#: src/Navigation/Notifications/Factory/Notification.php:203 #, php-format msgid "%1$s liked your post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:159 +#: src/Navigation/Notifications/Factory/Notification.php:210 #, php-format -msgid "%1$s disliked your comment %2$s" +msgid "%1$s disliked your comment on %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:162 +#: src/Navigation/Notifications/Factory/Notification.php:213 #, php-format msgid "%1$s disliked your post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:169 +#: src/Navigation/Notifications/Factory/Notification.php:220 #, php-format msgid "%1$s shared your comment %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:172 +#: src/Navigation/Notifications/Factory/Notification.php:223 #, php-format msgid "%1$s shared your post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:176 +#: src/Navigation/Notifications/Factory/Notification.php:227 +#: src/Navigation/Notifications/Factory/Notification.php:297 #, php-format msgid "%1$s shared the post %2$s from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:178 +#: src/Navigation/Notifications/Factory/Notification.php:229 +#: src/Navigation/Notifications/Factory/Notification.php:299 #, php-format msgid "%1$s shared a post from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:180 +#: src/Navigation/Notifications/Factory/Notification.php:231 +#: src/Navigation/Notifications/Factory/Notification.php:301 #, php-format msgid "%1$s shared the post %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:182 +#: src/Navigation/Notifications/Factory/Notification.php:233 +#: src/Navigation/Notifications/Factory/Notification.php:303 #, php-format msgid "%1$s shared a post" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:190 +#: src/Navigation/Notifications/Factory/Notification.php:241 #, php-format msgid "%1$s wants to attend your event %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:197 +#: src/Navigation/Notifications/Factory/Notification.php:248 #, php-format msgid "%1$s does not want to attend your event %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:204 +#: src/Navigation/Notifications/Factory/Notification.php:255 #, php-format msgid "%1$s maybe wants to attend your event %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:211 +#: src/Navigation/Notifications/Factory/Notification.php:262 #, php-format msgid "%1$s tagged you on %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:215 +#: src/Navigation/Notifications/Factory/Notification.php:266 #, php-format msgid "%1$s replied to you on %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:219 +#: src/Navigation/Notifications/Factory/Notification.php:270 #, php-format msgid "%1$s commented in your thread %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:223 +#: src/Navigation/Notifications/Factory/Notification.php:274 #, php-format msgid "%1$s commented on your comment %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:229 +#: src/Navigation/Notifications/Factory/Notification.php:281 #, php-format msgid "%1$s commented in their thread %2$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:231 +#: src/Navigation/Notifications/Factory/Notification.php:283 #, php-format msgid "%1$s commented in their thread" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:233 +#: src/Navigation/Notifications/Factory/Notification.php:285 #, php-format msgid "%1$s commented in the thread %2$s from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:235 +#: src/Navigation/Notifications/Factory/Notification.php:287 #, php-format msgid "%1$s commented in the thread from %3$s" msgstr "" -#: src/Navigation/Notifications/Factory/Notification.php:240 +#: src/Navigation/Notifications/Factory/Notification.php:292 #, php-format msgid "%1$s commented on your thread %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:211 -#: src/Navigation/Notifications/Repository/Notify.php:694 +#: src/Navigation/Notifications/Repository/Notify.php:222 +#: src/Navigation/Notifications/Repository/Notify.php:736 msgid "[Friendica:Notify]" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:275 +#: src/Navigation/Notifications/Repository/Notify.php:286 #, php-format msgid "%s New mail received at %s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:277 +#: src/Navigation/Notifications/Repository/Notify.php:288 #, php-format msgid "%1$s sent you a new private message at %2$s." msgstr "%1$sskickade ett privat meddelande till dig %2$s." -#: src/Navigation/Notifications/Repository/Notify.php:278 +#: src/Navigation/Notifications/Repository/Notify.php:289 msgid "a private message" msgstr "ett privat meddelande" -#: src/Navigation/Notifications/Repository/Notify.php:278 +#: src/Navigation/Notifications/Repository/Notify.php:289 #, php-format msgid "%1$s sent you %2$s." msgstr "%1$sskickade%2$s." -#: src/Navigation/Notifications/Repository/Notify.php:280 +#: src/Navigation/Notifications/Repository/Notify.php:291 #, php-format msgid "Please visit %s to view and/or reply to your private messages." msgstr "Gå till %sför att se och svara på dina privata meddelanden." -#: src/Navigation/Notifications/Repository/Notify.php:311 +#: src/Navigation/Notifications/Repository/Notify.php:321 #, php-format msgid "%1$s commented on %2$s's %3$s %4$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:316 +#: src/Navigation/Notifications/Repository/Notify.php:326 #, php-format msgid "%1$s commented on your %2$s %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:320 +#: src/Navigation/Notifications/Repository/Notify.php:330 #, php-format msgid "%1$s commented on their %2$s %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:324 -#: src/Navigation/Notifications/Repository/Notify.php:729 +#: src/Navigation/Notifications/Repository/Notify.php:334 +#: src/Navigation/Notifications/Repository/Notify.php:770 #, php-format msgid "%1$s Comment to conversation #%2$d by %3$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:326 +#: src/Navigation/Notifications/Repository/Notify.php:336 #, php-format msgid "%s commented on an item/conversation you have been following." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:330 -#: src/Navigation/Notifications/Repository/Notify.php:345 -#: src/Navigation/Notifications/Repository/Notify.php:364 -#: src/Navigation/Notifications/Repository/Notify.php:744 +#: src/Navigation/Notifications/Repository/Notify.php:340 +#: src/Navigation/Notifications/Repository/Notify.php:355 +#: src/Navigation/Notifications/Repository/Notify.php:374 +#: src/Navigation/Notifications/Repository/Notify.php:785 #, php-format msgid "Please visit %s to view and/or reply to the conversation." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:337 +#: src/Navigation/Notifications/Repository/Notify.php:347 #, php-format msgid "%s %s posted to your profile wall" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:339 +#: src/Navigation/Notifications/Repository/Notify.php:349 #, php-format msgid "%1$s posted to your profile wall at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:340 +#: src/Navigation/Notifications/Repository/Notify.php:350 #, php-format msgid "%1$s posted to [url=%2$s]your wall[/url]" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:352 +#: src/Navigation/Notifications/Repository/Notify.php:362 #, php-format msgid "%1$s %2$s poked you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:354 +#: src/Navigation/Notifications/Repository/Notify.php:364 #, php-format msgid "%1$s poked you at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:355 +#: src/Navigation/Notifications/Repository/Notify.php:365 #, php-format msgid "%1$s [url=%2$s]poked you[/url]." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:372 +#: src/Navigation/Notifications/Repository/Notify.php:382 #, php-format msgid "%s Introduction received" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:374 +#: src/Navigation/Notifications/Repository/Notify.php:384 #, php-format msgid "You've received an introduction from '%1$s' at %2$s" msgstr "Du tog emot en introduktion från '%1$s' vid %2$s" -#: src/Navigation/Notifications/Repository/Notify.php:375 +#: src/Navigation/Notifications/Repository/Notify.php:385 #, php-format msgid "You've received [url=%1$s]an introduction[/url] from %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:380 -#: src/Navigation/Notifications/Repository/Notify.php:426 +#: src/Navigation/Notifications/Repository/Notify.php:390 +#: src/Navigation/Notifications/Repository/Notify.php:436 #, php-format msgid "You may visit their profile at %s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:382 +#: src/Navigation/Notifications/Repository/Notify.php:392 #, php-format msgid "Please visit %s to approve or reject the introduction." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:389 -#, php-format -msgid "%s A new person is sharing with you" -msgstr "" - -#: src/Navigation/Notifications/Repository/Notify.php:391 -#: src/Navigation/Notifications/Repository/Notify.php:392 -#, php-format -msgid "%1$s is sharing with you at %2$s" -msgstr "" - #: src/Navigation/Notifications/Repository/Notify.php:399 #, php-format -msgid "%s You have a new follower" +msgid "%s A new person is sharing with you" msgstr "" #: src/Navigation/Notifications/Repository/Notify.php:401 #: src/Navigation/Notifications/Repository/Notify.php:402 #, php-format +msgid "%1$s is sharing with you at %2$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:409 +#, php-format +msgid "%s You have a new follower" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:411 +#: src/Navigation/Notifications/Repository/Notify.php:412 +#, php-format msgid "You have a new follower at %2$s : %1$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:415 +#: src/Navigation/Notifications/Repository/Notify.php:425 #, php-format msgid "%s Friend suggestion received" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:417 +#: src/Navigation/Notifications/Repository/Notify.php:427 #, php-format msgid "You've received a friend suggestion from '%1$s' at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:418 +#: src/Navigation/Notifications/Repository/Notify.php:428 #, php-format msgid "" "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:424 +#: src/Navigation/Notifications/Repository/Notify.php:434 msgid "Name:" msgstr "Namn:" -#: src/Navigation/Notifications/Repository/Notify.php:425 +#: src/Navigation/Notifications/Repository/Notify.php:435 msgid "Photo:" msgstr "Foto:" -#: src/Navigation/Notifications/Repository/Notify.php:428 +#: src/Navigation/Notifications/Repository/Notify.php:438 #, php-format msgid "Please visit %s to approve or reject the suggestion." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:436 -#: src/Navigation/Notifications/Repository/Notify.php:451 +#: src/Navigation/Notifications/Repository/Notify.php:446 +#: src/Navigation/Notifications/Repository/Notify.php:461 #, php-format msgid "%s Connection accepted" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:438 -#: src/Navigation/Notifications/Repository/Notify.php:453 +#: src/Navigation/Notifications/Repository/Notify.php:448 +#: src/Navigation/Notifications/Repository/Notify.php:463 #, php-format msgid "'%1$s' has accepted your connection request at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:439 -#: src/Navigation/Notifications/Repository/Notify.php:454 +#: src/Navigation/Notifications/Repository/Notify.php:449 +#: src/Navigation/Notifications/Repository/Notify.php:464 #, php-format msgid "%2$s has accepted your [url=%1$s]connection request[/url]." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:444 +#: src/Navigation/Notifications/Repository/Notify.php:454 msgid "" "You are now mutual friends and may exchange status updates, photos, and " "email without restriction." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:446 +#: src/Navigation/Notifications/Repository/Notify.php:456 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:459 +#: src/Navigation/Notifications/Repository/Notify.php:469 #, php-format msgid "" "'%1$s' has chosen to accept you a fan, which restricts some forms of " @@ -10281,33 +10553,33 @@ msgid "" "automatically." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:461 +#: src/Navigation/Notifications/Repository/Notify.php:471 #, php-format msgid "" "'%1$s' may choose to extend this into a two-way or more permissive " "relationship in the future." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:463 +#: src/Navigation/Notifications/Repository/Notify.php:473 #, php-format msgid "Please visit %s if you wish to make any changes to this relationship." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:473 +#: src/Navigation/Notifications/Repository/Notify.php:483 msgid "registration request" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:475 +#: src/Navigation/Notifications/Repository/Notify.php:485 #, php-format msgid "You've received a registration request from '%1$s' at %2$s" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:476 +#: src/Navigation/Notifications/Repository/Notify.php:486 #, php-format msgid "You've received a [url=%1$s]registration request[/url] from %2$s." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:481 +#: src/Navigation/Notifications/Repository/Notify.php:491 #, php-format msgid "" "Full Name:\t%s\n" @@ -10315,17 +10587,17 @@ msgid "" "Login Name:\t%s (%s)" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:487 +#: src/Navigation/Notifications/Repository/Notify.php:497 #, php-format msgid "Please visit %s to approve or reject the request." msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:723 +#: src/Navigation/Notifications/Repository/Notify.php:764 #, php-format msgid "%s %s tagged you" msgstr "" -#: src/Navigation/Notifications/Repository/Notify.php:726 +#: src/Navigation/Notifications/Repository/Notify.php:767 #, php-format msgid "%s %s shared a new post" msgstr "" @@ -10353,240 +10625,244 @@ msgstr "Kontakta avsändaren genom att svara på det här meddelandet om du inte msgid "%s posted an update." msgstr "%s har gjort ett inlägg." -#: src/Object/Post.php:147 -msgid "This entry was edited" -msgstr "Den här posten redigerades" - -#: src/Object/Post.php:175 +#: src/Object/Post.php:136 msgid "Private Message" msgstr "Privat meddelande" -#: src/Object/Post.php:178 +#: src/Object/Post.php:140 +msgid "Public Message" +msgstr "" + +#: src/Object/Post.php:144 +msgid "Unlisted Message" +msgstr "" + +#: src/Object/Post.php:179 +msgid "This entry was edited" +msgstr "Den här posten redigerades" + +#: src/Object/Post.php:207 msgid "Connector Message" msgstr "" -#: src/Object/Post.php:193 src/Object/Post.php:195 +#: src/Object/Post.php:222 src/Object/Post.php:224 msgid "Edit" msgstr "Ändra" -#: src/Object/Post.php:215 -msgid "Pinned item" -msgstr "" - -#: src/Object/Post.php:219 +#: src/Object/Post.php:248 msgid "Delete globally" msgstr "" -#: src/Object/Post.php:219 +#: src/Object/Post.php:248 msgid "Remove locally" msgstr "" -#: src/Object/Post.php:235 +#: src/Object/Post.php:264 #, php-format msgid "Block %s" msgstr "" -#: src/Object/Post.php:240 +#: src/Object/Post.php:269 msgid "Save to folder" msgstr "" -#: src/Object/Post.php:274 +#: src/Object/Post.php:304 msgid "I will attend" msgstr "" -#: src/Object/Post.php:274 +#: src/Object/Post.php:304 msgid "I will not attend" msgstr "" -#: src/Object/Post.php:274 +#: src/Object/Post.php:304 msgid "I might attend" msgstr "" -#: src/Object/Post.php:304 +#: src/Object/Post.php:334 msgid "Ignore thread" msgstr "" -#: src/Object/Post.php:305 +#: src/Object/Post.php:335 msgid "Unignore thread" msgstr "" -#: src/Object/Post.php:306 +#: src/Object/Post.php:336 msgid "Toggle ignore status" msgstr "" -#: src/Object/Post.php:316 +#: src/Object/Post.php:346 msgid "Add star" msgstr "" -#: src/Object/Post.php:317 +#: src/Object/Post.php:347 msgid "Remove star" msgstr "" -#: src/Object/Post.php:318 +#: src/Object/Post.php:348 msgid "Toggle star status" msgstr "" -#: src/Object/Post.php:329 +#: src/Object/Post.php:359 msgid "Pin" msgstr "" -#: src/Object/Post.php:330 +#: src/Object/Post.php:360 msgid "Unpin" msgstr "" -#: src/Object/Post.php:331 +#: src/Object/Post.php:361 msgid "Toggle pin status" msgstr "" -#: src/Object/Post.php:334 +#: src/Object/Post.php:364 msgid "Pinned" msgstr "" -#: src/Object/Post.php:339 +#: src/Object/Post.php:369 msgid "Add tag" msgstr "" -#: src/Object/Post.php:352 +#: src/Object/Post.php:382 msgid "Quote share this" msgstr "" -#: src/Object/Post.php:352 +#: src/Object/Post.php:382 msgid "Quote Share" msgstr "" -#: src/Object/Post.php:355 +#: src/Object/Post.php:385 msgid "Reshare this" msgstr "" -#: src/Object/Post.php:355 +#: src/Object/Post.php:385 msgid "Reshare" msgstr "" -#: src/Object/Post.php:356 +#: src/Object/Post.php:386 msgid "Cancel your Reshare" msgstr "" -#: src/Object/Post.php:356 +#: src/Object/Post.php:386 msgid "Unshare" msgstr "" -#: src/Object/Post.php:401 +#: src/Object/Post.php:433 #, php-format msgid "%s (Received %s)" msgstr "" -#: src/Object/Post.php:406 +#: src/Object/Post.php:438 msgid "Comment this item on your system" msgstr "" -#: src/Object/Post.php:406 +#: src/Object/Post.php:438 msgid "Remote comment" msgstr "" -#: src/Object/Post.php:422 -msgid "Pushed" +#: src/Object/Post.php:459 +msgid "Share via ..." msgstr "" -#: src/Object/Post.php:422 -msgid "Pulled" +#: src/Object/Post.php:459 +msgid "Share via external services" msgstr "" -#: src/Object/Post.php:456 +#: src/Object/Post.php:488 msgid "to" msgstr "till" -#: src/Object/Post.php:457 +#: src/Object/Post.php:489 msgid "via" msgstr "via" -#: src/Object/Post.php:458 +#: src/Object/Post.php:490 msgid "Wall-to-Wall" msgstr "Profil-till-profil" -#: src/Object/Post.php:459 +#: src/Object/Post.php:491 msgid "via Wall-To-Wall:" msgstr "via profil-till-profil:" -#: src/Object/Post.php:499 +#: src/Object/Post.php:533 #, php-format msgid "Reply to %s" msgstr "" -#: src/Object/Post.php:502 +#: src/Object/Post.php:536 msgid "More" msgstr "" -#: src/Object/Post.php:520 +#: src/Object/Post.php:554 msgid "Notifier task is pending" msgstr "" -#: src/Object/Post.php:521 +#: src/Object/Post.php:555 msgid "Delivery to remote servers is pending" msgstr "" -#: src/Object/Post.php:522 +#: src/Object/Post.php:556 msgid "Delivery to remote servers is underway" msgstr "" -#: src/Object/Post.php:523 +#: src/Object/Post.php:557 msgid "Delivery to remote servers is mostly done" msgstr "" -#: src/Object/Post.php:524 +#: src/Object/Post.php:558 msgid "Delivery to remote servers is done" msgstr "" -#: src/Object/Post.php:544 +#: src/Object/Post.php:578 #, php-format msgid "%d comment" msgid_plural "%d comments" msgstr[0] "%d kommentar" msgstr[1] "%d kommentarer" -#: src/Object/Post.php:545 +#: src/Object/Post.php:579 msgid "Show more" msgstr "" -#: src/Object/Post.php:546 +#: src/Object/Post.php:580 msgid "Show fewer" msgstr "" -#: src/Protocol/OStatus.php:1645 +#: src/Protocol/OStatus.php:1705 #, php-format msgid "%s is now following %s." msgstr "" -#: src/Protocol/OStatus.php:1646 +#: src/Protocol/OStatus.php:1706 msgid "following" msgstr "följer" -#: src/Protocol/OStatus.php:1649 +#: src/Protocol/OStatus.php:1709 #, php-format msgid "%s stopped following %s." msgstr "" -#: src/Protocol/OStatus.php:1650 +#: src/Protocol/OStatus.php:1710 msgid "stopped following" msgstr "följer inte längre" -#: src/Render/FriendicaSmartyEngine.php:52 +#: src/Render/FriendicaSmartyEngine.php:65 msgid "The folder view/smarty3/ must be writable by webserver." msgstr "" -#: src/Security/Authentication.php:221 +#: src/Security/Authentication.php:226 msgid "Login failed." msgstr "Inloggningen misslyckades." -#: src/Security/Authentication.php:262 +#: src/Security/Authentication.php:267 msgid "Login failed. Please check your credentials." msgstr "" -#: src/Security/Authentication.php:360 +#: src/Security/Authentication.php:369 #, php-format msgid "Welcome %s" msgstr "" -#: src/Security/Authentication.php:361 +#: src/Security/Authentication.php:370 msgid "Please upload a profile photo." msgstr "Vänligen ladda upp ett profil-foto." @@ -10688,11 +10964,11 @@ msgstr "" msgid "(no subject)" msgstr "" -#: src/Worker/PushSubscription.php:103 +#: src/Worker/PushSubscription.php:112 msgid "Notification from Friendica" msgstr "" -#: src/Worker/PushSubscription.php:104 +#: src/Worker/PushSubscription.php:113 msgid "Empty Post" msgstr "" @@ -10838,39 +11114,39 @@ msgstr "" msgid "Leave background image and color empty for theme defaults" msgstr "" -#: view/theme/frio/php/Image.php:40 +#: view/theme/frio/php/Image.php:39 msgid "Top Banner" msgstr "" -#: view/theme/frio/php/Image.php:40 +#: 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:41 +#: view/theme/frio/php/Image.php:40 msgid "Full screen" msgstr "" -#: view/theme/frio/php/Image.php:41 +#: 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:42 +#: view/theme/frio/php/Image.php:41 msgid "Single row mosaic" msgstr "" -#: view/theme/frio/php/Image.php:42 +#: 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:43 +#: view/theme/frio/php/Image.php:42 msgid "Mosaic" msgstr "" -#: view/theme/frio/php/Image.php:43 +#: view/theme/frio/php/Image.php:42 msgid "Repeat image to fill the screen." msgstr "" diff --git a/view/lang/sv/strings.php b/view/lang/sv/strings.php index 072355600e..d9517c957e 100644 --- a/view/lang/sv/strings.php +++ b/view/lang/sv/strings.php @@ -19,6 +19,7 @@ $a->strings['day'] = 'dag'; $a->strings['list'] = 'lista'; $a->strings['User not found'] = 'Användaren hittades inte'; $a->strings['This calendar format is not supported'] = 'Kalenderformatet stöds inte'; +$a->strings['No exportable data found'] = 'Inga data att exportera hittades'; $a->strings['calendar'] = 'kalender'; $a->strings['Public access denied.'] = 'Publik åtkomst nekades.'; $a->strings['The feed for this item is unavailable.'] = 'Flödet för det här föremålet är otillgängligt.'; @@ -151,9 +152,11 @@ $a->strings['%d message'] = [ $a->strings['Personal Notes'] = 'Personliga anteckningar'; $a->strings['Personal notes are visible only by yourself.'] = 'Personliga anteckningar kan endast ses av dig själv.'; $a->strings['Subscribing to contacts'] = 'Prenumererar på kontakter'; +$a->strings['No contact provided.'] = 'Ingen kontakt angedd'; $a->strings['Couldn\'t fetch information for contact.'] = 'Kunde inte hämta information för kontakten.'; $a->strings['Couldn\'t fetch friends for contact.'] = 'Kunde inte hämta vänner för kontakt.'; $a->strings['Couldn\'t fetch following contacts.'] = 'Kunde inte hämta följande kontakter.'; +$a->strings['Couldn\'t fetch remote profile.'] = 'Kunde inte hämta profil'; $a->strings['Unsupported network'] = 'Nätverket stöds inte'; $a->strings['Done'] = 'Färdig'; $a->strings['success'] = 'lyckades'; @@ -171,6 +174,7 @@ $a->strings['Album was empty.'] = 'Albumet var tomt.'; $a->strings['Failed to delete the photo.'] = 'Borttagningen av fotot misslyckades.'; $a->strings['a photo'] = 'ett foto'; $a->strings['%1$s was tagged in %2$s by %3$s'] = '%1$s taggades i %2$s av %3$s'; +$a->strings['Image exceeds size limit of %s'] = 'Bildstorlek överstiger %s'; $a->strings['Image upload didn\'t complete, please try again'] = 'Uppladdningen av bilden slutfördes inte, vänligen försök igen.'; $a->strings['Image file is missing'] = 'Bildfilen saknas'; $a->strings['Server can\'t accept new file upload at this time, please contact your administrator'] = 'Servern kan just nu inte acceptera uppladdning av en ny fil, vänligen kontakta din administratör'; @@ -219,9 +223,6 @@ $a->strings['Dislike'] = 'Ogilla'; $a->strings['I don\'t like this (toggle)'] = 'Jag ogillar det här (växla)'; $a->strings['Map'] = 'Karta'; $a->strings['View Album'] = 'Titta i album'; -$a->strings['{0} wants to be your friend'] = '{0} vill vara din vän'; -$a->strings['{0} requested registration'] = '{0} bad om registrering'; -$a->strings['{0} and %d others requested registration'] = '{0} och %d andra bad om registrering'; $a->strings['Bad Request.'] = 'Dålig begäran.'; $a->strings['Contact not found.'] = 'Kontakten hittades inte.'; $a->strings['[Friendica System Notify]'] = '[System-avisering för Friendica]'; @@ -234,26 +235,20 @@ $a->strings['Error'] = [ 0 => 'Fel', 1 => 'Fel', ]; -$a->strings['Passwords do not match.'] = 'Lösenorden matchar inte.'; -$a->strings['Password update failed. Please try again.'] = 'Det blev fel när lösenordet skulle ändras. Försök igen.'; -$a->strings['Password changed.'] = 'Lösenordet har ändrats.'; -$a->strings['Password unchanged.'] = 'Lösenordet oändrat.'; -$a->strings['Please use a shorter name.'] = 'Vänligen ange ett kortare namn.'; -$a->strings['Name too short.'] = 'Namnet för kort.'; -$a->strings['Wrong Password.'] = 'Fel lösenord.'; -$a->strings['Invalid email.'] = 'Ogiltig e-postadress.'; -$a->strings['Cannot change to that email.'] = 'Kan inte byta till den e-postadressen.'; -$a->strings['Settings were not updated.'] = 'Inställningarna uppdaterades inte.'; +$a->strings['Failed to connect with email account using the settings provided.'] = 'Kunde inte ansluta till e-postkontot med aktuella inställningar'; $a->strings['Connected Apps'] = 'Anslutna appar'; $a->strings['Name'] = 'Namn'; $a->strings['Home Page'] = 'Hemsida'; $a->strings['Created'] = 'Skapades'; $a->strings['Remove authorization'] = 'Ta bort autentisering'; $a->strings['Save Settings'] = 'Spara inställningar'; +$a->strings['Addon Settings'] = 'Inställningar för Tillägg'; +$a->strings['No Addon settings configured'] = 'Inga inställningar för Tillägg har gjorts'; $a->strings['Additional Features'] = 'Ytterligare funktioner'; $a->strings['Diaspora (Socialhome, Hubzilla)'] = 'Diaspora (Socialhome, Hubzilla)'; $a->strings['enabled'] = 'aktiverad'; $a->strings['disabled'] = 'inaktiverad'; +$a->strings['Built-in support for %s connectivity is %s'] = 'Inbyggt stöd för %s kommunikation är %s'; $a->strings['OStatus (GNU Social)'] = 'OStatus (GNU Social)'; $a->strings['Email access is disabled on this site.'] = 'E-poståtkomst är inaktiverat på den här sidan.'; $a->strings['None'] = 'Ingen'; @@ -262,6 +257,7 @@ $a->strings['General Social Media Settings'] = 'Generella inställningar för so $a->strings['Enable Content Warning'] = 'Aktivera innehållsvarning'; $a->strings['Enable intelligent shortening'] = 'Aktivera intelligent förkortning'; $a->strings['Repair OStatus subscriptions'] = 'Reparera OStatus-prenumerationer'; +$a->strings['If you wish to communicate with email contacts using this service (optional), please specify how to connect to your mailbox.'] = 'För att kommunicera via e-post med denna tjänst (valfritt), vänligen ange anslutningssätt till ditt e-postkonto.'; $a->strings['IMAP server name:'] = 'Namn på IMAP-server:'; $a->strings['IMAP port:'] = 'Port för IMAP:'; $a->strings['Security:'] = 'Säkerhet:'; @@ -273,60 +269,6 @@ $a->strings['Action after import:'] = 'Åtgärd efter importering:'; $a->strings['Mark as seen'] = 'Markera som läst'; $a->strings['Move to folder'] = 'Flytta till mapp'; $a->strings['Move to folder:'] = 'Flytta till mapp:'; -$a->strings['Unable to find your profile. Please contact your admin.'] = 'Kunde inte hitta din profil. Vänligen kontakta din admin.'; -$a->strings['Account Types'] = 'Typer av konton'; -$a->strings['Personal Page'] = 'Personlig sida'; -$a->strings['Account for a personal profile.'] = 'Konto för personlig profil.'; -$a->strings['Organisation Page'] = 'Sida för organisation'; -$a->strings['Normal Account Page'] = 'Normal konto-sida'; -$a->strings['Public Forum'] = 'Publikt forum'; -$a->strings['Automatically approves all contact requests.'] = 'Godkänner automatiskt alla kontaktförfrågningar.'; -$a->strings['Private Forum [Experimental]'] = 'Privat forum [Experimentiell]'; -$a->strings['OpenID:'] = 'OpenID:'; -$a->strings['(Optional) Allow this OpenID to login to this account.'] = '(Valfritt) Tillåt detta OpenID för att logga in till det här kontot.'; -$a->strings['Account Settings'] = 'Kontoinställningar'; -$a->strings['Password Settings'] = 'Lösenordsinställningar'; -$a->strings['New Password:'] = 'Nytt lösenord'; -$a->strings['Confirm:'] = 'Bekräfta (repetera):'; -$a->strings['Leave password fields blank unless changing'] = 'Lämna fältet tomt om du inte vill byta lösenord'; -$a->strings['Current Password:'] = 'Nuvarande lösenord:'; -$a->strings['Your current password to confirm the changes'] = 'Ditt nuvarande lösenord för att bekräfta ändringar'; -$a->strings['Password:'] = 'Lösenord:'; -$a->strings['Basic Settings'] = 'Grundläggande inställningar'; -$a->strings['Full Name:'] = 'Fullständigt namn:'; -$a->strings['Email Address:'] = 'E-postadress:'; -$a->strings['Your Timezone:'] = 'Tidszon:'; -$a->strings['Your Language:'] = 'Ditt språk:'; -$a->strings['Default Post Location:'] = 'Default Post Location:'; -$a->strings['Use Browser Location:'] = 'Använd webbläsarens positionering:'; -$a->strings['Security and Privacy Settings'] = 'Inställningar för säkerhet och sekretess'; -$a->strings['Maximum Friend Requests/Day:'] = 'Maximalt antal kontaktförfrågningar per dygn:'; -$a->strings['(to prevent spam abuse)'] = '(för att motverka spam)'; -$a->strings['Allow your profile to be searchable globally?'] = 'Tillåta att din profil ska vara sökbar globalt?'; -$a->strings['Hide your profile details from anonymous viewers?'] = 'Göm dina profildetaljer från anonyma tittare?'; -$a->strings['Allow friends to post to your profile page?'] = 'Tillåta vänner att göra inlägg på din profilsida?'; -$a->strings['Allow friends to tag your posts?'] = 'Tillåt vänner att tagga dina inlägg?'; -$a->strings['Your contacts can add additional tags to your posts.'] = 'Dina kontakter kan lägga till ytterligare taggar till dina inlägg.'; -$a->strings['Permit unknown people to send you private mail?'] = 'Ge okända personer tillstånd att skicka privata mail till dig?'; -$a->strings['Default Post Permissions'] = 'Standardåtkomst för inlägg'; -$a->strings['Notification Settings'] = 'Aviseringsinställningar'; -$a->strings['Send a notification email when:'] = 'Skicka ett aviseringsmail när:'; -$a->strings['You receive an introduction'] = 'En kontaktförfrågan anländer'; -$a->strings['Your introductions are confirmed'] = 'Dina förfrågningar godkänns'; -$a->strings['Someone writes on your profile wall'] = 'Någon gör inlägg på din profilsida'; -$a->strings['Someone writes a followup comment'] = 'Någon gör ett inlägg i samma tråd som du'; -$a->strings['You receive a private message'] = 'Du får personliga meddelanden'; -$a->strings['You receive a friend suggestion'] = 'Du tar emot ett vän-förslag'; -$a->strings['You are tagged in a post'] = 'Du är taggad i ett inlägg'; -$a->strings['Create a desktop notification when:'] = 'Skapa en skrivbordsavisering när:'; -$a->strings['Someone liked your content'] = 'Någon gillade ditt innehåll'; -$a->strings['Someone shared your content'] = 'Någon delade ditt innehåll'; -$a->strings['Activate desktop notifications'] = 'Aktivera skrivbordsaviseringar'; -$a->strings['Show detailled notifications'] = 'Visa detaljerade aviseringar'; -$a->strings['Import Contacts'] = 'Importera kontakter'; -$a->strings['Upload File'] = 'Ladda upp fil'; -$a->strings['Relocate'] = 'Omlokalisera'; -$a->strings['If you have moved this profile from another server, and some of your contacts don\'t receive your updates, try pushing this button.'] = 'Om du har flyttat den här profilen från en annan server och några av dina kontakter inte får dina uppdateringar, försök att trycka på den här knappen.'; $a->strings['Friend Suggestions'] = 'Vän-förslag'; $a->strings['photo'] = 'foto'; $a->strings['status'] = 'status'; @@ -344,6 +286,7 @@ $a->strings['Disconnect/Unfollow'] = 'Koppla ur/Avfölj'; $a->strings['Contact was successfully unfollowed'] = 'Avföljningen av kontakten lyckades'; $a->strings['Invalid request.'] = 'Ogiltig förfrågning.'; $a->strings['Or - did you try to upload an empty file?'] = 'Eller - provade du att ladda upp en tom fil?'; +$a->strings['File exceeds size limit of %s'] = 'Filen överstiger maxstorleken %s'; $a->strings['File upload failed.'] = 'Uppladdning av filen misslyckades.'; $a->strings['Wall Photos'] = 'Loggbilder'; $a->strings['Unable to check your home location.'] = 'Kunde inte kontrollera platsen för ditt hem.'; @@ -361,9 +304,16 @@ $a->strings['Common'] = 'Vanlig'; $a->strings['Addon not found'] = 'Insticksprogrammet hittades inte'; $a->strings['Addon already enabled'] = 'Insticksprogrammet är redan aktiverat'; $a->strings['Addon already disabled'] = 'Insticksprogrammet är redan inaktiverat'; +$a->strings[' - found'] = '- hittad'; +$a->strings[' - failed'] = '- misslyckad'; +$a->strings[' - success'] = '- framgång'; +$a->strings[' - deleted'] = '- borttagen'; +$a->strings[' - done'] = '- klar'; $a->strings['Done.'] = 'Färdig.'; $a->strings['Enter user nickname: '] = 'Ange smeknamn för användaren:'; $a->strings['Enter new password: '] = 'Ange nytt lösenord:'; +$a->strings['Password update failed. Please try again.'] = 'Det blev fel när lösenordet skulle ändras. Försök igen.'; +$a->strings['Password changed.'] = 'Lösenordet har ändrats.'; $a->strings['Enter user name: '] = 'Ange användarnamn:'; $a->strings['Enter user email address: '] = 'Ange användarens e-postadress:'; $a->strings['Enter a language (optional): '] = 'Ange ett språk (valfritt):'; @@ -533,7 +483,7 @@ $a->strings['Click to open/close'] = 'Klicka för att öppna/stänga'; $a->strings['$1 wrote:'] = '$1 skrev:'; $a->strings['Encrypted content'] = 'Krypterat innehåll'; $a->strings['Invalid source protocol'] = 'Ogiltigt källprotokoll'; -$a->strings['Invalid link protocol'] = 'Ogiltigt källprotokoll'; +$a->strings['Invalid link protocol'] = 'Ogiltigt länkprotokoll'; $a->strings['Loading more entries...'] = 'Laddar fler poster...'; $a->strings['The end'] = 'Slut'; $a->strings['Follow'] = 'Följ'; @@ -558,8 +508,8 @@ $a->strings['Groups'] = 'Grupper'; $a->strings['Everyone'] = 'Alla'; $a->strings['Relationships'] = 'Relationer'; $a->strings['All Contacts'] = 'Alla kontakter'; -$a->strings['Protocols'] = 'Protokoller'; -$a->strings['All Protocols'] = 'Alla protokoller'; +$a->strings['Protocols'] = 'Protokoll'; +$a->strings['All Protocols'] = 'Alla protokoll'; $a->strings['Saved Folders'] = 'Sparade mappar'; $a->strings['Everything'] = 'Allting'; $a->strings['Categories'] = 'Kategorier'; @@ -571,6 +521,7 @@ $a->strings['Archives'] = 'Arkiv'; $a->strings['Persons'] = 'Personer'; $a->strings['Organisations'] = 'Organisationer'; $a->strings['News'] = 'Nyheter'; +$a->strings['Account Types'] = 'Typer av konton'; $a->strings['All'] = 'Alla'; $a->strings['Export'] = 'Exportera'; $a->strings['Export calendar as ical'] = 'Exportera kalender som ical'; @@ -691,7 +642,9 @@ $a->strings['Approve'] = 'Godkänn'; $a->strings['Organisation'] = 'Organisation'; $a->strings['Forum'] = 'Forum'; $a->strings['Disallowed profile URL.'] = 'Otillåten profil-URL.'; +$a->strings['Blocked domain'] = 'Blockerad domän'; $a->strings['The profile address specified does not provide adequate information.'] = 'Angiven profiladress ger inte tillräcklig information.'; +$a->strings['No compatible communication protocols or feeds were discovered.'] = 'Inga kompatibla kommunikationsprotokoll eller flöden hittades.'; $a->strings['An author or name was not found.'] = 'En författare eller namnet hittades inte.'; $a->strings['Limited profile. This person will be unable to receive direct/personal notifications from you.'] = 'Begränsad profil. Den här personen kommer inte att kunna ta emot personliga meddelanden från dig.'; $a->strings['Unable to retrieve contact information.'] = 'Det gick inte att komma åt kontaktinformationen.'; @@ -722,6 +675,7 @@ $a->strings['comment'] = 'kommentar'; $a->strings['post'] = 'inlägg'; $a->strings['Content warning: %s'] = 'Innehållsvarning: %s'; $a->strings['bytes'] = 'bytes'; +$a->strings['Poll end: %s'] = 'Omröstningen slut om: %s'; $a->strings['View on separate page'] = 'Visa på en separat sida'; $a->strings['[no subject]'] = '[ingen rubrik]'; $a->strings['Edit profile'] = 'Redigera profil'; @@ -745,6 +699,8 @@ $a->strings['Since:'] = 'Sedan:'; $a->strings['Sexual Preference:'] = 'Sexualitet'; $a->strings['Political Views:'] = 'Politisk åskådning:'; $a->strings['Religious Views:'] = 'Religion:'; +$a->strings['Likes:'] = 'Gillar:'; +$a->strings['Dislikes:'] = 'Ogillar:'; $a->strings['Title/Description:'] = 'Titel/Beskrivning:'; $a->strings['Summary'] = 'Sammanfattning'; $a->strings['Musical interests'] = 'Musik'; @@ -794,10 +750,17 @@ $a->strings['Maintainer: '] = 'Underhållare:'; $a->strings['List of all users'] = 'Lista över alla användare'; $a->strings['Active'] = 'Aktiv'; $a->strings['List of active accounts'] = 'Lista över aktiva konton'; +$a->strings['Pending'] = 'Väntande'; +$a->strings['List of pending registrations'] = 'Lista över väntande registreringar'; $a->strings['Blocked'] = 'Blockerad'; $a->strings['List of blocked users'] = 'Lista över blockerade användare'; $a->strings['Deleted'] = 'Ta bort'; +$a->strings['List of pending user deletions'] = 'Lista över väntande borttagningar av användare'; +$a->strings['Normal Account Page'] = 'Normal konto-sida'; +$a->strings['Public Forum'] = 'Publikt forum'; $a->strings['Private Forum'] = 'Privat forum'; +$a->strings['Personal Page'] = 'Personlig sida'; +$a->strings['Organisation Page'] = 'Sida för organisation'; $a->strings['Relay'] = 'Fördröj'; $a->strings['You can\'t block a local contact, please block the user instead'] = 'Du kan inte blockera en lokal kontakt, vänligen blockera användaren istället'; $a->strings['select all'] = 'välj alla'; @@ -830,6 +793,13 @@ $a->strings['Lock feature %s'] = 'Lås-funktion %s'; $a->strings['Manage Additional Features'] = 'Hantera ytterligare funktioner'; $a->strings['Other'] = 'Annat'; $a->strings['unknown'] = 'okänd'; +$a->strings['%s total systems'] = '%s totala system'; +$a->strings['%s active users last month'] = '%s aktiva användare senaste månaden'; +$a->strings['%s active users last six months'] = '%s aktiva användare senaste 6 månaderna'; +$a->strings['%s registered users'] = '%s registrerade användare'; +$a->strings['%s locally created posts and comments'] = '%s lokalt skapade postningar och kommentarer'; +$a->strings['%s posts per user'] = '%s postningar per användare'; +$a->strings['%s users per system'] = '%s användare per system'; $a->strings['Item marked for deletion.'] = 'Objektet är markerat för borttagning.'; $a->strings['Delete Item'] = 'Ta bort objekt'; $a->strings['Delete this Item'] = 'Ta bort det här objektet'; @@ -890,7 +860,6 @@ $a->strings['Policies'] = 'Policyer'; $a->strings['Performance'] = 'Prestanda'; $a->strings['Worker'] = 'Arbetare'; $a->strings['Message Relay'] = 'Meddelandefördröjning'; -$a->strings['Relocate Instance'] = 'Omlokalisera instansen'; $a->strings['Site name'] = 'Namn på sida'; $a->strings['Sender Email'] = 'Sändare av e-post'; $a->strings['Banner/Logo'] = 'Banderoll/Logga'; @@ -993,10 +962,26 @@ $a->strings['Unignore'] = 'Sluta ignorera'; $a->strings['Mutual Friendship'] = 'Ömsesidig vänskap'; $a->strings['is a fan of yours'] = 'är ett fan till dig'; $a->strings['you are a fan of'] = 'du är fan till'; +$a->strings['Pending outgoing contact request'] = 'Väntande utgående kontaktbegäran'; +$a->strings['Pending incoming contact request'] = 'Väntande inkommande kontaktbegäran'; $a->strings['Visit %s\'s profile [%s]'] = 'Besök %s\'s profil [%s]'; $a->strings['Contact update failed.'] = 'Det gick inte att uppdatera kontakt.'; $a->strings['New photo from this URL'] = 'Nytt foto från den här webbadressen'; $a->strings['Invalid contact.'] = 'Ogiltig kontakt.'; +$a->strings['No known contacts.'] = 'Inga kända kontakter.'; +$a->strings['No common contacts.'] = 'Inga gemensamma kontakter.'; +$a->strings['Follower (%s)'] = [ + 0 => 'Följare (%s)', + 1 => 'Följare (%s)', +]; +$a->strings['Following (%s)'] = [ + 0 => 'Följer (%s)', + 1 => 'Följer (%s)', +]; +$a->strings['Mutual friend (%s)'] = [ + 0 => 'Gemensam vän (%s)', + 1 => 'Gemensamma vänner (%s)', +]; $a->strings['Choose what you wish to do to recipient'] = 'Välj vad du vill göra med mottagaren'; $a->strings['Make this post private'] = 'Gör det här inlägget privat'; $a->strings['Failed to update contact record.'] = 'Det blev fel när kontakten skulle uppdateras.'; @@ -1017,6 +1002,8 @@ $a->strings['Communications lost with this contact!'] = 'Kommunikationen med den $a->strings['Fetch information'] = 'Hämta information'; $a->strings['No mirroring'] = 'Ingen spegling'; $a->strings['Contact Information / Notes'] = 'Kontaktuppgifter/Anteckningar'; +$a->strings['Contact'] = 'Kontakt'; +$a->strings['Their personal note'] = 'Deras personliga anteckning'; $a->strings['Edit contact notes'] = 'Redigera kontaktanteckningar'; $a->strings['Block/Unblock contact'] = 'Spärra kontakt eller häv spärr'; $a->strings['Ignore contact'] = 'Ignorera kontakt'; @@ -1029,6 +1016,9 @@ $a->strings['Currently ignored'] = 'Ignoreras'; $a->strings['Hide this contact from others'] = 'Göm den här kontakten för andra'; $a->strings['Notification for new posts'] = 'Avisering för nya inlägg'; $a->strings['Yes'] = 'Ja'; +$a->strings['Own Contacts'] = 'Egna kontakter'; +$a->strings['Include'] = 'Inkludera'; +$a->strings['Hide'] = 'Dölj'; $a->strings['No results.'] = 'Inga resultat.'; $a->strings['Not available.'] = 'Inte tillgängligt.'; $a->strings['No such group'] = 'Gruppen finns inte'; @@ -1037,11 +1027,15 @@ $a->strings['Personal'] = 'Privat'; $a->strings['Posts that mention or involve you'] = 'Inlägg som nämnde eller involverade dig'; $a->strings['Starred'] = 'Stjärnmärkt'; $a->strings['Favourite Posts'] = 'Favoriserade inlägg'; +$a->strings['You must be logged in to use this module'] = 'Du måste vara inloggad för att använda denna modul'; $a->strings['Time Conversion'] = 'Tidskonvertering'; $a->strings['UTC time: %s'] = 'UTC-tid: %s'; $a->strings['Current timezone: %s'] = 'Nuvarande tidszon: %s'; $a->strings['Converted localtime: %s'] = 'Konverterad lokaltid: %s'; $a->strings['Please select your timezone:'] = 'Vänligen välj din tidszon:'; +$a->strings['You are now logged in as %s'] = 'Du är nu inloggad som %s'; +$a->strings['Switch between your accounts'] = 'Växla mellan dina konton'; +$a->strings['Manage your accounts'] = 'Hantera dina konton'; $a->strings['Select an identity to manage: '] = 'Välj vilken identitet du vill hantera: '; $a->strings['No entries (some entries may be hidden).'] = 'Inget att visa. (Man kan välja att inte synas här)'; $a->strings['Find on this site'] = 'Hitta på den här sidan'; @@ -1097,11 +1091,14 @@ $a->strings['Network Notifications'] = 'Nätverksaviseringar'; $a->strings['System Notifications'] = 'Systemets aviseringar'; $a->strings['Personal Notifications'] = 'Privata aviseringar'; $a->strings['Home Notifications'] = 'Hem-aviseringar'; +$a->strings['{0} requested registration'] = '{0} bad om registrering'; +$a->strings['{0} and %d others requested registration'] = '{0} och %d andra bad om registrering'; $a->strings['Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'] = 'Vill du ge den här applikationen åtkomst till dina inlägg och kontakter, och/eller skapa nya inlägg för dig?'; $a->strings['Remote privacy information not available.'] = 'Remote privacy information not available.'; $a->strings['Visible to:'] = 'Synlig för:'; $a->strings['No contacts.'] = 'Inga kontakter.'; $a->strings['Profile not found.'] = 'Profilen hittades inte.'; +$a->strings['Full Name:'] = 'Fullständigt namn:'; $a->strings['j F, Y'] = 'j F, Y'; $a->strings['j F'] = 'j F'; $a->strings['Birthday:'] = 'Födelsedatum:'; @@ -1109,6 +1106,8 @@ $a->strings['Age: '] = 'Ålder: '; $a->strings['If you are not familiar with OpenID, please leave that field blank and fill in the rest of the items.'] = 'Om du inte vet vad OpenID är, eller inte vill använda det, kan du lämna det fältet tomt och fylla i resten.'; $a->strings['Your OpenID (optional): '] = 'OpenID (om du vill): '; $a->strings['Include your profile in member directory?'] = 'Ta med profilen i medlemskatalogen?'; +$a->strings['New Password:'] = 'Nytt lösenord'; +$a->strings['Confirm:'] = 'Bekräfta (repetera):'; $a->strings['Choose a nickname: '] = 'Välj ett användarnamn: '; $a->strings['Import your profile to this friendica instance'] = 'Importera din profil till den här friendica-instansen'; $a->strings['Registration successful. Please check your email for further instructions.'] = 'Registrering klar. Kolla din e-post för vidare information.'; @@ -1126,6 +1125,60 @@ $a->strings['terms of service'] = 'användarvillkor'; $a->strings['Website Privacy Policy'] = 'Integritetspolicy för hemsidan'; $a->strings['privacy policy'] = 'integritetspolicy'; $a->strings['Logged out.'] = 'Utloggad.'; +$a->strings['Passwords do not match.'] = 'Lösenorden matchar inte.'; +$a->strings['Password unchanged.'] = 'Lösenordet oändrat.'; +$a->strings['Please use a shorter name.'] = 'Vänligen ange ett kortare namn.'; +$a->strings['Name too short.'] = 'Namnet för kort.'; +$a->strings['Wrong Password.'] = 'Fel lösenord.'; +$a->strings['Invalid email.'] = 'Ogiltig e-postadress.'; +$a->strings['Cannot change to that email.'] = 'Kan inte byta till den e-postadressen.'; +$a->strings['Settings were not updated.'] = 'Inställningarna uppdaterades inte.'; +$a->strings['Unable to find your profile. Please contact your admin.'] = 'Kunde inte hitta din profil. Vänligen kontakta din admin.'; +$a->strings['Account for a personal profile.'] = 'Konto för personlig profil.'; +$a->strings['Automatically approves all contact requests.'] = 'Godkänner automatiskt alla kontaktförfrågningar.'; +$a->strings['Private Forum [Experimental]'] = 'Privat forum [Experimentiell]'; +$a->strings['OpenID:'] = 'OpenID:'; +$a->strings['(Optional) Allow this OpenID to login to this account.'] = '(Valfritt) Tillåt detta OpenID för att logga in till det här kontot.'; +$a->strings['Account Settings'] = 'Kontoinställningar'; +$a->strings['Password Settings'] = 'Lösenordsinställningar'; +$a->strings['Leave password fields blank unless changing'] = 'Lämna fältet tomt om du inte vill byta lösenord'; +$a->strings['Current Password:'] = 'Nuvarande lösenord:'; +$a->strings['Your current password to confirm the changes'] = 'Ditt nuvarande lösenord för att bekräfta ändringar'; +$a->strings['Password:'] = 'Lösenord:'; +$a->strings['Basic Settings'] = 'Grundläggande inställningar'; +$a->strings['Email Address:'] = 'E-postadress:'; +$a->strings['Your Timezone:'] = 'Tidszon:'; +$a->strings['Your Language:'] = 'Ditt språk:'; +$a->strings['Default Post Location:'] = 'Default Post Location:'; +$a->strings['Use Browser Location:'] = 'Använd webbläsarens positionering:'; +$a->strings['Security and Privacy Settings'] = 'Inställningar för säkerhet och sekretess'; +$a->strings['Maximum Friend Requests/Day:'] = 'Maximalt antal kontaktförfrågningar per dygn:'; +$a->strings['(to prevent spam abuse)'] = '(för att motverka spam)'; +$a->strings['Allow your profile to be searchable globally?'] = 'Tillåta att din profil ska vara sökbar globalt?'; +$a->strings['Hide your profile details from anonymous viewers?'] = 'Göm dina profildetaljer från anonyma tittare?'; +$a->strings['Allow friends to post to your profile page?'] = 'Tillåta vänner att göra inlägg på din profilsida?'; +$a->strings['Allow friends to tag your posts?'] = 'Tillåt vänner att tagga dina inlägg?'; +$a->strings['Your contacts can add additional tags to your posts.'] = 'Dina kontakter kan lägga till ytterligare taggar till dina inlägg.'; +$a->strings['Permit unknown people to send you private mail?'] = 'Ge okända personer tillstånd att skicka privata mail till dig?'; +$a->strings['Default Post Permissions'] = 'Standardåtkomst för inlägg'; +$a->strings['Notification Settings'] = 'Aviseringsinställningar'; +$a->strings['Send a notification email when:'] = 'Skicka ett aviseringsmail när:'; +$a->strings['You receive an introduction'] = 'En kontaktförfrågan anländer'; +$a->strings['Your introductions are confirmed'] = 'Dina förfrågningar godkänns'; +$a->strings['Someone writes on your profile wall'] = 'Någon gör inlägg på din profilsida'; +$a->strings['Someone writes a followup comment'] = 'Någon gör ett inlägg i samma tråd som du'; +$a->strings['You receive a private message'] = 'Du får personliga meddelanden'; +$a->strings['You receive a friend suggestion'] = 'Du tar emot ett vän-förslag'; +$a->strings['You are tagged in a post'] = 'Du är taggad i ett inlägg'; +$a->strings['Create a desktop notification when:'] = 'Skapa en skrivbordsavisering när:'; +$a->strings['Someone liked your content'] = 'Någon gillade ditt innehåll'; +$a->strings['Someone shared your content'] = 'Någon delade ditt innehåll'; +$a->strings['Activate desktop notifications'] = 'Aktivera skrivbordsaviseringar'; +$a->strings['Show detailled notifications'] = 'Visa detaljerade aviseringar'; +$a->strings['Import Contacts'] = 'Importera kontakter'; +$a->strings['Upload File'] = 'Ladda upp fil'; +$a->strings['Relocate'] = 'Omlokalisera'; +$a->strings['If you have moved this profile from another server, and some of your contacts don\'t receive your updates, try pushing this button.'] = 'Om du har flyttat den här profilen från en annan server och några av dina kontakter inte får dina uppdateringar, försök att trycka på den här knappen.'; $a->strings['Potential Delegates'] = 'Potentiella delegater'; $a->strings['Add'] = 'Lägg till'; $a->strings['No entries.'] = 'Inga poster.'; @@ -1161,7 +1214,6 @@ $a->strings['Please adjust the image cropping for optimum viewing.'] = 'Välj hu $a->strings['or'] = 'eller'; $a->strings['skip this step'] = 'hoppa över det här steget'; $a->strings['select a photo from your photo albums'] = 'välj en bild från ett album'; -$a->strings['Wrong Password'] = 'Fel lösenord'; $a->strings['Export account'] = 'Exportera konto'; $a->strings['Export all'] = 'Exportera allt'; $a->strings['Welcome to Friendica'] = 'Välkommen till Friendica'; @@ -1193,8 +1245,8 @@ $a->strings['Name:'] = 'Namn:'; $a->strings['Photo:'] = 'Foto:'; $a->strings['Please contact the sender by replying to this post if you do not wish to receive these messages.'] = 'Kontakta avsändaren genom att svara på det här meddelandet om du inte vill ha sådana här meddelanden.'; $a->strings['%s posted an update.'] = '%s har gjort ett inlägg.'; -$a->strings['This entry was edited'] = 'Den här posten redigerades'; $a->strings['Private Message'] = 'Privat meddelande'; +$a->strings['This entry was edited'] = 'Den här posten redigerades'; $a->strings['Edit'] = 'Ändra'; $a->strings['to'] = 'till'; $a->strings['via'] = 'via'; diff --git a/view/templates/admin/site.tpl b/view/templates/admin/site.tpl index f23cc521e7..88fc11336d 100644 --- a/view/templates/admin/site.tpl +++ b/view/templates/admin/site.tpl @@ -107,6 +107,7 @@

{{$performance}}

+ {{include file="field_checkbox.tpl" field=$compute_group_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/settings/twofactor/trusted_browsers.tpl b/view/templates/settings/twofactor/trusted_browsers.tpl index 29d2ab29c6..1a9ae91fe5 100644 --- a/view/templates/settings/twofactor/trusted_browsers.tpl +++ b/view/templates/settings/twofactor/trusted_browsers.tpl @@ -10,6 +10,7 @@ {{$device_label}} {{$os_label}} {{$browser_label}} + {{$trusted_label}} {{$created_label}} {{$last_used_label}} @@ -28,6 +29,9 @@ {{$trusted_browser.browser}} + {{$trusted_browser.trusted_labeled}} + + diff --git a/view/templates/twofactor/signout.tpl b/view/templates/twofactor/signout.tpl new file mode 100644 index 0000000000..f2a211102e --- /dev/null +++ b/view/templates/twofactor/signout.tpl @@ -0,0 +1,14 @@ +
+

{{$title}}

+
{{$message nofilter}}
+ +
+ + +
+ + + +
+
+
diff --git a/view/templates/twofactor/trust.tpl b/view/templates/twofactor/trust.tpl new file mode 100644 index 0000000000..6bfe307d5e --- /dev/null +++ b/view/templates/twofactor/trust.tpl @@ -0,0 +1,14 @@ +
+

{{$title}}

+
{{$message nofilter}}
+ +
+ + +
+ + + +
+
+
diff --git a/view/templates/twofactor/verify.tpl b/view/templates/twofactor/verify.tpl index 938f98da09..2b1fe31421 100644 --- a/view/templates/twofactor/verify.tpl +++ b/view/templates/twofactor/verify.tpl @@ -18,8 +18,6 @@ {{include file="field_input.tpl" field=$verify_code}} - {{include file="field_checkbox.tpl" field=$trust_browser}} -
diff --git a/view/theme/duepuntozero/style.php b/view/theme/duepuntozero/style.php index a56a012825..575f0dff58 100644 --- a/view/theme/duepuntozero/style.php +++ b/view/theme/duepuntozero/style.php @@ -25,13 +25,12 @@ if (file_exists("$THEMEPATH/style.css")) { echo file_get_contents("$THEMEPATH/style.css"); } -$uid = $_REQUEST['puid'] ?? 0; - -$s_colorset = DI::config()->get('duepuntozero', 'colorset'); -$colorset = DI::pConfig()->get($uid, 'duepuntozero', 'colorset'); - -if (empty($colorset)) { - $colorset = $s_colorset; +/* + * This script can be included when the maintenance mode is on, which requires us to avoid any config call + */ +if (DI::mode()->has(\Friendica\App\Mode::MAINTENANCEDISABLED)) { + $s_colorset = DI::config()->get('duepuntozero', 'colorset'); + $colorset = DI::pConfig()->get($_REQUEST['puid'] ?? 0, 'duepuntozero', 'colorset', $s_colorset); } $setcss = ''; diff --git a/view/theme/duepuntozero/theme.php b/view/theme/duepuntozero/theme.php index cc77e781bf..327a1e73ba 100644 --- a/view/theme/duepuntozero/theme.php +++ b/view/theme/duepuntozero/theme.php @@ -23,27 +23,36 @@ use Friendica\App; use Friendica\Core\Renderer; use Friendica\DI; +/* + * This script can be included even when the app is in maintenance mode which requires us to avoid any config call + */ + function duepuntozero_init(App $a) { -Renderer::setActiveTemplateEngine('smarty3'); + Renderer::setActiveTemplateEngine('smarty3'); - $colorset = DI::pConfig()->get( local_user(), 'duepuntozero','colorset'); - if (!$colorset) - $colorset = DI::config()->get('duepuntozero', 'colorset'); // user setting have priority, then node settings - if ($colorset) { - if ($colorset == 'greenzero') - DI::page()['htmlhead'] .= ''."\n"; - if ($colorset == 'purplezero') - DI::page()['htmlhead'] .= ''."\n"; - if ($colorset == 'easterbunny') - DI::page()['htmlhead'] .= ''."\n"; - if ($colorset == 'darkzero') - DI::page()['htmlhead'] .= ''."\n"; - if ($colorset == 'comix') - DI::page()['htmlhead'] .= ''."\n"; - if ($colorset == 'slackr') - DI::page()['htmlhead'] .= ''."\n"; - } + $colorset = null; + + if (DI::mode()->has(App\Mode::MAINTENANCEDISABLED)) { + $colorset = DI::pConfig()->get(local_user(), 'duepuntozero', 'colorset'); + if (!$colorset) + $colorset = DI::config()->get('duepuntozero', 'colorset'); // user setting have priority, then node settings + } + + if ($colorset) { + if ($colorset == 'greenzero') + DI::page()['htmlhead'] .= '' . "\n"; + if ($colorset == 'purplezero') + DI::page()['htmlhead'] .= '' . "\n"; + if ($colorset == 'easterbunny') + DI::page()['htmlhead'] .= '' . "\n"; + if ($colorset == 'darkzero') + DI::page()['htmlhead'] .= '' . "\n"; + if ($colorset == 'comix') + DI::page()['htmlhead'] .= '' . "\n"; + if ($colorset == 'slackr') + DI::page()['htmlhead'] .= '' . "\n"; + } DI::page()['htmlhead'] .= <<< EOT '; DI::page()['htmlhead'] .= '';; diff --git a/view/theme/smoothly/theme.php b/view/theme/smoothly/theme.php index e20e9003f9..9cc5b4a224 100644 --- a/view/theme/smoothly/theme.php +++ b/view/theme/smoothly/theme.php @@ -14,6 +14,10 @@ use Friendica\App; use Friendica\Core\Renderer; use Friendica\DI; +/* + * This script can be included even when the app is in maintenance mode which requires us to avoid any config call + */ + function smoothly_init(App $a) { Renderer::setActiveTemplateEngine('smarty3'); diff --git a/view/theme/vier/style.php b/view/theme/vier/style.php index 8e31a14bfc..ff888dac61 100644 --- a/view/theme/vier/style.php +++ b/view/theme/vier/style.php @@ -23,16 +23,16 @@ use Friendica\Core\Logger; use Friendica\DI; use Friendica\Network\HTTPException\NotModifiedException; -$uid = $_REQUEST['puid'] ?? 0; +/* + * This script can be included when the maintenance mode is on, which requires us to avoid any config call and + * use the following hardcoded default + */ +$style = 'plus'; -$style = DI::pConfig()->get($uid, 'vier', 'style'); +if (DI::mode()->has(\Friendica\App\Mode::MAINTENANCEDISABLED)) { + $uid = $_REQUEST['puid'] ?? 0; -if (empty($style)) { - $style = DI::config()->get('vier', 'style'); -} - -if (empty($style)) { - $style = "plus"; + $style = DI::pConfig()->get($uid, 'vier', 'style', DI::config()->get('vier', 'style', $style)); } $stylecss = ''; diff --git a/view/theme/vier/theme.php b/view/theme/vier/theme.php index c156298381..a548d0a7dc 100644 --- a/view/theme/vier/theme.php +++ b/view/theme/vier/theme.php @@ -19,6 +19,10 @@ use Friendica\DI; use Friendica\Model\Contact; use Friendica\Util\Strings; +/* + * This script can be included even when the app is in maintenance mode which requires us to avoid any config call + */ + function vier_init(App $a) { $a->setThemeInfoValue('events_in_profile', false); @@ -27,7 +31,12 @@ function vier_init(App $a) $args = DI::args(); - if ($args->get(0) === 'profile' && $args->get(1) === ($a->getLoggedInUserNickname() ?? '') || $args->get(0) === 'network' && local_user() + if ( + DI::mode()->has(App\Mode::MAINTENANCEDISABLED) + && ( + $args->get(0) === 'profile' && $args->get(1) === ($a->getLoggedInUserNickname() ?? '') + || $args->get(0) === 'network' && local_user() + ) ) { vier_community_info();