mirror of
https://github.com/friendica/friendica
synced 2025-02-19 10:06:49 +00:00
commit
6e70ad1f0e
14 changed files with 1737 additions and 643 deletions
32
.github/workflows/code-quality.yml
vendored
32
.github/workflows/code-quality.yml
vendored
|
@ -75,3 +75,35 @@ jobs:
|
||||||
|
|
||||||
- name: Run PHPStan
|
- name: Run PHPStan
|
||||||
run: composer run phpstan
|
run: composer run phpstan
|
||||||
|
|
||||||
|
phpmd:
|
||||||
|
name: PHPMD (PHP ${{ matrix.php }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
operating-system: ['ubuntu-latest']
|
||||||
|
php: ['8.4']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: Setup PHP with composer and extensions
|
||||||
|
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php }}
|
||||||
|
coverage: none
|
||||||
|
tools: none
|
||||||
|
|
||||||
|
- name: Clone addon repository
|
||||||
|
run: git clone -b develop --single-branch https://git.friendi.ca/friendica/friendica-addons.git addon
|
||||||
|
|
||||||
|
- name: Install Composer dependencies
|
||||||
|
uses: "ramsey/composer-install@v2"
|
||||||
|
|
||||||
|
- name: Run PHPMD
|
||||||
|
run: vendor/bin/phpmd src/ text .phpmd-ruleset.xml --color
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -89,6 +89,7 @@ venv/
|
||||||
#Ignore cache files
|
#Ignore cache files
|
||||||
.php_cs.cache
|
.php_cs.cache
|
||||||
.php-cs-fixer.cache
|
.php-cs-fixer.cache
|
||||||
|
.phpmd.result-cache.php
|
||||||
|
|
||||||
#ignore avatar picture cache path
|
#ignore avatar picture cache path
|
||||||
/avatar
|
/avatar
|
||||||
|
|
26
.phpmd-ruleset.xml
Normal file
26
.phpmd-ruleset.xml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="Friendica Ruleset"
|
||||||
|
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
|
||||||
|
http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||||
|
xsi:noNamespaceSchemaLocation="
|
||||||
|
http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||||
|
<description>
|
||||||
|
PHPMD ruleset for friendica code.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<rule ref="rulesets/codesize.xml/ExcessiveClassComplexity">
|
||||||
|
<priority>3</priority>
|
||||||
|
<properties>
|
||||||
|
<property name="maximum" value="800" />
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
<rule ref="rulesets/codesize.xml/CyclomaticComplexity">
|
||||||
|
<priority>3</priority>
|
||||||
|
<properties>
|
||||||
|
<property name="reportLevel" value="100" />
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
</ruleset>
|
3
.phpmd-ruleset.xml.license
Normal file
3
.phpmd-ruleset.xml.license
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||||
|
|
||||||
|
SPDX-License-Identifier: CC0-1.0
|
46
.woodpecker/.phpmd_check.yml
Normal file
46
.woodpecker/.phpmd_check.yml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# SPDX-FileCopyrightText: 2010 - 2024 the Friendica project
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
# The phpmd check is just triggered for PRs and pushes to non-stable branches of Friendica
|
||||||
|
when:
|
||||||
|
branch:
|
||||||
|
exclude: [ stable ]
|
||||||
|
event: [ pull_request, push ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
restore_cache:
|
||||||
|
image: meltwater/drone-cache:dev
|
||||||
|
settings:
|
||||||
|
backend: "filesystem"
|
||||||
|
restore: true
|
||||||
|
cache_key: "{{ .Repo.Name }}_php${PHP_MAJOR_VERSION}_{{ arch }}_{{ os }}"
|
||||||
|
archive_format: "gzip"
|
||||||
|
mount:
|
||||||
|
- '.composer'
|
||||||
|
volumes:
|
||||||
|
- /tmp/drone-cache:/tmp/cache
|
||||||
|
|
||||||
|
composer_install:
|
||||||
|
image: friendicaci/php8.3:php8.3.3
|
||||||
|
commands:
|
||||||
|
- mkdir addon # create empty addon folder to appease composer
|
||||||
|
- export COMPOSER_HOME=.composer
|
||||||
|
- ./bin/composer.phar install --prefer-dist
|
||||||
|
|
||||||
|
rebuild_cache:
|
||||||
|
image: meltwater/drone-cache:dev
|
||||||
|
settings:
|
||||||
|
backend: "filesystem"
|
||||||
|
rebuild: true
|
||||||
|
cache_key: "{{ .Repo.Name }}_php${PHP_MAJOR_VERSION}_{{ arch }}_{{ os }}"
|
||||||
|
archive_format: "gzip"
|
||||||
|
mount:
|
||||||
|
- '.composer'
|
||||||
|
volumes:
|
||||||
|
- /tmp/drone-cache:/tmp/cache
|
||||||
|
|
||||||
|
phpmd:
|
||||||
|
image: friendicaci/php8.3:php8.3.3
|
||||||
|
commands:
|
||||||
|
- ./bin/composer.phar run phpmd
|
|
@ -70,7 +70,7 @@
|
||||||
"pragmarx/google2fa": "^5.0",
|
"pragmarx/google2fa": "^5.0",
|
||||||
"pragmarx/recovery": "^0.2",
|
"pragmarx/recovery": "^0.2",
|
||||||
"psr/clock": "^1.0",
|
"psr/clock": "^1.0",
|
||||||
"psr/container": "^2.0",
|
"psr/container": "^1.1|^2.0",
|
||||||
"psr/event-dispatcher": "^1.0",
|
"psr/event-dispatcher": "^1.0",
|
||||||
"psr/log": "^1.1",
|
"psr/log": "^1.1",
|
||||||
"seld/cli-prompt": "^1.0",
|
"seld/cli-prompt": "^1.0",
|
||||||
|
@ -154,12 +154,14 @@
|
||||||
"mikey179/vfsstream": "^1.6",
|
"mikey179/vfsstream": "^1.6",
|
||||||
"mockery/mockery": "^1.3",
|
"mockery/mockery": "^1.3",
|
||||||
"php-mock/php-mock-phpunit": "^2.10",
|
"php-mock/php-mock-phpunit": "^2.10",
|
||||||
|
"phpmd/phpmd": "^2.15",
|
||||||
"phpstan/phpstan": "^2.0",
|
"phpstan/phpstan": "^2.0",
|
||||||
"phpunit/phpunit": "^9"
|
"phpunit/phpunit": "^9"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "phpunit",
|
"test": "phpunit",
|
||||||
"test:unit": "phpunit -c tests/phpunit.xml --testsuite unit",
|
"test:unit": "phpunit -c tests/phpunit.xml --testsuite unit",
|
||||||
|
"phpmd": "phpmd src/ text .phpmd-ruleset.xml --color --cache",
|
||||||
"phpstan": "phpstan analyze --memory-limit 1024M --configuration .phpstan.neon",
|
"phpstan": "phpstan analyze --memory-limit 1024M --configuration .phpstan.neon",
|
||||||
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l",
|
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l",
|
||||||
"docker:translate": "docker run --rm -v $PWD:/data -w /data friendicaci/transifex bin/run_xgettext.sh",
|
"docker:translate": "docker run --rm -v $PWD:/data -w /data friendicaci/transifex bin/run_xgettext.sh",
|
||||||
|
|
892
composer.lock
generated
892
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "8ee8f9186d271b65b83c2ddbd12c5c03",
|
"content-hash": "b77bf714197f04022a5feb001bf07852",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "asika/simple-console",
|
"name": "asika/simple-console",
|
||||||
|
@ -3139,6 +3139,9 @@
|
||||||
"psr",
|
"psr",
|
||||||
"psr-6"
|
"psr-6"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/cache/tree/master"
|
||||||
|
},
|
||||||
"time": "2016-08-06T20:24:11+00:00"
|
"time": "2016-08-06T20:24:11+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3187,27 +3190,22 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "psr/container",
|
||||||
"version": "2.0.2",
|
"version": "1.1.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/php-fig/container.git",
|
"url": "https://github.com/php-fig/container.git",
|
||||||
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
|
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
"url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
|
||||||
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.4.0"
|
"php": ">=7.4.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "2.0.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Psr\\Container\\": "src/"
|
"Psr\\Container\\": "src/"
|
||||||
|
@ -3232,7 +3230,11 @@
|
||||||
"container-interop",
|
"container-interop",
|
||||||
"psr"
|
"psr"
|
||||||
],
|
],
|
||||||
"time": "2021-11-05T16:47:00+00:00"
|
"support": {
|
||||||
|
"issues": "https://github.com/php-fig/container/issues",
|
||||||
|
"source": "https://github.com/php-fig/container/tree/1.1.2"
|
||||||
|
},
|
||||||
|
"time": "2021-11-05T16:50:12+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/event-dispatcher",
|
"name": "psr/event-dispatcher",
|
||||||
|
@ -3480,6 +3482,9 @@
|
||||||
"psr",
|
"psr",
|
||||||
"psr-3"
|
"psr-3"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/log/tree/1.1.4"
|
||||||
|
},
|
||||||
"time": "2021-05-03T11:20:27+00:00"
|
"time": "2021-05-03T11:20:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3697,16 +3702,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v2.5.2",
|
"version": "v2.5.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
|
"reference": "605389f2a7e5625f273b53960dc46aeaf9c62918"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918",
|
||||||
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
|
"reference": "605389f2a7e5625f273b53960dc46aeaf9c62918",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3714,12 +3719,12 @@
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/contracts",
|
||||||
|
"name": "symfony/contracts"
|
||||||
|
},
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "2.5-dev"
|
"dev-main": "2.5-dev"
|
||||||
},
|
|
||||||
"thanks": {
|
|
||||||
"name": "symfony/contracts",
|
|
||||||
"url": "https://github.com/symfony/contracts"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -3743,6 +3748,9 @@
|
||||||
],
|
],
|
||||||
"description": "A generic function and convention to trigger deprecation notices",
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4"
|
||||||
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://symfony.com/sponsor",
|
"url": "https://symfony.com/sponsor",
|
||||||
|
@ -3757,7 +3765,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-01-02T09:53:40+00:00"
|
"time": "2024-09-25T14:11:13+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/event-dispatcher",
|
"name": "symfony/event-dispatcher",
|
||||||
|
@ -4591,6 +4599,151 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
|
{
|
||||||
|
"name": "composer/pcre",
|
||||||
|
"version": "3.3.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/pcre.git",
|
||||||
|
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||||
|
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.4 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"phpstan/phpstan": "<1.11.10"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.12 || ^2",
|
||||||
|
"phpstan/phpstan-strict-rules": "^1 || ^2",
|
||||||
|
"phpunit/phpunit": "^8 || ^9"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"phpstan": {
|
||||||
|
"includes": [
|
||||||
|
"extension.neon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\Pcre\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "j.boggiano@seld.be",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
|
||||||
|
"keywords": [
|
||||||
|
"PCRE",
|
||||||
|
"preg",
|
||||||
|
"regex",
|
||||||
|
"regular expression"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/composer/pcre/issues",
|
||||||
|
"source": "https://github.com/composer/pcre/tree/3.3.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-11-12T16:29:46+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "composer/xdebug-handler",
|
||||||
|
"version": "3.0.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/xdebug-handler.git",
|
||||||
|
"reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
|
||||||
|
"reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/pcre": "^1 || ^2 || ^3",
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"psr/log": "^1 || ^2 || ^3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.0",
|
||||||
|
"phpstan/phpstan-strict-rules": "^1.1",
|
||||||
|
"phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\XdebugHandler\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "John Stevenson",
|
||||||
|
"email": "john-stevenson@blueyonder.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Restarts a process without Xdebug.",
|
||||||
|
"keywords": [
|
||||||
|
"Xdebug",
|
||||||
|
"performance"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||||
|
"issues": "https://github.com/composer/xdebug-handler/issues",
|
||||||
|
"source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-05-06T16:37:16+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "dms/phpunit-arraysubset-asserts",
|
"name": "dms/phpunit-arraysubset-asserts",
|
||||||
"version": "v0.3.1",
|
"version": "v0.3.1",
|
||||||
|
@ -4976,6 +5129,69 @@
|
||||||
],
|
],
|
||||||
"time": "2024-03-05T20:51:40+00:00"
|
"time": "2024-03-05T20:51:40+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "pdepend/pdepend",
|
||||||
|
"version": "2.16.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/pdepend/pdepend.git",
|
||||||
|
"reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
|
||||||
|
"reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.7",
|
||||||
|
"symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0",
|
||||||
|
"symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0",
|
||||||
|
"symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0",
|
||||||
|
"symfony/polyfill-mbstring": "^1.19"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"easy-doc/easy-doc": "0.0.0|^1.2.3",
|
||||||
|
"gregwar/rst": "^1.0",
|
||||||
|
"squizlabs/php_codesniffer": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"src/bin/pdepend"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PDepend\\": "src/main/php/PDepend"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"description": "Official version of pdepend to be handled with Composer",
|
||||||
|
"keywords": [
|
||||||
|
"PHP Depend",
|
||||||
|
"PHP_Depend",
|
||||||
|
"dev",
|
||||||
|
"pdepend"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/pdepend/pdepend/issues",
|
||||||
|
"source": "https://github.com/pdepend/pdepend/tree/2.16.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-12-17T18:09:59+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
|
@ -5293,6 +5509,89 @@
|
||||||
],
|
],
|
||||||
"time": "2024-02-11T07:24:16+00:00"
|
"time": "2024-02-11T07:24:16+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "phpmd/phpmd",
|
||||||
|
"version": "2.15.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/phpmd/phpmd.git",
|
||||||
|
"reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0",
|
||||||
|
"reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"pdepend/pdepend": "^2.16.1",
|
||||||
|
"php": ">=5.3.9"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"easy-doc/easy-doc": "0.0.0 || ^1.3.2",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"gregwar/rst": "^1.0",
|
||||||
|
"mikey179/vfsstream": "^1.6.8",
|
||||||
|
"squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"src/bin/phpmd"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"PHPMD\\": "src/main/php"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Manuel Pichler",
|
||||||
|
"email": "github@manuel-pichler.de",
|
||||||
|
"homepage": "https://github.com/manuelpichler",
|
||||||
|
"role": "Project Founder"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marc Würth",
|
||||||
|
"email": "ravage@bluewin.ch",
|
||||||
|
"homepage": "https://github.com/ravage84",
|
||||||
|
"role": "Project Maintainer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Other contributors",
|
||||||
|
"homepage": "https://github.com/phpmd/phpmd/graphs/contributors",
|
||||||
|
"role": "Contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.",
|
||||||
|
"homepage": "https://phpmd.org/",
|
||||||
|
"keywords": [
|
||||||
|
"dev",
|
||||||
|
"mess detection",
|
||||||
|
"mess detector",
|
||||||
|
"pdepend",
|
||||||
|
"phpmd",
|
||||||
|
"pmd"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"irc": "irc://irc.freenode.org/phpmd",
|
||||||
|
"issues": "https://github.com/phpmd/phpmd/issues",
|
||||||
|
"source": "https://github.com/phpmd/phpmd/tree/2.15.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-12-11T08:22:20+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan",
|
"name": "phpstan/phpstan",
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
|
@ -6647,6 +6946,559 @@
|
||||||
],
|
],
|
||||||
"time": "2020-09-28T06:39:44+00:00"
|
"time": "2020-09-28T06:39:44+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/config",
|
||||||
|
"version": "v5.4.46",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/config.git",
|
||||||
|
"reference": "977c88a02d7d3f16904a81907531b19666a08e78"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/config/zipball/977c88a02d7d3f16904a81907531b19666a08e78",
|
||||||
|
"reference": "977c88a02d7d3f16904a81907531b19666a08e78",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"symfony/deprecation-contracts": "^2.1|^3",
|
||||||
|
"symfony/filesystem": "^4.4|^5.0|^6.0",
|
||||||
|
"symfony/polyfill-ctype": "~1.8",
|
||||||
|
"symfony/polyfill-php80": "^1.16",
|
||||||
|
"symfony/polyfill-php81": "^1.22"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/finder": "<4.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/event-dispatcher": "^4.4|^5.0|^6.0",
|
||||||
|
"symfony/finder": "^4.4|^5.0|^6.0",
|
||||||
|
"symfony/messenger": "^4.4|^5.0|^6.0",
|
||||||
|
"symfony/service-contracts": "^1.1|^2|^3",
|
||||||
|
"symfony/yaml": "^4.4|^5.0|^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/yaml": "To use the yaml reference dumper"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Config\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/config/tree/v5.4.46"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-10-30T07:58:02+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/dependency-injection",
|
||||||
|
"version": "v5.4.48",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/dependency-injection.git",
|
||||||
|
"reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e5ca16dee39ef7d63e552ff0bf0a2526a1142c92",
|
||||||
|
"reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"psr/container": "^1.1.1",
|
||||||
|
"symfony/deprecation-contracts": "^2.1|^3",
|
||||||
|
"symfony/polyfill-php80": "^1.16",
|
||||||
|
"symfony/polyfill-php81": "^1.22",
|
||||||
|
"symfony/service-contracts": "^1.1.6|^2"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"ext-psr": "<1.1|>=2",
|
||||||
|
"symfony/config": "<5.3",
|
||||||
|
"symfony/finder": "<4.4",
|
||||||
|
"symfony/proxy-manager-bridge": "<4.4",
|
||||||
|
"symfony/yaml": "<4.4.26"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"psr/container-implementation": "1.0",
|
||||||
|
"symfony/service-implementation": "1.0|2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/config": "^5.3|^6.0",
|
||||||
|
"symfony/expression-language": "^4.4|^5.0|^6.0",
|
||||||
|
"symfony/yaml": "^4.4.26|^5.0|^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/config": "",
|
||||||
|
"symfony/expression-language": "For using expressions in service container configuration",
|
||||||
|
"symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
|
||||||
|
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
|
||||||
|
"symfony/yaml": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\DependencyInjection\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.48"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-11-20T10:51:57+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/filesystem",
|
||||||
|
"version": "v5.4.45",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/filesystem.git",
|
||||||
|
"reference": "57c8294ed37d4a055b77057827c67f9558c95c54"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54",
|
||||||
|
"reference": "57c8294ed37d4a055b77057827c67f9558c95c54",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"symfony/polyfill-ctype": "~1.8",
|
||||||
|
"symfony/polyfill-mbstring": "~1.8",
|
||||||
|
"symfony/polyfill-php80": "^1.16"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/process": "^5.4|^6.4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Filesystem\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides basic utilities for the filesystem",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/filesystem/tree/v5.4.45"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-10-22T13:05:35+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-ctype",
|
||||||
|
"version": "v1.31.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||||
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
|
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"ext-ctype": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-ctype": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Ctype\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Gert de Pagter",
|
||||||
|
"email": "BackEndTea@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for ctype functions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"ctype",
|
||||||
|
"polyfill",
|
||||||
|
"portable"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-mbstring",
|
||||||
|
"version": "v1.31.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
|
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"ext-mbstring": "*"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for the Mbstring extension",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"mbstring",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php81",
|
||||||
|
"version": "v1.31.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||||
|
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||||
|
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php81\\": ""
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-09T11:45:10+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/service-contracts",
|
||||||
|
"version": "v2.5.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/service-contracts.git",
|
||||||
|
"reference": "f37b419f7aea2e9abf10abd261832cace12e3300"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300",
|
||||||
|
"reference": "f37b419f7aea2e9abf10abd261832cace12e3300",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.5",
|
||||||
|
"psr/container": "^1.1",
|
||||||
|
"symfony/deprecation-contracts": "^2.1|^3"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"ext-psr": "<1.1|>=2"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/service-implementation": ""
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/contracts",
|
||||||
|
"name": "symfony/contracts"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "2.5-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Contracts\\Service\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Generic abstractions related to writing services",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"abstractions",
|
||||||
|
"contracts",
|
||||||
|
"decoupling",
|
||||||
|
"interfaces",
|
||||||
|
"interoperability",
|
||||||
|
"standards"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/service-contracts/tree/v2.5.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-09-25T14:11:13+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/tokenizer",
|
"name": "theseer/tokenizer",
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
|
|
|
@ -162,6 +162,8 @@ class APContact
|
||||||
DI::cache()->set($cachekey, System::callstack(20), Duration::FIVE_MINUTES);
|
DI::cache()->set($cachekey, System::callstack(20), Duration::FIVE_MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$local_owner = [];
|
||||||
|
|
||||||
if (DI::baseUrl()->isLocalUrl($url) && ($local_uid = User::getIdForURL($url))) {
|
if (DI::baseUrl()->isLocalUrl($url) && ($local_uid = User::getIdForURL($url))) {
|
||||||
try {
|
try {
|
||||||
$data = Transmitter::getProfile($local_uid);
|
$data = Transmitter::getProfile($local_uid);
|
||||||
|
@ -205,6 +207,15 @@ class APContact
|
||||||
return $fetched_contact;
|
return $fetched_contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return self::compactProfile($apcontact, $compacted, $url, $fetched_contact, $webfinger, $local_owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|bool $fetched_contact
|
||||||
|
* @param array|bool $local_owner
|
||||||
|
*/
|
||||||
|
private static function compactProfile(array $apcontact, array $compacted, string $url, $fetched_contact, bool $webfinger, $local_owner): array
|
||||||
|
{
|
||||||
$apcontact['url'] = $compacted['@id'];
|
$apcontact['url'] = $compacted['@id'];
|
||||||
$apcontact['uuid'] = JsonLD::fetchElement($compacted, 'diaspora:guid', '@value');
|
$apcontact['uuid'] = JsonLD::fetchElement($compacted, 'diaspora:guid', '@value');
|
||||||
$apcontact['type'] = str_replace('as:', '', JsonLD::fetchElement($compacted, '@type'));
|
$apcontact['type'] = str_replace('as:', '', JsonLD::fetchElement($compacted, '@type'));
|
||||||
|
|
|
@ -817,6 +817,25 @@ class GServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count the number of known contacts from this server
|
// Count the number of known contacts from this server
|
||||||
|
self::countNumberOfKnownContacts((int) $id, $serverdata);
|
||||||
|
|
||||||
|
if (in_array($serverdata['network'], [Protocol::DFRN, Protocol::DIASPORA])) {
|
||||||
|
self::discoverRelay($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($systemactor)) {
|
||||||
|
$contact = Contact::getByURL($systemactor, true, ['gsid', 'baseurl', 'id', 'network', 'url', 'name']);
|
||||||
|
DI::logger()->debug('Fetched system actor', ['url' => $url, 'gsid' => $id, 'contact' => $contact]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of known contacts from this server
|
||||||
|
*/
|
||||||
|
private static function countNumberOfKnownContacts(int $id, array $serverdata): void
|
||||||
|
{
|
||||||
if (!empty($id) && !in_array($serverdata['network'], [Protocol::PHANTOM, Protocol::FEED])) {
|
if (!empty($id) && !in_array($serverdata['network'], [Protocol::PHANTOM, Protocol::FEED])) {
|
||||||
$apcontacts = DBA::count('apcontact', ['gsid' => $id]);
|
$apcontacts = DBA::count('apcontact', ['gsid' => $id]);
|
||||||
$contacts = DBA::count('contact', ['uid' => 0, 'gsid' => $id, 'failed' => false]);
|
$contacts = DBA::count('contact', ['uid' => 0, 'gsid' => $id, 'failed' => false]);
|
||||||
|
@ -842,17 +861,6 @@ class GServer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($serverdata['network'], [Protocol::DFRN, Protocol::DIASPORA])) {
|
|
||||||
self::discoverRelay($url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($systemactor)) {
|
|
||||||
$contact = Contact::getByURL($systemactor, true, ['gsid', 'baseurl', 'id', 'network', 'url', 'name']);
|
|
||||||
DI::logger()->debug('Fetched system actor', ['url' => $url, 'gsid' => $id, 'contact' => $contact]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -580,52 +580,6 @@ class Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the item array is a duplicate
|
|
||||||
*
|
|
||||||
* @param array $item Item record
|
|
||||||
* @return boolean is it a duplicate?
|
|
||||||
*/
|
|
||||||
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']];
|
|
||||||
if (Post::exists($condition)) {
|
|
||||||
DI::logger()->notice('Found already existing item', $condition);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$condition = [
|
|
||||||
'uri-id' => $item['uri-id'], 'uid' => $item['uid'],
|
|
||||||
'network' => [$item['network'], Protocol::DFRN]
|
|
||||||
];
|
|
||||||
if (Post::exists($condition)) {
|
|
||||||
DI::logger()->notice('duplicated item with the same uri found.', $condition);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// On Friendica and Diaspora the GUID is unique
|
|
||||||
if (in_array($item['network'], [Protocol::DFRN, Protocol::DIASPORA])) {
|
|
||||||
$condition = ['guid' => $item['guid'], 'uid' => $item['uid']];
|
|
||||||
if (Post::exists($condition)) {
|
|
||||||
DI::logger()->notice('duplicated item with the same guid found.', $condition);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for already added items.
|
|
||||||
* There is a timing issue here that sometimes creates double postings.
|
|
||||||
* An unique index would help - but the limitations of MySQL (maximum size of index values) prevent this.
|
|
||||||
*/
|
|
||||||
if (($item['uid'] == 0) && Post::exists(['uri-id' => $item['uri-id'], 'uid' => 0])) {
|
|
||||||
DI::logger()->notice('Global item already stored.', ['uri-id' => $item['uri-id'], 'network' => $item['network']]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the item array is valid
|
* Check if the item array is valid
|
||||||
*
|
*
|
||||||
|
@ -694,42 +648,6 @@ class Item
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the id of the given item array if it has been stored before
|
|
||||||
*
|
|
||||||
* @param array $item Item record
|
|
||||||
* @return integer Item id or zero on error
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
];
|
|
||||||
$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
|
|
||||||
if ($item['uid'] != 0) {
|
|
||||||
DI::logger()->notice('Item already existed for user', [
|
|
||||||
'uri-id' => $item['uri-id'],
|
|
||||||
'uid' => $item['uid'],
|
|
||||||
'network' => $item['network'],
|
|
||||||
'existing_id' => $existing['id'],
|
|
||||||
'existing_network' => $existing['network']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $existing['id'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the uri-id of the parent for the given uri-id
|
* Fetch the uri-id of the parent for the given uri-id
|
||||||
*
|
*
|
||||||
|
@ -750,106 +668,6 @@ class Item
|
||||||
return self::getParent($thread_parent['thr-parent-id']);
|
return self::getParent($thread_parent['thr-parent-id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch top-level parent data for the given item array
|
|
||||||
*
|
|
||||||
* @param array $item
|
|
||||||
* @return array item array with parent data
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
private static function getTopLevelParent(array $item): array
|
|
||||||
{
|
|
||||||
$fields = [
|
|
||||||
'uid', 'uri', 'parent-uri', 'id', 'deleted',
|
|
||||||
'uri-id', 'parent-uri-id', 'restrictions', 'verb',
|
|
||||||
'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
|
|
||||||
'wall', 'private', 'origin', 'author-id'
|
|
||||||
];
|
|
||||||
$condition = ['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => $item['uid']];
|
|
||||||
$params = ['order' => ['id' => false]];
|
|
||||||
$parent = Post::selectFirst($fields, $condition, $params);
|
|
||||||
|
|
||||||
if (!DBA::isResult($parent) && Post::exists(['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => 0])) {
|
|
||||||
$stored = Item::storeForUserByUriId($item['thr-parent-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
|
|
||||||
if (!$stored && ($item['thr-parent-id'] != $item['parent-uri-id'])) {
|
|
||||||
$stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
|
|
||||||
}
|
|
||||||
if ($stored) {
|
|
||||||
DI::logger()->info('Stored thread parent item for user', ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid'], 'stored' => $stored]);
|
|
||||||
$parent = Post::selectFirst($fields, $condition, $params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DBA::isResult($parent)) {
|
|
||||||
DI::logger()->notice('item parent was not found - ignoring item', ['uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::hasRestrictions($item, $parent['author-id'], $parent['restrictions'])) {
|
|
||||||
DI::logger()->notice('Restrictions apply - ignoring item', ['restrictions' => $parent['restrictions'], 'verb' => $parent['verb'], 'uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($parent['uri-id'] == $parent['parent-uri-id']) {
|
|
||||||
return $parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
$condition = [
|
|
||||||
'uri-id' => $parent['parent-uri-id'],
|
|
||||||
'parent-uri-id' => $parent['parent-uri-id'],
|
|
||||||
'uid' => $parent['uid']
|
|
||||||
];
|
|
||||||
$params = ['order' => ['id' => false]];
|
|
||||||
$toplevel_parent = Post::selectFirst($fields, $condition, $params);
|
|
||||||
|
|
||||||
if (!DBA::isResult($toplevel_parent) && $item['origin']) {
|
|
||||||
$stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
|
|
||||||
DI::logger()->info('Stored parent item for user', ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid'], 'stored' => $stored]);
|
|
||||||
$toplevel_parent = Post::selectFirst($fields, $condition, $params);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DBA::isResult($toplevel_parent)) {
|
|
||||||
DI::logger()->notice('item top level parent was not found - ignoring item', ['parent-uri-id' => $parent['parent-uri-id'], 'uid' => $parent['uid']]);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $toplevel_parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the gravity for the given item array
|
|
||||||
*
|
|
||||||
* @param array $item
|
|
||||||
* @return integer gravity
|
|
||||||
*/
|
|
||||||
private static function getGravity(array $item): int
|
|
||||||
{
|
|
||||||
$activity = DI::activity();
|
|
||||||
|
|
||||||
if (isset($item['gravity'])) {
|
|
||||||
return intval($item['gravity']);
|
|
||||||
} elseif ($item['parent-uri-id'] === $item['uri-id']) {
|
|
||||||
return self::GRAVITY_PARENT;
|
|
||||||
} elseif ($activity->match($item['verb'], Activity::POST)) {
|
|
||||||
return self::GRAVITY_COMMENT;
|
|
||||||
} elseif ($activity->match($item['verb'], Activity::FOLLOW)) {
|
|
||||||
return self::GRAVITY_ACTIVITY;
|
|
||||||
} elseif ($activity->match($item['verb'], Activity::ANNOUNCE)) {
|
|
||||||
return self::GRAVITY_ACTIVITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
DI::logger()->info('Unknown gravity for verb', ['verb' => $item['verb']]);
|
|
||||||
return self::GRAVITY_UNKNOWN; // Should not happen
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function prepareOriginPost(array $item): array
|
|
||||||
{
|
|
||||||
$item = DI::contentItem()->initializePost($item);
|
|
||||||
$item = DI::contentItem()->finalizePost($item, false);
|
|
||||||
|
|
||||||
return $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts item record
|
* Inserts item record
|
||||||
*
|
*
|
||||||
|
@ -860,6 +678,14 @@ class Item
|
||||||
*/
|
*/
|
||||||
public static function insert(array $item, int $notify = 0, bool $post_local = true): int
|
public static function insert(array $item, int $notify = 0, bool $post_local = true): int
|
||||||
{
|
{
|
||||||
|
$itemHelper = new ItemHelper(
|
||||||
|
DI::contentItem(),
|
||||||
|
DI::activity(),
|
||||||
|
DI::logger(),
|
||||||
|
DI::dba(),
|
||||||
|
DI::baseUrl(),
|
||||||
|
);
|
||||||
|
|
||||||
$orig_item = $item;
|
$orig_item = $item;
|
||||||
|
|
||||||
$priority = Worker::PRIORITY_HIGH;
|
$priority = Worker::PRIORITY_HIGH;
|
||||||
|
@ -868,7 +694,7 @@ class Item
|
||||||
|
|
||||||
// If it is a posting where users should get notifications, then define it as wall posting
|
// If it is a posting where users should get notifications, then define it as wall posting
|
||||||
if ($notify) {
|
if ($notify) {
|
||||||
$item = self::prepareOriginPost($item);
|
$item = $itemHelper->prepareOriginPost($item);
|
||||||
|
|
||||||
if (is_int($notify) && in_array($notify, Worker::PRIORITIES)) {
|
if (is_int($notify) && in_array($notify, Worker::PRIORITIES)) {
|
||||||
$priority = $notify;
|
$priority = $notify;
|
||||||
|
@ -881,23 +707,7 @@ class Item
|
||||||
$item['network'] = trim(($item['network'] ?? '') ?: Protocol::PHANTOM);
|
$item['network'] = trim(($item['network'] ?? '') ?: Protocol::PHANTOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
$uid = intval($item['uid']);
|
$item = $itemHelper->prepareItemData($item, (bool) $notify);
|
||||||
|
|
||||||
$item['guid'] = self::guid($item, $notify);
|
|
||||||
$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']]);
|
|
||||||
|
|
||||||
// Backward compatibility: parent-uri used to be the direct parent uri.
|
|
||||||
// If it is provided without a thr-parent, it probably is the old behavior.
|
|
||||||
if (empty($item['thr-parent']) || empty($item['parent-uri'])) {
|
|
||||||
$item['thr-parent'] = trim($item['thr-parent'] ?? $item['parent-uri'] ?? $item['uri']);
|
|
||||||
$item['parent-uri'] = $item['thr-parent'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$item['thr-parent-id'] = ItemURI::getIdByURI($item['thr-parent']);
|
|
||||||
$item['parent-uri-id'] = ItemURI::getIdByURI($item['parent-uri']);
|
|
||||||
|
|
||||||
// Store conversation data
|
// Store conversation data
|
||||||
$source = $item['source'] ?? '';
|
$source = $item['source'] ?? '';
|
||||||
|
@ -910,14 +720,14 @@ class Item
|
||||||
* We have to check several networks since Friendica posts could be repeated
|
* We have to check several networks since Friendica posts could be repeated
|
||||||
* via Diaspora.
|
* via Diaspora.
|
||||||
*/
|
*/
|
||||||
$duplicate = self::getDuplicateID($item);
|
$duplicate = $itemHelper->getDuplicateID($item);
|
||||||
if ($duplicate) {
|
if ($duplicate) {
|
||||||
return $duplicate;
|
return $duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional duplicate checks
|
// Additional duplicate checks
|
||||||
/// @todo Check why the first duplication check returns the item number and the second a 0
|
/// @todo Check why the first duplication check returns the item number and the second a 0
|
||||||
if (self::isDuplicate($item)) {
|
if ($itemHelper->isDuplicate($item)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,44 +737,7 @@ class Item
|
||||||
|
|
||||||
$defined_permissions = isset($item['allow_cid']) && isset($item['allow_gid']) && isset($item['deny_cid']) && isset($item['deny_gid']) && isset($item['private']);
|
$defined_permissions = isset($item['allow_cid']) && isset($item['allow_gid']) && isset($item['deny_cid']) && isset($item['deny_gid']) && isset($item['private']);
|
||||||
|
|
||||||
$item['wall'] = intval($item['wall'] ?? 0);
|
$uid = intval($item['uid']);
|
||||||
$item['extid'] = trim($item['extid'] ?? '');
|
|
||||||
$item['author-name'] = trim($item['author-name'] ?? '');
|
|
||||||
$item['author-link'] = trim($item['author-link'] ?? '');
|
|
||||||
$item['author-avatar'] = trim($item['author-avatar'] ?? '');
|
|
||||||
$item['owner-name'] = trim($item['owner-name'] ?? '');
|
|
||||||
$item['owner-link'] = trim($item['owner-link'] ?? '');
|
|
||||||
$item['owner-avatar'] = trim($item['owner-avatar'] ?? '');
|
|
||||||
$item['received'] = (isset($item['received']) ? DateTimeFormat::utc($item['received']) : DateTimeFormat::utcNow());
|
|
||||||
$item['created'] = (isset($item['created']) ? DateTimeFormat::utc($item['created']) : $item['received']);
|
|
||||||
$item['edited'] = (isset($item['edited']) ? DateTimeFormat::utc($item['edited']) : $item['created']);
|
|
||||||
$item['changed'] = (isset($item['changed']) ? DateTimeFormat::utc($item['changed']) : $item['created']);
|
|
||||||
$item['commented'] = (isset($item['commented']) ? DateTimeFormat::utc($item['commented']) : $item['created']);
|
|
||||||
$item['title'] = substr(trim($item['title'] ?? ''), 0, 255);
|
|
||||||
$item['location'] = trim($item['location'] ?? '');
|
|
||||||
$item['coord'] = trim($item['coord'] ?? '');
|
|
||||||
$item['visible'] = (isset($item['visible']) ? intval($item['visible']) : 1);
|
|
||||||
$item['deleted'] = 0;
|
|
||||||
$item['verb'] = trim($item['verb'] ?? '');
|
|
||||||
$item['object-type'] = trim($item['object-type'] ?? '');
|
|
||||||
$item['object'] = trim($item['object'] ?? '');
|
|
||||||
$item['target-type'] = trim($item['target-type'] ?? '');
|
|
||||||
$item['target'] = trim($item['target'] ?? '');
|
|
||||||
$item['plink'] = substr(trim($item['plink'] ?? ''), 0, 255);
|
|
||||||
$item['allow_cid'] = trim($item['allow_cid'] ?? '');
|
|
||||||
$item['allow_gid'] = trim($item['allow_gid'] ?? '');
|
|
||||||
$item['deny_cid'] = trim($item['deny_cid'] ?? '');
|
|
||||||
$item['deny_gid'] = trim($item['deny_gid'] ?? '');
|
|
||||||
$item['private'] = intval($item['private'] ?? self::PUBLIC);
|
|
||||||
$item['body'] = trim($item['body'] ?? '');
|
|
||||||
$item['raw-body'] = trim($item['raw-body'] ?? $item['body']);
|
|
||||||
$item['app'] = trim($item['app'] ?? '');
|
|
||||||
$item['origin'] = intval($item['origin'] ?? 0);
|
|
||||||
$item['postopts'] = trim($item['postopts'] ?? '');
|
|
||||||
$item['resource-id'] = trim($item['resource-id'] ?? '');
|
|
||||||
$item['event-id'] = intval($item['event-id'] ?? 0);
|
|
||||||
$item['inform'] = trim($item['inform'] ?? '');
|
|
||||||
$item['file'] = trim($item['file'] ?? '');
|
|
||||||
|
|
||||||
// Communities aren't working with the Diaspora protocol
|
// Communities aren't working with the Diaspora protocol
|
||||||
if (($uid != 0) && ($item['network'] == Protocol::DIASPORA)) {
|
if (($uid != 0) && ($item['network'] == Protocol::DIASPORA)) {
|
||||||
|
@ -975,33 +748,7 @@ class Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Items cannot be stored before they happen ...
|
$item = $itemHelper->validateItemData($item);
|
||||||
if ($item['created'] > DateTimeFormat::utcNow()) {
|
|
||||||
$item['created'] = DateTimeFormat::utcNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We haven't invented time travel by now.
|
|
||||||
if ($item['edited'] > DateTimeFormat::utcNow()) {
|
|
||||||
$item['edited'] = DateTimeFormat::utcNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
$item['plink'] = ($item['plink'] ?? '') ?: DI::baseUrl() . '/display/' . urlencode($item['guid']);
|
|
||||||
|
|
||||||
$item['gravity'] = self::getGravity($item);
|
|
||||||
|
|
||||||
$default = [
|
|
||||||
'url' => $item['author-link'], 'name' => $item['author-name'],
|
|
||||||
'photo' => $item['author-avatar'], 'network' => $item['network']
|
|
||||||
];
|
|
||||||
$item['author-id'] = ($item['author-id'] ?? 0) ?: Contact::getIdForURL($item['author-link'], 0, null, $default);
|
|
||||||
|
|
||||||
$default = [
|
|
||||||
'url' => $item['owner-link'], 'name' => $item['owner-name'],
|
|
||||||
'photo' => $item['owner-avatar'], 'network' => $item['network']
|
|
||||||
];
|
|
||||||
$item['owner-id'] = ($item['owner-id'] ?? 0) ?: Contact::getIdForURL($item['owner-link'], 0, null, $default);
|
|
||||||
|
|
||||||
$item['post-reason'] = self::getPostReason($item);
|
|
||||||
|
|
||||||
// Ensure that there is an avatar cache
|
// Ensure that there is an avatar cache
|
||||||
Contact::checkAvatarCache($item['author-id']);
|
Contact::checkAvatarCache($item['author-id']);
|
||||||
|
@ -1022,55 +769,14 @@ class Item
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($item['gravity'] !== self::GRAVITY_PARENT) {
|
if ($item['gravity'] !== self::GRAVITY_PARENT) {
|
||||||
$toplevel_parent = self::getTopLevelParent($item);
|
$toplevel_parent = $itemHelper->getTopLevelParent($item);
|
||||||
if (empty($toplevel_parent)) {
|
if (empty($toplevel_parent)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$parent_id = $toplevel_parent['id'];
|
$parent_id = (int) $toplevel_parent['id'];
|
||||||
$item['parent-uri'] = $toplevel_parent['uri'];
|
$item = $itemHelper->handleToplevelParent($item, $toplevel_parent, $defined_permissions);
|
||||||
$item['parent-uri-id'] = $toplevel_parent['uri-id'];
|
|
||||||
$item['deleted'] = $toplevel_parent['deleted'];
|
|
||||||
$item['wall'] = $toplevel_parent['wall'];
|
|
||||||
|
|
||||||
// Reshares have to keep their permissions to allow groups to work
|
|
||||||
if (!$defined_permissions && (!$item['origin'] || ($item['verb'] != Activity::ANNOUNCE))) {
|
|
||||||
// Don't store the permissions on pure AP posts
|
|
||||||
$store_permissions = ($item['network'] != Protocol::ACTIVITYPUB) || $item['origin'] || !empty($item['diaspora_signed_text']);
|
|
||||||
$item['allow_cid'] = $store_permissions ? $toplevel_parent['allow_cid'] : '';
|
|
||||||
$item['allow_gid'] = $store_permissions ? $toplevel_parent['allow_gid'] : '';
|
|
||||||
$item['deny_cid'] = $store_permissions ? $toplevel_parent['deny_cid'] : '';
|
|
||||||
$item['deny_gid'] = $store_permissions ? $toplevel_parent['deny_gid'] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$parent_origin = $toplevel_parent['origin'];
|
$parent_origin = $toplevel_parent['origin'];
|
||||||
|
|
||||||
// Don't federate received participation messages
|
|
||||||
if ($item['verb'] != Activity::FOLLOW) {
|
|
||||||
$item['wall'] = $toplevel_parent['wall'];
|
|
||||||
} else {
|
|
||||||
$item['wall'] = false;
|
|
||||||
// Participations are technical messages, so they are set to "seen" automatically
|
|
||||||
$item['unseen'] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the parent is private, force privacy for the entire conversation
|
|
||||||
* This differs from the above settings as it subtly allows comments from
|
|
||||||
* email correspondents to be private even if the overall thread is not.
|
|
||||||
*/
|
|
||||||
if (!$defined_permissions && $toplevel_parent['private']) {
|
|
||||||
$item['private'] = $toplevel_parent['private'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If its a post that originated here then tag the thread as "mention"
|
|
||||||
if ($item['origin'] && $item['uid']) {
|
|
||||||
DBA::update('post-thread-user', ['mention' => true], ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
|
|
||||||
DI::logger()->info('tagged thread as mention', ['parent' => $parent_id, 'parent-uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the contact relations
|
|
||||||
Contact\Relation::store($toplevel_parent['author-id'], $item['author-id'], $item['created']);
|
|
||||||
} else {
|
} else {
|
||||||
$parent_id = 0;
|
$parent_id = 0;
|
||||||
$parent_origin = $item['origin'];
|
$parent_origin = $item['origin'];
|
||||||
|
@ -1344,6 +1050,11 @@ class Item
|
||||||
|
|
||||||
DI::logger()->notice('created item', ['post-id' => $post_user_id, 'uid' => $item['uid'], 'network' => $item['network'], 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]);
|
DI::logger()->notice('created item', ['post-id' => $post_user_id, 'uid' => $item['uid'], 'network' => $item['network'], 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]);
|
||||||
|
|
||||||
|
return self::handleCreatedItem($orig_item, $post_user_id, $uid, $notify, $copy_permissions, $parent_origin, $priority, $notify_type, $inserted, $source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function handleCreatedItem(array $orig_item, int $post_user_id, int $uid, int $notify, bool $copy_permissions, $parent_origin, int $priority, string $notify_type, bool $inserted, $source): int
|
||||||
|
{
|
||||||
$posted_item = Post::selectFirst(self::ITEM_FIELDLIST, ['post-user-id' => $post_user_id]);
|
$posted_item = Post::selectFirst(self::ITEM_FIELDLIST, ['post-user-id' => $post_user_id]);
|
||||||
if (!DBA::isResult($posted_item)) {
|
if (!DBA::isResult($posted_item)) {
|
||||||
// On failure store the data into a spool file so that the "SpoolPost" worker can try again later.
|
// On failure store the data into a spool file so that the "SpoolPost" worker can try again later.
|
||||||
|
@ -1484,33 +1195,6 @@ class Item
|
||||||
return $post_user_id;
|
return $post_user_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function hasRestrictions(array $item, int $author_id, int $restrictions = null): bool
|
|
||||||
{
|
|
||||||
if (empty($restrictions) || ($author_id == $item['author-id'])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only have to apply restrictions if the post originates from our server or is federated.
|
|
||||||
// Every other time we can trust the remote system.
|
|
||||||
if (!in_array($item['network'], Protocol::FEDERATED) && !$item['origin']) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($restrictions & self::CANT_REPLY) && ($item['verb'] == Activity::POST)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($restrictions & self::CANT_ANNOUNCE) && ($item['verb'] == Activity::ANNOUNCE)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($restrictions & self::CANT_LIKE) && in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE, Activity::ATTEND, Activity::ATTENDMAYBE, Activity::ATTENDNO])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function reshareChannelPost(int $uri_id, int $reshare_id = 0)
|
private static function reshareChannelPost(int $uri_id, int $reshare_id = 0)
|
||||||
{
|
{
|
||||||
if (!DI::config()->get('system', 'allow_relay_channels')) {
|
if (!DI::config()->get('system', 'allow_relay_channels')) {
|
||||||
|
@ -1890,7 +1574,7 @@ class Item
|
||||||
*
|
*
|
||||||
* @param int $uriid
|
* @param int $uriid
|
||||||
* @param int $uid
|
* @param int $uid
|
||||||
* @return int
|
* @return int|null
|
||||||
*/
|
*/
|
||||||
private static function GetOriginUidForUriId(int $uriid, int $uid)
|
private static function GetOriginUidForUriId(int $uriid, int $uid)
|
||||||
{
|
{
|
||||||
|
|
404
src/Model/ItemHelper.php
Normal file
404
src/Model/ItemHelper.php
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Copyright (C) 2010-2024, the Friendica project
|
||||||
|
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
namespace Friendica\Model;
|
||||||
|
|
||||||
|
use Friendica\App\BaseURL;
|
||||||
|
use Friendica\Content\Item as ItemContent;
|
||||||
|
use Friendica\Core\Protocol;
|
||||||
|
use Friendica\Database\Database;
|
||||||
|
use Friendica\Protocol\Activity;
|
||||||
|
use Friendica\Util\DateTimeFormat;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class for handling an Item Model
|
||||||
|
*
|
||||||
|
* @internal ONLY for use in Friendica\Content\Item class
|
||||||
|
*
|
||||||
|
* @see Item::insert()
|
||||||
|
*/
|
||||||
|
final class ItemHelper
|
||||||
|
{
|
||||||
|
private ItemContent $itemContent;
|
||||||
|
|
||||||
|
private Activity $activity;
|
||||||
|
|
||||||
|
private LoggerInterface $logger;
|
||||||
|
|
||||||
|
private Database $database;
|
||||||
|
|
||||||
|
private string $baseUrl;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ItemContent $itemContent,
|
||||||
|
Activity $activity,
|
||||||
|
LoggerInterface $logger,
|
||||||
|
Database $database,
|
||||||
|
BaseURL $baseURL
|
||||||
|
) {
|
||||||
|
$this->itemContent = $itemContent;
|
||||||
|
$this->activity = $activity;
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->database = $database;
|
||||||
|
$this->baseUrl = $baseURL->__toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareOriginPost(array $item): array
|
||||||
|
{
|
||||||
|
$item = $this->itemContent->initializePost($item);
|
||||||
|
$item = $this->itemContent->finalizePost($item, false);
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareItemData(array $item, bool $notify): array
|
||||||
|
{
|
||||||
|
$item['guid'] = Item::guid($item, $notify);
|
||||||
|
$item['uri'] = substr(trim($item['uri'] ?? '') ?: Item::newURI($item['guid']), 0, 255);
|
||||||
|
|
||||||
|
// Store URI data
|
||||||
|
$item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]);
|
||||||
|
|
||||||
|
// Backward compatibility: parent-uri used to be the direct parent uri.
|
||||||
|
// If it is provided without a thr-parent, it probably is the old behavior.
|
||||||
|
if (empty($item['thr-parent']) || empty($item['parent-uri'])) {
|
||||||
|
$item['thr-parent'] = trim($item['thr-parent'] ?? $item['parent-uri'] ?? $item['uri']);
|
||||||
|
$item['parent-uri'] = $item['thr-parent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$item['thr-parent-id'] = ItemURI::getIdByURI($item['thr-parent']);
|
||||||
|
$item['parent-uri-id'] = ItemURI::getIdByURI($item['parent-uri']);
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the id of the given item array if it has been stored before
|
||||||
|
*
|
||||||
|
* @param array $item Item record
|
||||||
|
* @return integer Item id or zero on error
|
||||||
|
*/
|
||||||
|
public 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
|
||||||
|
];
|
||||||
|
|
||||||
|
$existing = Post::selectFirst(['id', 'network'], $condition);
|
||||||
|
|
||||||
|
if ($this->database->isResult($existing)) {
|
||||||
|
// We only log the entries with a different user id than 0. Otherwise we would have too many false positives
|
||||||
|
if ($item['uid'] != 0) {
|
||||||
|
$this->logger->notice('Item already existed for user', [
|
||||||
|
'uri-id' => $item['uri-id'],
|
||||||
|
'uid' => $item['uid'],
|
||||||
|
'network' => $item['network'],
|
||||||
|
'existing_id' => $existing['id'],
|
||||||
|
'existing_network' => $existing['network']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $existing['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the item array is a duplicate
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*
|
||||||
|
* @param array $item Item record
|
||||||
|
* @return boolean is it a duplicate?
|
||||||
|
*/
|
||||||
|
public 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']];
|
||||||
|
if (Post::exists($condition)) {
|
||||||
|
$this->logger->notice('Found already existing item', $condition);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$condition = [
|
||||||
|
'uri-id' => $item['uri-id'], 'uid' => $item['uid'],
|
||||||
|
'network' => [$item['network'], Protocol::DFRN]
|
||||||
|
];
|
||||||
|
if (Post::exists($condition)) {
|
||||||
|
$this->logger->notice('duplicated item with the same uri found.', $condition);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Friendica and Diaspora the GUID is unique
|
||||||
|
if (in_array($item['network'], [Protocol::DFRN, Protocol::DIASPORA])) {
|
||||||
|
$condition = ['guid' => $item['guid'], 'uid' => $item['uid']];
|
||||||
|
if (Post::exists($condition)) {
|
||||||
|
$this->logger->notice('duplicated item with the same guid found.', $condition);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for already added items.
|
||||||
|
* There is a timing issue here that sometimes creates double postings.
|
||||||
|
* An unique index would help - but the limitations of MySQL (maximum size of index values) prevent this.
|
||||||
|
*/
|
||||||
|
if (($item['uid'] == 0) && Post::exists(['uri-id' => $item['uri-id'], 'uid' => 0])) {
|
||||||
|
$this->logger->notice('Global item already stored.', ['uri-id' => $item['uri-id'], 'network' => $item['network']]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateItemData(array $item): array
|
||||||
|
{
|
||||||
|
$item['wall'] = intval($item['wall'] ?? 0);
|
||||||
|
$item['extid'] = trim($item['extid'] ?? '');
|
||||||
|
$item['author-name'] = trim($item['author-name'] ?? '');
|
||||||
|
$item['author-link'] = trim($item['author-link'] ?? '');
|
||||||
|
$item['author-avatar'] = trim($item['author-avatar'] ?? '');
|
||||||
|
$item['owner-name'] = trim($item['owner-name'] ?? '');
|
||||||
|
$item['owner-link'] = trim($item['owner-link'] ?? '');
|
||||||
|
$item['owner-avatar'] = trim($item['owner-avatar'] ?? '');
|
||||||
|
$item['received'] = (isset($item['received']) ? DateTimeFormat::utc($item['received']) : DateTimeFormat::utcNow());
|
||||||
|
$item['created'] = (isset($item['created']) ? DateTimeFormat::utc($item['created']) : $item['received']);
|
||||||
|
$item['edited'] = (isset($item['edited']) ? DateTimeFormat::utc($item['edited']) : $item['created']);
|
||||||
|
$item['changed'] = (isset($item['changed']) ? DateTimeFormat::utc($item['changed']) : $item['created']);
|
||||||
|
$item['commented'] = (isset($item['commented']) ? DateTimeFormat::utc($item['commented']) : $item['created']);
|
||||||
|
$item['title'] = substr(trim($item['title'] ?? ''), 0, 255);
|
||||||
|
$item['location'] = trim($item['location'] ?? '');
|
||||||
|
$item['coord'] = trim($item['coord'] ?? '');
|
||||||
|
$item['visible'] = (isset($item['visible']) ? intval($item['visible']) : 1);
|
||||||
|
$item['deleted'] = 0;
|
||||||
|
$item['verb'] = trim($item['verb'] ?? '');
|
||||||
|
$item['object-type'] = trim($item['object-type'] ?? '');
|
||||||
|
$item['object'] = trim($item['object'] ?? '');
|
||||||
|
$item['target-type'] = trim($item['target-type'] ?? '');
|
||||||
|
$item['target'] = trim($item['target'] ?? '');
|
||||||
|
$item['plink'] = substr(trim($item['plink'] ?? ''), 0, 255);
|
||||||
|
$item['allow_cid'] = trim($item['allow_cid'] ?? '');
|
||||||
|
$item['allow_gid'] = trim($item['allow_gid'] ?? '');
|
||||||
|
$item['deny_cid'] = trim($item['deny_cid'] ?? '');
|
||||||
|
$item['deny_gid'] = trim($item['deny_gid'] ?? '');
|
||||||
|
$item['private'] = intval($item['private'] ?? Item::PUBLIC);
|
||||||
|
$item['body'] = trim($item['body'] ?? '');
|
||||||
|
$item['raw-body'] = trim($item['raw-body'] ?? $item['body']);
|
||||||
|
$item['app'] = trim($item['app'] ?? '');
|
||||||
|
$item['origin'] = intval($item['origin'] ?? 0);
|
||||||
|
$item['postopts'] = trim($item['postopts'] ?? '');
|
||||||
|
$item['resource-id'] = trim($item['resource-id'] ?? '');
|
||||||
|
$item['event-id'] = intval($item['event-id'] ?? 0);
|
||||||
|
$item['inform'] = trim($item['inform'] ?? '');
|
||||||
|
$item['file'] = trim($item['file'] ?? '');
|
||||||
|
|
||||||
|
// Items cannot be stored before they happen ...
|
||||||
|
if ($item['created'] > DateTimeFormat::utcNow()) {
|
||||||
|
$item['created'] = DateTimeFormat::utcNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We haven't invented time travel by now.
|
||||||
|
if ($item['edited'] > DateTimeFormat::utcNow()) {
|
||||||
|
$item['edited'] = DateTimeFormat::utcNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
$item['plink'] = ($item['plink'] ?? '') ?: $this->baseUrl . '/display/' . urlencode($item['guid']);
|
||||||
|
|
||||||
|
$item['gravity'] = $this->getGravity($item);
|
||||||
|
|
||||||
|
if ($item['gravity'] === Item::GRAVITY_UNKNOWN) {
|
||||||
|
$this->logger->info('Unknown gravity for verb', ['verb' => $item['verb']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$default = [
|
||||||
|
'url' => $item['author-link'], 'name' => $item['author-name'],
|
||||||
|
'photo' => $item['author-avatar'], 'network' => $item['network']
|
||||||
|
];
|
||||||
|
$item['author-id'] = ($item['author-id'] ?? 0) ?: Contact::getIdForURL($item['author-link'], 0, null, $default);
|
||||||
|
|
||||||
|
$default = [
|
||||||
|
'url' => $item['owner-link'], 'name' => $item['owner-name'],
|
||||||
|
'photo' => $item['owner-avatar'], 'network' => $item['network']
|
||||||
|
];
|
||||||
|
$item['owner-id'] = ($item['owner-id'] ?? 0) ?: Contact::getIdForURL($item['owner-link'], 0, null, $default);
|
||||||
|
|
||||||
|
$item['post-reason'] = Item::getPostReason($item);
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch top-level parent data for the given item array
|
||||||
|
*
|
||||||
|
* @param array $item
|
||||||
|
* @return array item array with parent data
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function getTopLevelParent(array $item): array
|
||||||
|
{
|
||||||
|
$fields = [
|
||||||
|
'uid', 'uri', 'parent-uri', 'id', 'deleted',
|
||||||
|
'uri-id', 'parent-uri-id', 'restrictions', 'verb',
|
||||||
|
'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
|
||||||
|
'wall', 'private', 'origin', 'author-id'
|
||||||
|
];
|
||||||
|
$condition = ['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => $item['uid']];
|
||||||
|
$params = ['order' => ['id' => false]];
|
||||||
|
$parent = Post::selectFirst($fields, $condition, $params);
|
||||||
|
|
||||||
|
if (!$this->database->isResult($parent) && Post::exists(['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => 0])) {
|
||||||
|
$stored = Item::storeForUserByUriId($item['thr-parent-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
|
||||||
|
if (!$stored && ($item['thr-parent-id'] != $item['parent-uri-id'])) {
|
||||||
|
$stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
|
||||||
|
}
|
||||||
|
if ($stored) {
|
||||||
|
$this->logger->info('Stored thread parent item for user', ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid'], 'stored' => $stored]);
|
||||||
|
$parent = Post::selectFirst($fields, $condition, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->database->isResult($parent)) {
|
||||||
|
$this->logger->notice('item parent was not found - ignoring item', ['uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasRestrictions($item, $parent['author-id'], $parent['restrictions'])) {
|
||||||
|
$this->logger->notice('Restrictions apply - ignoring item', ['restrictions' => $parent['restrictions'], 'verb' => $parent['verb'], 'uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($parent['uri-id'] == $parent['parent-uri-id']) {
|
||||||
|
return $parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
$condition = [
|
||||||
|
'uri-id' => $parent['parent-uri-id'],
|
||||||
|
'parent-uri-id' => $parent['parent-uri-id'],
|
||||||
|
'uid' => $parent['uid']
|
||||||
|
];
|
||||||
|
$params = ['order' => ['id' => false]];
|
||||||
|
$toplevel_parent = Post::selectFirst($fields, $condition, $params);
|
||||||
|
|
||||||
|
if (!$this->database->isResult($toplevel_parent) && $item['origin']) {
|
||||||
|
$stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
|
||||||
|
$this->logger->info('Stored parent item for user', ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid'], 'stored' => $stored]);
|
||||||
|
$toplevel_parent = Post::selectFirst($fields, $condition, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->database->isResult($toplevel_parent)) {
|
||||||
|
$this->logger->notice('item top level parent was not found - ignoring item', ['parent-uri-id' => $parent['parent-uri-id'], 'uid' => $parent['uid']]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $toplevel_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleToplevelParent(array $item, array $toplevel_parent, bool $defined_permissions): array
|
||||||
|
{
|
||||||
|
$parent_id = (int) $toplevel_parent['id'];
|
||||||
|
$item['parent-uri'] = $toplevel_parent['uri'];
|
||||||
|
$item['parent-uri-id'] = $toplevel_parent['uri-id'];
|
||||||
|
$item['deleted'] = $toplevel_parent['deleted'];
|
||||||
|
$item['wall'] = $toplevel_parent['wall'];
|
||||||
|
|
||||||
|
// Reshares have to keep their permissions to allow groups to work
|
||||||
|
if (!$defined_permissions && (!$item['origin'] || ($item['verb'] != Activity::ANNOUNCE))) {
|
||||||
|
// Don't store the permissions on pure AP posts
|
||||||
|
$store_permissions = ($item['network'] != Protocol::ACTIVITYPUB) || $item['origin'] || !empty($item['diaspora_signed_text']);
|
||||||
|
$item['allow_cid'] = $store_permissions ? $toplevel_parent['allow_cid'] : '';
|
||||||
|
$item['allow_gid'] = $store_permissions ? $toplevel_parent['allow_gid'] : '';
|
||||||
|
$item['deny_cid'] = $store_permissions ? $toplevel_parent['deny_cid'] : '';
|
||||||
|
$item['deny_gid'] = $store_permissions ? $toplevel_parent['deny_gid'] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't federate received participation messages
|
||||||
|
if ($item['verb'] != Activity::FOLLOW) {
|
||||||
|
$item['wall'] = $toplevel_parent['wall'];
|
||||||
|
} else {
|
||||||
|
$item['wall'] = false;
|
||||||
|
// Participations are technical messages, so they are set to "seen" automatically
|
||||||
|
$item['unseen'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the parent is private, force privacy for the entire conversation
|
||||||
|
* This differs from the above settings as it subtly allows comments from
|
||||||
|
* email correspondents to be private even if the overall thread is not.
|
||||||
|
*/
|
||||||
|
if (!$defined_permissions && $toplevel_parent['private']) {
|
||||||
|
$item['private'] = $toplevel_parent['private'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If its a post that originated here then tag the thread as "mention"
|
||||||
|
if ($item['origin'] && $item['uid']) {
|
||||||
|
$this->database->update('post-thread-user', ['mention' => true], ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
|
||||||
|
$this->logger->info('tagged thread as mention', ['parent' => $parent_id, 'parent-uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the contact relations
|
||||||
|
Contact\Relation::store($toplevel_parent['author-id'], $item['author-id'], $item['created']);
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasRestrictions(array $item, int $author_id, int $restrictions = null): bool
|
||||||
|
{
|
||||||
|
if (empty($restrictions) || ($author_id == $item['author-id'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only have to apply restrictions if the post originates from our server or is federated.
|
||||||
|
// Every other time we can trust the remote system.
|
||||||
|
if (!in_array($item['network'], Protocol::FEDERATED) && !$item['origin']) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($restrictions & Item::CANT_REPLY) && ($item['verb'] == Activity::POST)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($restrictions & Item::CANT_ANNOUNCE) && ($item['verb'] == Activity::ANNOUNCE)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($restrictions & Item::CANT_LIKE) && in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE, Activity::ATTEND, Activity::ATTENDMAYBE, Activity::ATTENDNO])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the gravity for the given item array
|
||||||
|
*
|
||||||
|
* @return int gravity
|
||||||
|
*/
|
||||||
|
private function getGravity(array $item): int
|
||||||
|
{
|
||||||
|
if (isset($item['gravity'])) {
|
||||||
|
return intval($item['gravity']);
|
||||||
|
} elseif ($item['parent-uri-id'] === $item['uri-id']) {
|
||||||
|
return Item::GRAVITY_PARENT;
|
||||||
|
} elseif ($this->activity->match($item['verb'], Activity::POST)) {
|
||||||
|
return Item::GRAVITY_COMMENT;
|
||||||
|
} elseif ($this->activity->match($item['verb'], Activity::FOLLOW)) {
|
||||||
|
return Item::GRAVITY_ACTIVITY;
|
||||||
|
} elseif ($this->activity->match($item['verb'], Activity::ANNOUNCE)) {
|
||||||
|
return Item::GRAVITY_ACTIVITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Item::GRAVITY_UNKNOWN; // Should not happen
|
||||||
|
}
|
||||||
|
}
|
|
@ -807,25 +807,45 @@ class Transmitter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = self::filterReceiverData($data, $item['author-link']);
|
||||||
|
|
||||||
|
$receivers = ['to' => array_values($data['to']), 'cc' => array_values($data['cc']), 'bto' => array_values($data['bto']), 'bcc' => array_values($data['bcc']), 'audience' => array_values($data['audience'])];
|
||||||
|
|
||||||
|
if (!$blindcopy) {
|
||||||
|
unset($receivers['bto']);
|
||||||
|
unset($receivers['bcc']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$blindcopy && count($receivers['audience']) == 1) {
|
||||||
|
$receivers['audience'] = $receivers['audience'][0];
|
||||||
|
} elseif (!$receivers['audience']) {
|
||||||
|
unset($receivers['audience']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $receivers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function filterReceiverData(array $data, string $author_link): array
|
||||||
|
{
|
||||||
$data['to'] = array_unique($data['to']);
|
$data['to'] = array_unique($data['to']);
|
||||||
$data['cc'] = array_unique($data['cc']);
|
$data['cc'] = array_unique($data['cc']);
|
||||||
$data['bto'] = array_unique($data['bto']);
|
$data['bto'] = array_unique($data['bto']);
|
||||||
$data['bcc'] = array_unique($data['bcc']);
|
$data['bcc'] = array_unique($data['bcc']);
|
||||||
$data['audience'] = array_unique($data['audience']);
|
$data['audience'] = array_unique($data['audience']);
|
||||||
|
|
||||||
if (($key = array_search($item['author-link'], $data['to'])) !== false) {
|
if (($key = array_search($author_link, $data['to'])) !== false) {
|
||||||
unset($data['to'][$key]);
|
unset($data['to'][$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($key = array_search($item['author-link'], $data['cc'])) !== false) {
|
if (($key = array_search($author_link, $data['cc'])) !== false) {
|
||||||
unset($data['cc'][$key]);
|
unset($data['cc'][$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($key = array_search($item['author-link'], $data['bto'])) !== false) {
|
if (($key = array_search($author_link, $data['bto'])) !== false) {
|
||||||
unset($data['bto'][$key]);
|
unset($data['bto'][$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($key = array_search($item['author-link'], $data['bcc'])) !== false) {
|
if (($key = array_search($author_link, $data['bcc'])) !== false) {
|
||||||
unset($data['bcc'][$key]);
|
unset($data['bcc'][$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -859,20 +879,7 @@ class Transmitter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$receivers = ['to' => array_values($data['to']), 'cc' => array_values($data['cc']), 'bto' => array_values($data['bto']), 'bcc' => array_values($data['bcc']), 'audience' => array_values($data['audience'])];
|
return $data;
|
||||||
|
|
||||||
if (!$blindcopy) {
|
|
||||||
unset($receivers['bto']);
|
|
||||||
unset($receivers['bcc']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$blindcopy && count($receivers['audience']) == 1) {
|
|
||||||
$receivers['audience'] = $receivers['audience'][0];
|
|
||||||
} elseif (!$receivers['audience']) {
|
|
||||||
unset($receivers['audience']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $receivers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace Friendica\Protocol;
|
||||||
|
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use DOMElement;
|
use DOMElement;
|
||||||
|
use DOMNode;
|
||||||
|
use DOMNodeList;
|
||||||
use DOMXPath;
|
use DOMXPath;
|
||||||
use Friendica\App;
|
use Friendica\App;
|
||||||
use Friendica\Contact\LocalRelationship\Entity\LocalRelationship;
|
use Friendica\Contact\LocalRelationship\Entity\LocalRelationship;
|
||||||
|
@ -67,12 +69,12 @@ class Feed
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$basepath = '';
|
||||||
|
|
||||||
if (!empty($contact['poll'])) {
|
if (!empty($contact['poll'])) {
|
||||||
$basepath = $contact['poll'];
|
$basepath = (string) $contact['poll'];
|
||||||
} elseif (!empty($contact['url'])) {
|
} elseif (!empty($contact['url'])) {
|
||||||
$basepath = $contact['url'];
|
$basepath = (string) $contact['url'];
|
||||||
} else {
|
|
||||||
$basepath = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$doc = new DOMDocument();
|
$doc = new DOMDocument();
|
||||||
|
@ -287,6 +289,77 @@ class Feed
|
||||||
$total_items = $max_items;
|
$total_items = $max_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$postings = self::importOlderEntries($entries, $total_items, $header, $author, $contact, $importer, $xpath, $atomns, $basepath, $dryRun);
|
||||||
|
|
||||||
|
if (!empty($postings)) {
|
||||||
|
$min_posting = DI::config()->get('system', 'minimum_posting_interval', 0);
|
||||||
|
$total = count($postings);
|
||||||
|
if ($total > 1) {
|
||||||
|
// Posts shouldn't be delayed more than a day
|
||||||
|
$interval = min(1440, self::getPollInterval($contact));
|
||||||
|
$delay = max(round(($interval * 60) / $total), 60 * $min_posting);
|
||||||
|
DI::logger()->info('Got posting delay', ['delay' => $delay, 'interval' => $interval, 'items' => $total, 'cid' => $contact['id'], 'url' => $contact['url']]);
|
||||||
|
} else {
|
||||||
|
$delay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$post_delay = 0;
|
||||||
|
|
||||||
|
foreach ($postings as $posting) {
|
||||||
|
if ($delay > 0) {
|
||||||
|
$publish_time = time() + $post_delay;
|
||||||
|
$post_delay += $delay;
|
||||||
|
} else {
|
||||||
|
$publish_time = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$last_publish = DI::pConfig()->get($posting['item']['uid'], 'system', 'last_publish', 0, true);
|
||||||
|
$next_publish = max($last_publish + (60 * $min_posting), time());
|
||||||
|
if ($publish_time < $next_publish) {
|
||||||
|
$publish_time = $next_publish;
|
||||||
|
}
|
||||||
|
$publish_at = date(DateTimeFormat::MYSQL, $publish_time);
|
||||||
|
|
||||||
|
if (Post\Delayed::add($posting['item']['uri'], $posting['item'], $posting['notify'], Post\Delayed::PREPARED, $publish_at, $posting['taglist'], $posting['attachments'])) {
|
||||||
|
DI::pConfig()->set($posting['item']['uid'], 'system', 'last_publish', $publish_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$dryRun && DI::config()->get('system', 'adjust_poll_frequency')) {
|
||||||
|
self::adjustPollFrequency($contact, $creation_dates);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['header' => $author, 'items' => $items];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getTitleFromItemOrEntry(array $item, DOMXPath $xpath, string $atomns, ?DOMNode $entry): string
|
||||||
|
{
|
||||||
|
$title = (string) $item['title'];
|
||||||
|
|
||||||
|
if (empty($title)) {
|
||||||
|
$title = XML::getFirstNodeValue($xpath, $atomns . ':title/text()', $entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($title)) {
|
||||||
|
$title = XML::getFirstNodeValue($xpath, 'title/text()', $entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($title)) {
|
||||||
|
$title = XML::getFirstNodeValue($xpath, 'rss:title/text()', $entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($title)) {
|
||||||
|
$title = XML::getFirstNodeValue($xpath, 'itunes:title/text()', $entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = trim(html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
|
||||||
|
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function importOlderEntries(DOMNodeList $entries, int $total_items, array $header, array $author, array $contact, array $importer, DOMXPath $xpath, string $atomns, string $basepath, bool $dryRun): array
|
||||||
|
{
|
||||||
$postings = [];
|
$postings = [];
|
||||||
|
|
||||||
// Importing older entries first
|
// Importing older entries first
|
||||||
|
@ -386,23 +459,7 @@ class Feed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($item['title'])) {
|
$item['title'] = self::getTitleFromItemOrEntry($item, $xpath, $atomns, $entry);
|
||||||
$item['title'] = XML::getFirstNodeValue($xpath, $atomns . ':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, 'itunes:title/text()', $entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
$item['title'] = trim(html_entity_decode($item['title'], ENT_QUOTES, 'UTF-8'));
|
|
||||||
|
|
||||||
$published = XML::getFirstNodeValue($xpath, $atomns . ':published/text()', $entry);
|
$published = XML::getFirstNodeValue($xpath, $atomns . ':published/text()', $entry);
|
||||||
|
|
||||||
|
@ -705,46 +762,7 @@ class Feed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($postings)) {
|
return $postings;
|
||||||
$min_posting = DI::config()->get('system', 'minimum_posting_interval', 0);
|
|
||||||
$total = count($postings);
|
|
||||||
if ($total > 1) {
|
|
||||||
// Posts shouldn't be delayed more than a day
|
|
||||||
$interval = min(1440, self::getPollInterval($contact));
|
|
||||||
$delay = max(round(($interval * 60) / $total), 60 * $min_posting);
|
|
||||||
DI::logger()->info('Got posting delay', ['delay' => $delay, 'interval' => $interval, 'items' => $total, 'cid' => $contact['id'], 'url' => $contact['url']]);
|
|
||||||
} else {
|
|
||||||
$delay = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$post_delay = 0;
|
|
||||||
|
|
||||||
foreach ($postings as $posting) {
|
|
||||||
if ($delay > 0) {
|
|
||||||
$publish_time = time() + $post_delay;
|
|
||||||
$post_delay += $delay;
|
|
||||||
} else {
|
|
||||||
$publish_time = time();
|
|
||||||
}
|
|
||||||
|
|
||||||
$last_publish = DI::pConfig()->get($posting['item']['uid'], 'system', 'last_publish', 0, true);
|
|
||||||
$next_publish = max($last_publish + (60 * $min_posting), time());
|
|
||||||
if ($publish_time < $next_publish) {
|
|
||||||
$publish_time = $next_publish;
|
|
||||||
}
|
|
||||||
$publish_at = date(DateTimeFormat::MYSQL, $publish_time);
|
|
||||||
|
|
||||||
if (Post\Delayed::add($posting['item']['uri'], $posting['item'], $posting['notify'], Post\Delayed::PREPARED, $publish_at, $posting['taglist'], $posting['attachments'])) {
|
|
||||||
DI::pConfig()->set($posting['item']['uid'], 'system', 'last_publish', $publish_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$dryRun && DI::config()->get('system', 'adjust_poll_frequency')) {
|
|
||||||
self::adjustPollFrequency($contact, $creation_dates);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['header' => $author, 'items' => $items];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue