Compare commits
167 Commits
Author | SHA1 | Date |
---|---|---|
Tobias Diekershoff | bda829665e | |
Michael | 846addf7b3 | |
Hypolite Petovan | 1f12d1e668 | |
Hypolite Petovan | 570de6a91a | |
Hypolite Petovan | c81ee0d1c3 | |
Michael | 4ce1911889 | |
loma-one | 367170a92a | |
Michael | 0426572e92 | |
Hypolite Petovan | cad3a01b1c | |
Michael | 69b1958483 | |
Hypolite Petovan | 3493b2c1b5 | |
Michael | 1c66d49599 | |
Hypolite Petovan | a6f3c961dc | |
Michael | e12f92e516 | |
Hypolite Petovan | bd6616e84f | |
Michael | 60f5fd8188 | |
Hypolite Petovan | cfad5809ff | |
Hypolite Petovan | 104d355096 | |
Michael | 82327b0b06 | |
Michael | 8a100e847d | |
Tobias Diekershoff | 9ae4a17977 | |
Hypolite Petovan | c604477cac | |
Michael | 21fc28029a | |
Michael | 52b11856fa | |
Hypolite Petovan | 9e1362ba46 | |
Michael | 5751e024c0 | |
Hypolite Petovan | d788cb82cc | |
Hypolite Petovan | ec5e8a55b5 | |
Hypolite Petovan | a73ba083f9 | |
Michael | e43f96740b | |
Michael | bca86beda0 | |
Michael | 567292533e | |
Tobias Diekershoff | ee9510e17d | |
Tobias Diekershoff | 99426d4188 | |
Michael Vogel | 0be622e049 | |
Michael | f574bc72ca | |
Michael Vogel | 5b55ba2176 | |
Tobias Diekershoff | db8cab77c1 | |
Hypolite Petovan | 40949483f3 | |
Hypolite Petovan | 28784eef85 | |
Hypolite Petovan | 42c3faa450 | |
Hannes Heute | 786a8dbd3b | |
Hannes Heute | afda3de363 | |
Hypolite Petovan | 25475b4838 | |
Hypolite Petovan | a6cb3ed903 | |
Hypolite Petovan | c19a68dc64 | |
Hannes Heute | a356fe65d0 | |
Hypolite Petovan | f566c52624 | |
Hypolite Petovan | 9dc0e5393e | |
Hannes Heute | e049fd5e47 | |
Hannes Heute | 579a0b43ce | |
Michael | afff2b949f | |
Tobias Diekershoff | 0ae91b59ca | |
Tobias Diekershoff | e7b9d97672 | |
Michael | e7b861388d | |
Michael | 55fb52299d | |
Tobias Diekershoff | 38e082949d | |
Tobias Diekershoff | aeb1382039 | |
Tobias Diekershoff | 63a7536624 | |
Tobias Diekershoff | bf278adb15 | |
Hypolite Petovan | 765af10f00 | |
ImgBotApp | e98b3a307b | |
Michael Vogel | e8aaa9cfec | |
Hypolite Petovan | b1b2e9bd11 | |
Hypolite Petovan | fe9ef20392 | |
Michael | 984a972e72 | |
Hypolite Petovan | 1cabf53bf5 | |
Michael | 2776411c6c | |
Hypolite Petovan | 894c56ea22 | |
Michael | c82a1ed467 | |
Hypolite Petovan | bae1f63424 | |
Michael | 652802f758 | |
Tobias Diekershoff | ac195c7061 | |
Michael | 9cf8678323 | |
Michael | 0e79b5373b | |
Hypolite Petovan | c30e4c02de | |
Michael | b351819986 | |
Michael | 642c55ee3e | |
Michael | 6e0118f3fe | |
Hypolite Petovan | 49a0b0fc3c | |
Hypolite Petovan | 4a0b989386 | |
Hypolite Petovan | 9329eebec0 | |
Matthew Exon | 619a63af6b | |
Michael | 38da9013ff | |
Matthew Exon | e24d1da13b | |
Hypolite Petovan | ed01b0f409 | |
Matthew Exon | f616dc054f | |
Matthew Exon | a20b876d67 | |
Matthew Exon | c5b8abcaf0 | |
Hypolite Petovan | 9fe0d72461 | |
Michael | 45b30825f0 | |
Michael | 7dc5622dca | |
Hypolite Petovan | ce580241e2 | |
Michael | a440619769 | |
Tobias Diekershoff | 9626a76b18 | |
Tobias Diekershoff | b02a5ed701 | |
Michael | 69fc2c04e4 | |
Michael | d7e8ee51ae | |
Tobias Diekershoff | 02d8cc2f71 | |
Tobias Diekershoff | 0a88d5a94a | |
Michael | 8b75aab4ad | |
Michael | a2da42640c | |
Tobias Diekershoff | ad65e56b16 | |
Michael | 78dc61b59e | |
Hypolite Petovan | e9dcf15d86 | |
Michael | b40687081e | |
Michael | 50b1de5959 | |
Michael Vogel | 44344af055 | |
Jonathan Lamothe | cbcec17bcb | |
Hypolite Petovan | 9ab5d8a83a | |
Michael | 0d4f956fba | |
Hypolite Petovan | c71f4eb1df | |
Michael | 626ab7cb54 | |
Hypolite Petovan | c8fff8c50c | |
Hypolite Petovan | 3bb00f36f8 | |
Hypolite Petovan | fda2873a92 | |
Éibhear Ó hAnluain | 394c388a46 | |
Éibhear Ó hAnluain | 6e7178022b | |
Éibhear Ó hAnluain | 1d86146f64 | |
Éibhear Ó hAnluain | 751ffe6bc6 | |
Hypolite Petovan | 31b74b1c8a | |
Michael | 0fde21ff28 | |
Hypolite Petovan | 53a2fb648f | |
Hannes Heute | 13b890605b | |
Hypolite Petovan | 97f7a99382 | |
Hannes Heute | e602b16dfb | |
Hannes Heute | 5c7dd34fba | |
Hannes Heute | 4b647d288a | |
Hannes Heute | 71a9e6112e | |
Hannes Heute | 0fd5c00010 | |
Hypolite Petovan | 250b3b813c | |
Michael | f537d7a64f | |
Hypolite Petovan | 5ec445e90b | |
Michael | 67e0b6357e | |
Tobias Diekershoff | f928372266 | |
Michael | 200cf29a8d | |
Michael Vogel | f78b0e7c51 | |
Hypolite Petovan | b21604a720 | |
Hypolite Petovan | c67225c62d | |
Michael Vogel | 449464a2b1 | |
Michael | c041c65c1d | |
Hypolite Petovan | e293de04f5 | |
Hypolite Petovan | b4d71f1855 | |
Tobias Diekershoff | d824bb536f | |
Tobias Diekershoff | 1b9fa0fe00 | |
Michael | b72e32a842 | |
Michael | b39c48fb02 | |
Hypolite Petovan | b5a69da872 | |
Michael | 618a3153ab | |
Hypolite Petovan | 0ccb3e7efe | |
Michael | 4b695e361c | |
Hypolite Petovan | 4834255acf | |
Michael | 325932dc5a | |
Hypolite Petovan | faac52e078 | |
Michael | 7a0c5d141e | |
Hypolite Petovan | 732d738b82 | |
Michael | 3d267c7b8f | |
Hypolite Petovan | 987e6c5ea6 | |
Hypolite Petovan | 9e240c24ce | |
Michael | 3b419cae1e | |
Hypolite Petovan | 56f3743e75 | |
Hypolite Petovan | f26f35f009 | |
Michael | fdd777d75d | |
Michael | aff45278e1 | |
Michael | 11a16589da | |
Tobias Diekershoff | f60638787e | |
Tobias Diekershoff | c5936bb51e |
|
@ -1,3 +1,10 @@
|
|||
Version 2024.06 (unreleased)
|
||||
Friendica Core
|
||||
|
||||
Friendica Addons
|
||||
|
||||
Closed Issues
|
||||
|
||||
Version 2024.03 (2024-03-21)
|
||||
Friendica Core
|
||||
Updates to the translations AR, BG, CS, DE, EO, ES, FR, GD, HU, IS, IT, JA, PL, RO, RU, SV
|
||||
|
|
|
@ -138,9 +138,9 @@ function execute_tests() {
|
|||
if [ -n "${USEDOCKER}" ]; then
|
||||
echo "Fire up the mysql docker"
|
||||
DOCKER_CONTAINER_ID=$(docker run \
|
||||
-e MYSQL_ROOT_PASSWORD=friendica \
|
||||
-e MYSQL_ROOT_PASSWORD="${DATABASE_PASSWORD}" \
|
||||
-e MYSQL_USER="${DATABASE_USER}" \
|
||||
-e MYSQL_PASSWORD=friendica \
|
||||
-e MYSQL_PASSWORD="${DATABASE_PASSWORD}" \
|
||||
-e MYSQL_DATABASE="${DATABASE_NAME}" \
|
||||
-d mysql)
|
||||
DATABASE_HOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "${DOCKER_CONTAINER_ID}")
|
||||
|
@ -152,8 +152,8 @@ function execute_tests() {
|
|||
echo "To use the docker container set the USEDOCKER environment variable"
|
||||
exit 3
|
||||
fi
|
||||
mysql -u "${DATABASE_USER}" -pfriendica -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true
|
||||
mysql -u "${DATABASE_USER}" -pfriendica -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST}
|
||||
mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true
|
||||
mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST}
|
||||
else
|
||||
DATABASE_HOST=mysql
|
||||
fi
|
||||
|
@ -171,9 +171,9 @@ function execute_tests() {
|
|||
if [ -n "${USEDOCKER}" ]; then
|
||||
echo "Fire up the mariadb docker"
|
||||
DOCKER_CONTAINER_ID=$(docker run \
|
||||
-e MYSQL_ROOT_PASSWORD=friendica \
|
||||
-e MYSQL_ROOT_PASSWORD="${DATABASE_PASSWORD}" \
|
||||
-e MYSQL_USER="${DATABASE_USER}" \
|
||||
-e MYSQL_PASSWORD=friendica \
|
||||
-e MYSQL_PASSWORD="${DATABASE_PASSWORD}" \
|
||||
-e MYSQL_DATABASE="${DATABASE_NAME}" \
|
||||
-d mariadb)
|
||||
DATABASE_HOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "${DOCKER_CONTAINER_ID}")
|
||||
|
@ -185,8 +185,8 @@ function execute_tests() {
|
|||
echo "To use the docker container set the USEDOCKER environment variable"
|
||||
exit 3
|
||||
fi
|
||||
mysql -u "${DATABASE_USER}" -pfriendica -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true
|
||||
mysql -u "${DATABASE_USER}" -pfriendica -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST}
|
||||
mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" -e "DROP DATABASE IF EXISTS ${DATABASE_NAME}" -h ${DATABASE_HOST} || true
|
||||
mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" -e "CREATE DATABASE ${DATABASE_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h ${DATABASE_HOST}
|
||||
else
|
||||
DATABASE_HOST=mariadb
|
||||
fi
|
||||
|
@ -203,14 +203,14 @@ function execute_tests() {
|
|||
|
||||
if [ -n "${USEDOCKER}" ]; then
|
||||
echo "Initialize database..."
|
||||
docker exec ${DOCKER_CONTAINER_ID} mysql -u root -pfriendica -e "CREATE DATABASE IF NOT EXISTS ${DATABASE_NAME};"
|
||||
docker exec ${DOCKER_CONTAINER_ID} mysql -u root -p"${DATABASE_PASSWORD}" -e "CREATE DATABASE IF NOT EXISTS ${DATABASE_NAME};"
|
||||
fi
|
||||
|
||||
export MYSQL_HOST="${DATABASE_HOST}"
|
||||
|
||||
#call installer
|
||||
echo "Installing Friendica..."
|
||||
"${PHP}" ./bin/console.php autoinstall --dbuser="${DATABASE_USER}" --dbpass=friendica --dbdata="${DATABASE_NAME}" --dbhost="${DATABASE_HOST}" --url=https://friendica.local --admin=admin@friendica.local
|
||||
"${PHP}" ./bin/console.php autoinstall --dbuser="${DATABASE_USER}" --dbpass="${DATABASE_PASSWORD}" --dbdata="${DATABASE_NAME}" --dbhost="${DATABASE_HOST}" --url=https://friendica.local --admin=admin@friendica.local
|
||||
fi
|
||||
|
||||
#test execution
|
||||
|
|
540
database.sql
|
@ -1,6 +1,6 @@
|
|||
-- ------------------------------------------
|
||||
-- Friendica 2024.03 (Yellow Archangel)
|
||||
-- DB_UPDATE_VERSION 1557
|
||||
-- Friendica 2024.06-dev (Yellow Archangel)
|
||||
-- DB_UPDATE_VERSION 1560
|
||||
-- ------------------------------------------
|
||||
|
||||
|
||||
|
@ -1347,7 +1347,7 @@ CREATE TABLE IF NOT EXISTS `post-engagement` (
|
|||
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
|
||||
`owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item owner',
|
||||
`contact-type` tinyint NOT NULL DEFAULT 0 COMMENT 'Person, organisation, news, community, relay',
|
||||
`media-type` tinyint NOT NULL DEFAULT 0 COMMENT 'Type of media in a bit array (1 = image, 2 = video, 4 = audio',
|
||||
`media-type` tinyint NOT NULL DEFAULT 0 COMMENT 'Type of media in a bit array (1 = image, 2 = video, 4 = audio)',
|
||||
`language` char(2) COMMENT 'Language information about this post in the ISO 639-1 format',
|
||||
`searchtext` mediumtext COMMENT 'Simplified text for the full text search',
|
||||
`size` int unsigned COMMENT 'Body size',
|
||||
|
@ -1439,6 +1439,36 @@ CREATE TABLE IF NOT EXISTS `post-media` (
|
|||
FOREIGN KEY (`media-uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Attached media';
|
||||
|
||||
--
|
||||
-- TABLE post-origin
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `post-origin` (
|
||||
`id` int unsigned NOT NULL,
|
||||
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
|
||||
`uid` mediumint unsigned NOT NULL COMMENT 'Owner id which owns this copy of the item',
|
||||
`parent-uri-id` int unsigned COMMENT 'Id of the item-uri table that contains the parent uri',
|
||||
`thr-parent-id` int unsigned COMMENT 'Id of the item-uri table that contains the thread parent uri',
|
||||
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation timestamp.',
|
||||
`received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime',
|
||||
`gravity` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
|
||||
`vid` smallint unsigned COMMENT 'Id of the verb table entry that contains the activity verbs',
|
||||
`private` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0=public, 1=private, 2=unlisted',
|
||||
`wall` boolean NOT NULL DEFAULT '0' COMMENT 'This item was posted to the wall of uid',
|
||||
PRIMARY KEY(`id`),
|
||||
UNIQUE INDEX `uid_uri-id` (`uid`,`uri-id`),
|
||||
INDEX `uri-id` (`uri-id`),
|
||||
INDEX `parent-uri-id` (`parent-uri-id`),
|
||||
INDEX `thr-parent-id` (`thr-parent-id`),
|
||||
INDEX `vid` (`vid`),
|
||||
INDEX `parent-uri-id_uid` (`parent-uri-id`,`uid`),
|
||||
INDEX `uid_wall_received` (`uid`,`wall`,`received`),
|
||||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`parent-uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`thr-parent-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`vid`) REFERENCES `verb` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Posts from local users';
|
||||
|
||||
--
|
||||
-- TABLE post-question
|
||||
--
|
||||
|
@ -1471,7 +1501,7 @@ CREATE TABLE IF NOT EXISTS `post-question-option` (
|
|||
CREATE TABLE IF NOT EXISTS `post-searchindex` (
|
||||
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
|
||||
`owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item owner',
|
||||
`media-type` tinyint NOT NULL DEFAULT 0 COMMENT 'Type of media in a bit array (1 = image, 2 = video, 4 = audio',
|
||||
`media-type` tinyint NOT NULL DEFAULT 0 COMMENT 'Type of media in a bit array (1 = image, 2 = video, 4 = audio)',
|
||||
`language` char(2) COMMENT 'Language information about this post in the ISO 639-1 format',
|
||||
`searchtext` mediumtext COMMENT 'Simplified text for the full text search',
|
||||
`size` int unsigned COMMENT 'Body size',
|
||||
|
@ -1550,6 +1580,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
|
|||
`post-reason` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Reason why the post arrived at the user',
|
||||
`vid` smallint unsigned COMMENT 'Id of the verb table entry that contains the activity verbs',
|
||||
`private` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0=public, 1=private, 2=unlisted',
|
||||
`restrictions` tinyint unsigned COMMENT 'Bit array of post restrictions (1 = Reply, 2 = Like, 4 = Announce)',
|
||||
`global` boolean NOT NULL DEFAULT '0' COMMENT '',
|
||||
`visible` boolean NOT NULL DEFAULT '0' COMMENT '',
|
||||
`deleted` boolean NOT NULL DEFAULT '0' COMMENT 'item has been marked for deletion',
|
||||
|
@ -1947,6 +1978,7 @@ CREATE TABLE IF NOT EXISTS `user-contact` (
|
|||
`ignored` boolean COMMENT 'Posts from this contact are ignored',
|
||||
`collapsed` boolean COMMENT 'Posts from this contact are collapsed',
|
||||
`hidden` boolean COMMENT 'This contact is hidden from the others',
|
||||
`channel-only` boolean COMMENT 'This contact is displayed only in channels, but not in the network stream.',
|
||||
`is-blocked` boolean COMMENT 'User is blocked by this contact',
|
||||
`channel-frequency` tinyint unsigned COMMENT 'Controls the frequency of the appearance of this contact in channels',
|
||||
`pending` boolean COMMENT '',
|
||||
|
@ -2000,7 +2032,7 @@ CREATE TABLE IF NOT EXISTS `worker-ipc` (
|
|||
-- VIEW application-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `application-view`;
|
||||
CREATE VIEW `application-view` AS SELECT
|
||||
CREATE VIEW `application-view` AS SELECT
|
||||
`application`.`id` AS `id`,
|
||||
`application-token`.`uid` AS `uid`,
|
||||
`application`.`name` AS `name`,
|
||||
|
@ -2024,7 +2056,7 @@ CREATE VIEW `application-view` AS SELECT
|
|||
-- VIEW circle-member-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `circle-member-view`;
|
||||
CREATE VIEW `circle-member-view` AS SELECT
|
||||
CREATE VIEW `circle-member-view` AS SELECT
|
||||
`group_member`.`id` AS `id`,
|
||||
`group`.`uid` AS `uid`,
|
||||
`group_member`.`contact-id` AS `contact-id`,
|
||||
|
@ -2055,7 +2087,7 @@ CREATE VIEW `circle-member-view` AS SELECT
|
|||
-- VIEW post-counts-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-counts-view`;
|
||||
CREATE VIEW `post-counts-view` AS SELECT
|
||||
CREATE VIEW `post-counts-view` AS SELECT
|
||||
`post-counts`.`uri-id` AS `uri-id`,
|
||||
`post-counts`.`vid` AS `vid`,
|
||||
`verb`.`name` AS `verb`,
|
||||
|
@ -2069,7 +2101,7 @@ CREATE VIEW `post-counts-view` AS SELECT
|
|||
-- VIEW post-timeline-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-timeline-view`;
|
||||
CREATE VIEW `post-timeline-view` AS SELECT
|
||||
CREATE VIEW `post-timeline-view` AS SELECT
|
||||
`post-user`.`uid` AS `uid`,
|
||||
`post-user`.`uri-id` AS `uri-id`,
|
||||
`post-user`.`gravity` AS `gravity`,
|
||||
|
@ -2110,11 +2142,57 @@ CREATE VIEW `post-timeline-view` AS SELECT
|
|||
STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id`
|
||||
LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-user`.`causer-id`;
|
||||
|
||||
--
|
||||
-- VIEW post-timeline-origin-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-timeline-origin-view`;
|
||||
CREATE VIEW `post-timeline-origin-view` AS SELECT
|
||||
`post-origin`.`uid` AS `uid`,
|
||||
`post-origin`.`uri-id` AS `uri-id`,
|
||||
`post-origin`.`gravity` AS `gravity`,
|
||||
`post-origin`.`created` AS `created`,
|
||||
`post-user`.`edited` AS `edited`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
`post-origin`.`received` AS `received`,
|
||||
`post-thread-user`.`changed` AS `changed`,
|
||||
`post-origin`.`private` AS `private`,
|
||||
`post-user`.`visible` AS `visible`,
|
||||
`post-user`.`deleted` AS `deleted`,
|
||||
true AS `origin`,
|
||||
`post-user`.`global` AS `global`,
|
||||
`post-user`.`network` AS `network`,
|
||||
`post-user`.`protocol` AS `protocol`,
|
||||
`post-origin`.`vid` AS `vid`,
|
||||
`post-user`.`contact-id` AS `contact-id`,
|
||||
`contact`.`blocked` AS `contact-blocked`,
|
||||
`contact`.`readonly` AS `contact-readonly`,
|
||||
`contact`.`pending` AS `contact-pending`,
|
||||
`contact`.`rel` AS `contact-rel`,
|
||||
`contact`.`uid` AS `contact-uid`,
|
||||
`contact`.`self` AS `self`,
|
||||
`post-user`.`author-id` AS `author-id`,
|
||||
`author`.`blocked` AS `author-blocked`,
|
||||
`author`.`hidden` AS `author-hidden`,
|
||||
`author`.`gsid` AS `author-gsid`,
|
||||
`post-user`.`owner-id` AS `owner-id`,
|
||||
`owner`.`blocked` AS `owner-blocked`,
|
||||
`owner`.`gsid` AS `owner-gsid`,
|
||||
`post-user`.`causer-id` AS `causer-id`,
|
||||
`causer`.`blocked` AS `causer-blocked`,
|
||||
`causer`.`gsid` AS `causer-gsid`
|
||||
FROM `post-origin`
|
||||
INNER JOIN `post-user` ON `post-user`.`id` = `post-origin`.`id`
|
||||
LEFT JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-origin`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-origin`.`uid`
|
||||
STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id`
|
||||
STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id`
|
||||
STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id`
|
||||
LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-user`.`causer-id`;
|
||||
|
||||
--
|
||||
-- VIEW post-searchindex-user-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-searchindex-user-view`;
|
||||
CREATE VIEW `post-searchindex-user-view` AS SELECT
|
||||
CREATE VIEW `post-searchindex-user-view` AS SELECT
|
||||
`post-thread-user`.`uid` AS `uid`,
|
||||
`post-searchindex`.`uri-id` AS `uri-id`,
|
||||
`post-searchindex`.`owner-id` AS `owner-id`,
|
||||
|
@ -2142,11 +2220,385 @@ CREATE VIEW `post-searchindex-user-view` AS SELECT
|
|||
AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`))
|
||||
AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
|
||||
|
||||
--
|
||||
-- VIEW post-origin-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-origin-view`;
|
||||
CREATE VIEW `post-origin-view` AS SELECT
|
||||
`post-origin`.`id` AS `id`,
|
||||
`post-origin`.`id` AS `post-user-id`,
|
||||
`post-origin`.`uid` AS `uid`,
|
||||
`post-thread-user`.`post-user-id` AS `parent`,
|
||||
`item-uri`.`uri` AS `uri`,
|
||||
`post-origin`.`uri-id` AS `uri-id`,
|
||||
`parent-item-uri`.`uri` AS `parent-uri`,
|
||||
`post-origin`.`parent-uri-id` AS `parent-uri-id`,
|
||||
`thr-parent-item-uri`.`uri` AS `thr-parent`,
|
||||
`post-origin`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread-user`.`conversation-id` AS `conversation-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
`post-origin`.`wall` AS `wall`,
|
||||
`post-origin`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post-user`.`external-id` AS `external-id`,
|
||||
`post-origin`.`created` AS `created`,
|
||||
`post-user`.`edited` AS `edited`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
`post-origin`.`received` AS `received`,
|
||||
`post-thread-user`.`changed` AS `changed`,
|
||||
`post-user`.`post-type` AS `post-type`,
|
||||
`post-user`.`post-reason` AS `post-reason`,
|
||||
`post-origin`.`private` AS `private`,
|
||||
`post-thread-user`.`pubmail` AS `pubmail`,
|
||||
`post-user`.`visible` AS `visible`,
|
||||
`post-thread-user`.`starred` AS `starred`,
|
||||
`post-user`.`unseen` AS `unseen`,
|
||||
`post-user`.`deleted` AS `deleted`,
|
||||
true AS `origin`,
|
||||
`post-thread-user`.`origin` AS `parent-origin`,
|
||||
`post-thread-user`.`mention` AS `mention`,
|
||||
`post-user`.`global` AS `global`,
|
||||
EXISTS(SELECT `type` FROM `post-collection` WHERE `type` = 0 AND `uri-id` = `post-origin`.`uri-id`) AS `featured`,
|
||||
`post-user`.`network` AS `network`,
|
||||
`post-user`.`protocol` AS `protocol`,
|
||||
`post-origin`.`vid` AS `vid`,
|
||||
`post-user`.`psid` AS `psid`,
|
||||
IF (`post-origin`.`vid` IS NULL, '', `verb`.`name`) AS `verb`,
|
||||
`post-content`.`title` AS `title`,
|
||||
`post-content`.`content-warning` AS `content-warning`,
|
||||
`post-content`.`raw-body` AS `raw-body`,
|
||||
IFNULL (`post-content`.`body`, '') AS `body`,
|
||||
`post-content`.`rendered-hash` AS `rendered-hash`,
|
||||
`post-content`.`rendered-html` AS `rendered-html`,
|
||||
`post-content`.`language` AS `language`,
|
||||
`post-content`.`plink` AS `plink`,
|
||||
`post-content`.`location` AS `location`,
|
||||
`post-content`.`coord` AS `coord`,
|
||||
`post-content`.`sensitive` AS `sensitive`,
|
||||
`post-user`.`restrictions` AS `restrictions`,
|
||||
`post-content`.`app` AS `app`,
|
||||
`post-content`.`object-type` AS `object-type`,
|
||||
`post-content`.`object` AS `object`,
|
||||
`post-content`.`target-type` AS `target-type`,
|
||||
`post-content`.`target` AS `target`,
|
||||
`post-content`.`resource-id` AS `resource-id`,
|
||||
`post-user`.`contact-id` AS `contact-id`,
|
||||
`contact`.`uri-id` AS `contact-uri-id`,
|
||||
`contact`.`url` AS `contact-link`,
|
||||
`contact`.`addr` AS `contact-addr`,
|
||||
`contact`.`name` AS `contact-name`,
|
||||
`contact`.`nick` AS `contact-nick`,
|
||||
`contact`.`thumb` AS `contact-avatar`,
|
||||
`contact`.`network` AS `contact-network`,
|
||||
`contact`.`blocked` AS `contact-blocked`,
|
||||
`contact`.`hidden` AS `contact-hidden`,
|
||||
`contact`.`readonly` AS `contact-readonly`,
|
||||
`contact`.`archive` AS `contact-archive`,
|
||||
`contact`.`pending` AS `contact-pending`,
|
||||
`contact`.`rel` AS `contact-rel`,
|
||||
`contact`.`uid` AS `contact-uid`,
|
||||
`contact`.`contact-type` AS `contact-contact-type`,
|
||||
IF (`post-user`.`network` IN ('apub', 'dfrn', 'dspr', 'stat'), true, `contact`.`writable`) AS `writable`,
|
||||
`contact`.`self` AS `self`,
|
||||
`contact`.`id` AS `cid`,
|
||||
`contact`.`alias` AS `alias`,
|
||||
`contact`.`photo` AS `photo`,
|
||||
`contact`.`name-date` AS `name-date`,
|
||||
`contact`.`uri-date` AS `uri-date`,
|
||||
`contact`.`avatar-date` AS `avatar-date`,
|
||||
`contact`.`thumb` AS `thumb`,
|
||||
`post-user`.`author-id` AS `author-id`,
|
||||
`author`.`uri-id` AS `author-uri-id`,
|
||||
`author`.`url` AS `author-link`,
|
||||
`author`.`addr` AS `author-addr`,
|
||||
IF (`contact`.`url` = `author`.`url` AND `contact`.`name` != '', `contact`.`name`, `author`.`name`) AS `author-name`,
|
||||
`author`.`nick` AS `author-nick`,
|
||||
`author`.`alias` AS `author-alias`,
|
||||
IF (`contact`.`url` = `author`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `author`.`thumb`) AS `author-avatar`,
|
||||
`author`.`network` AS `author-network`,
|
||||
`author`.`blocked` AS `author-blocked`,
|
||||
`author`.`hidden` AS `author-hidden`,
|
||||
`author`.`updated` AS `author-updated`,
|
||||
`author`.`contact-type` AS `author-contact-type`,
|
||||
`author`.`gsid` AS `author-gsid`,
|
||||
`author`.`baseurl` AS `author-baseurl`,
|
||||
`post-user`.`owner-id` AS `owner-id`,
|
||||
`owner`.`uri-id` AS `owner-uri-id`,
|
||||
`owner`.`url` AS `owner-link`,
|
||||
`owner`.`addr` AS `owner-addr`,
|
||||
IF (`contact`.`url` = `owner`.`url` AND `contact`.`name` != '', `contact`.`name`, `owner`.`name`) AS `owner-name`,
|
||||
`owner`.`nick` AS `owner-nick`,
|
||||
`owner`.`alias` AS `owner-alias`,
|
||||
IF (`contact`.`url` = `owner`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `owner`.`thumb`) AS `owner-avatar`,
|
||||
`owner`.`network` AS `owner-network`,
|
||||
`owner`.`blocked` AS `owner-blocked`,
|
||||
`owner`.`hidden` AS `owner-hidden`,
|
||||
`owner`.`updated` AS `owner-updated`,
|
||||
`owner`.`gsid` AS `owner-gsid`,
|
||||
`owner`.`contact-type` AS `owner-contact-type`,
|
||||
`post-user`.`causer-id` AS `causer-id`,
|
||||
`causer`.`uri-id` AS `causer-uri-id`,
|
||||
`causer`.`url` AS `causer-link`,
|
||||
`causer`.`addr` AS `causer-addr`,
|
||||
`causer`.`name` AS `causer-name`,
|
||||
`causer`.`nick` AS `causer-nick`,
|
||||
`causer`.`alias` AS `causer-alias`,
|
||||
`causer`.`thumb` AS `causer-avatar`,
|
||||
`causer`.`network` AS `causer-network`,
|
||||
`causer`.`blocked` AS `causer-blocked`,
|
||||
`causer`.`hidden` AS `causer-hidden`,
|
||||
`causer`.`gsid` AS `causer-gsid`,
|
||||
`causer`.`contact-type` AS `causer-contact-type`,
|
||||
`post-delivery-data`.`postopts` AS `postopts`,
|
||||
`post-delivery-data`.`inform` AS `inform`,
|
||||
`post-delivery-data`.`queue_count` AS `delivery_queue_count`,
|
||||
`post-delivery-data`.`queue_done` AS `delivery_queue_done`,
|
||||
`post-delivery-data`.`queue_failed` AS `delivery_queue_failed`,
|
||||
IF (`post-user`.`psid` IS NULL, '', `permissionset`.`allow_cid`) AS `allow_cid`,
|
||||
IF (`post-user`.`psid` IS NULL, '', `permissionset`.`allow_gid`) AS `allow_gid`,
|
||||
IF (`post-user`.`psid` IS NULL, '', `permissionset`.`deny_cid`) AS `deny_cid`,
|
||||
IF (`post-user`.`psid` IS NULL, '', `permissionset`.`deny_gid`) AS `deny_gid`,
|
||||
`post-user`.`event-id` AS `event-id`,
|
||||
`event`.`created` AS `event-created`,
|
||||
`event`.`edited` AS `event-edited`,
|
||||
`event`.`start` AS `event-start`,
|
||||
`event`.`finish` AS `event-finish`,
|
||||
`event`.`summary` AS `event-summary`,
|
||||
`event`.`desc` AS `event-desc`,
|
||||
`event`.`location` AS `event-location`,
|
||||
`event`.`type` AS `event-type`,
|
||||
`event`.`nofinish` AS `event-nofinish`,
|
||||
`event`.`ignore` AS `event-ignore`,
|
||||
`post-question`.`id` AS `question-id`,
|
||||
`post-question`.`multiple` AS `question-multiple`,
|
||||
`post-question`.`voters` AS `question-voters`,
|
||||
`post-question`.`end-time` AS `question-end-time`,
|
||||
EXISTS(SELECT `uri-id` FROM `post-category` WHERE `post-category`.`uri-id` = `post-origin`.`uri-id` AND `post-category`.`uid` = `post-origin`.`uid`) AS `has-categories`,
|
||||
EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-origin`.`uri-id`) AS `has-media`,
|
||||
`diaspora-interaction`.`interaction` AS `signed_text`,
|
||||
`parent-item-uri`.`guid` AS `parent-guid`,
|
||||
`post-thread-user`.`network` AS `parent-network`,
|
||||
`post-thread-user`.`author-id` AS `parent-author-id`,
|
||||
`parent-post-author`.`url` AS `parent-author-link`,
|
||||
`parent-post-author`.`name` AS `parent-author-name`,
|
||||
`parent-post-author`.`nick` AS `parent-author-nick`,
|
||||
`parent-post-author`.`network` AS `parent-author-network`
|
||||
FROM `post-origin`
|
||||
INNER JOIN `post-user` ON `post-user`.`id` = `post-origin`.`id`
|
||||
INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-origin`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-origin`.`uid`
|
||||
STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id`
|
||||
STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id`
|
||||
STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id`
|
||||
LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-user`.`causer-id`
|
||||
LEFT JOIN `item-uri` ON `item-uri`.`id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-origin`.`thr-parent-id`
|
||||
LEFT JOIN `item-uri` AS `parent-item-uri` ON `parent-item-uri`.`id` = `post-origin`.`parent-uri-id`
|
||||
LEFT JOIN `item-uri` AS `conversation-item-uri` ON `conversation-item-uri`.`id` = `post-thread-user`.`conversation-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post-user`.`external-id`
|
||||
LEFT JOIN `verb` ON `verb`.`id` = `post-origin`.`vid`
|
||||
LEFT JOIN `event` ON `event`.`id` = `post-user`.`event-id`
|
||||
LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id`
|
||||
LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-user`.`psid`
|
||||
LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `post-thread-user`.`author-id`;
|
||||
|
||||
--
|
||||
-- VIEW post-thread-origin-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-thread-origin-view`;
|
||||
CREATE VIEW `post-thread-origin-view` AS SELECT
|
||||
`post-origin`.`id` AS `id`,
|
||||
`post-origin`.`id` AS `post-user-id`,
|
||||
`post-origin`.`uid` AS `uid`,
|
||||
`post-thread-user`.`post-user-id` AS `parent`,
|
||||
`item-uri`.`uri` AS `uri`,
|
||||
`post-origin`.`uri-id` AS `uri-id`,
|
||||
`parent-item-uri`.`uri` AS `parent-uri`,
|
||||
`post-origin`.`parent-uri-id` AS `parent-uri-id`,
|
||||
`thr-parent-item-uri`.`uri` AS `thr-parent`,
|
||||
`post-origin`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread-user`.`conversation-id` AS `conversation-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
`post-origin`.`wall` AS `wall`,
|
||||
`post-origin`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post-user`.`external-id` AS `external-id`,
|
||||
`post-origin`.`created` AS `created`,
|
||||
`post-user`.`edited` AS `edited`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
`post-origin`.`received` AS `received`,
|
||||
`post-thread-user`.`changed` AS `changed`,
|
||||
`post-user`.`post-type` AS `post-type`,
|
||||
`post-user`.`post-reason` AS `post-reason`,
|
||||
`post-origin`.`private` AS `private`,
|
||||
`post-thread-user`.`pubmail` AS `pubmail`,
|
||||
`post-thread-user`.`ignored` AS `ignored`,
|
||||
`post-user`.`visible` AS `visible`,
|
||||
`post-thread-user`.`starred` AS `starred`,
|
||||
`post-thread-user`.`unseen` AS `unseen`,
|
||||
`post-user`.`deleted` AS `deleted`,
|
||||
true AS `origin`,
|
||||
`post-thread-user`.`mention` AS `mention`,
|
||||
`post-user`.`global` AS `global`,
|
||||
EXISTS(SELECT `type` FROM `post-collection` WHERE `type` = 0 AND `uri-id` = `post-thread-user`.`uri-id`) AS `featured`,
|
||||
`post-thread-user`.`network` AS `network`,
|
||||
`post-origin`.`vid` AS `vid`,
|
||||
`post-thread-user`.`psid` AS `psid`,
|
||||
IF (`post-origin`.`vid` IS NULL, '', `verb`.`name`) AS `verb`,
|
||||
`post-content`.`title` AS `title`,
|
||||
`post-content`.`content-warning` AS `content-warning`,
|
||||
`post-content`.`raw-body` AS `raw-body`,
|
||||
`post-content`.`body` AS `body`,
|
||||
`post-content`.`rendered-hash` AS `rendered-hash`,
|
||||
`post-content`.`rendered-html` AS `rendered-html`,
|
||||
`post-content`.`language` AS `language`,
|
||||
`post-content`.`plink` AS `plink`,
|
||||
`post-content`.`location` AS `location`,
|
||||
`post-content`.`coord` AS `coord`,
|
||||
`post-content`.`sensitive` AS `sensitive`,
|
||||
`post-user`.`restrictions` AS `restrictions`,
|
||||
`post-content`.`app` AS `app`,
|
||||
`post-content`.`object-type` AS `object-type`,
|
||||
`post-content`.`object` AS `object`,
|
||||
`post-content`.`target-type` AS `target-type`,
|
||||
`post-content`.`target` AS `target`,
|
||||
`post-content`.`resource-id` AS `resource-id`,
|
||||
`post-thread-user`.`contact-id` AS `contact-id`,
|
||||
`contact`.`uri-id` AS `contact-uri-id`,
|
||||
`contact`.`url` AS `contact-link`,
|
||||
`contact`.`addr` AS `contact-addr`,
|
||||
`contact`.`name` AS `contact-name`,
|
||||
`contact`.`nick` AS `contact-nick`,
|
||||
`contact`.`thumb` AS `contact-avatar`,
|
||||
`contact`.`network` AS `contact-network`,
|
||||
`contact`.`blocked` AS `contact-blocked`,
|
||||
`contact`.`hidden` AS `contact-hidden`,
|
||||
`contact`.`readonly` AS `contact-readonly`,
|
||||
`contact`.`archive` AS `contact-archive`,
|
||||
`contact`.`pending` AS `contact-pending`,
|
||||
`contact`.`rel` AS `contact-rel`,
|
||||
`contact`.`uid` AS `contact-uid`,
|
||||
`contact`.`gsid` AS `contact-gsid`,
|
||||
`contact`.`contact-type` AS `contact-contact-type`,
|
||||
IF (`post-user`.`network` IN ('apub', 'dfrn', 'dspr', 'stat'), true, `contact`.`writable`) AS `writable`,
|
||||
`contact`.`self` AS `self`,
|
||||
`contact`.`id` AS `cid`,
|
||||
`contact`.`alias` AS `alias`,
|
||||
`contact`.`photo` AS `photo`,
|
||||
`contact`.`name-date` AS `name-date`,
|
||||
`contact`.`uri-date` AS `uri-date`,
|
||||
`contact`.`avatar-date` AS `avatar-date`,
|
||||
`contact`.`thumb` AS `thumb`,
|
||||
`post-thread-user`.`author-id` AS `author-id`,
|
||||
`author`.`uri-id` AS `author-uri-id`,
|
||||
`author`.`url` AS `author-link`,
|
||||
`author`.`addr` AS `author-addr`,
|
||||
IF (`contact`.`url` = `author`.`url` AND `contact`.`name` != '', `contact`.`name`, `author`.`name`) AS `author-name`,
|
||||
`author`.`nick` AS `author-nick`,
|
||||
`author`.`alias` AS `author-alias`,
|
||||
IF (`contact`.`url` = `author`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `author`.`thumb`) AS `author-avatar`,
|
||||
`author`.`network` AS `author-network`,
|
||||
`author`.`blocked` AS `author-blocked`,
|
||||
`author`.`hidden` AS `author-hidden`,
|
||||
`author`.`updated` AS `author-updated`,
|
||||
`author`.`contact-type` AS `author-contact-type`,
|
||||
`author`.`gsid` AS `author-gsid`,
|
||||
`post-thread-user`.`owner-id` AS `owner-id`,
|
||||
`owner`.`uri-id` AS `owner-uri-id`,
|
||||
`owner`.`url` AS `owner-link`,
|
||||
`owner`.`addr` AS `owner-addr`,
|
||||
IF (`contact`.`url` = `owner`.`url` AND `contact`.`name` != '', `contact`.`name`, `owner`.`name`) AS `owner-name`,
|
||||
`owner`.`nick` AS `owner-nick`,
|
||||
`owner`.`alias` AS `owner-alias`,
|
||||
IF (`contact`.`url` = `owner`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `owner`.`thumb`) AS `owner-avatar`,
|
||||
`owner`.`network` AS `owner-network`,
|
||||
`owner`.`blocked` AS `owner-blocked`,
|
||||
`owner`.`hidden` AS `owner-hidden`,
|
||||
`owner`.`updated` AS `owner-updated`,
|
||||
`owner`.`gsid` AS `owner-gsid`,
|
||||
`owner`.`contact-type` AS `owner-contact-type`,
|
||||
`post-thread-user`.`causer-id` AS `causer-id`,
|
||||
`causer`.`uri-id` AS `causer-uri-id`,
|
||||
`causer`.`url` AS `causer-link`,
|
||||
`causer`.`addr` AS `causer-addr`,
|
||||
`causer`.`name` AS `causer-name`,
|
||||
`causer`.`nick` AS `causer-nick`,
|
||||
`causer`.`alias` AS `causer-alias`,
|
||||
`causer`.`thumb` AS `causer-avatar`,
|
||||
`causer`.`network` AS `causer-network`,
|
||||
`causer`.`blocked` AS `causer-blocked`,
|
||||
`causer`.`hidden` AS `causer-hidden`,
|
||||
`causer`.`gsid` AS `causer-gsid`,
|
||||
`causer`.`contact-type` AS `causer-contact-type`,
|
||||
`post-delivery-data`.`postopts` AS `postopts`,
|
||||
`post-delivery-data`.`inform` AS `inform`,
|
||||
`post-delivery-data`.`queue_count` AS `delivery_queue_count`,
|
||||
`post-delivery-data`.`queue_done` AS `delivery_queue_done`,
|
||||
`post-delivery-data`.`queue_failed` AS `delivery_queue_failed`,
|
||||
IF (`post-thread-user`.`psid` IS NULL, '', `permissionset`.`allow_cid`) AS `allow_cid`,
|
||||
IF (`post-thread-user`.`psid` IS NULL, '', `permissionset`.`allow_gid`) AS `allow_gid`,
|
||||
IF (`post-thread-user`.`psid` IS NULL, '', `permissionset`.`deny_cid`) AS `deny_cid`,
|
||||
IF (`post-thread-user`.`psid` IS NULL, '', `permissionset`.`deny_gid`) AS `deny_gid`,
|
||||
`post-user`.`event-id` AS `event-id`,
|
||||
`event`.`created` AS `event-created`,
|
||||
`event`.`edited` AS `event-edited`,
|
||||
`event`.`start` AS `event-start`,
|
||||
`event`.`finish` AS `event-finish`,
|
||||
`event`.`summary` AS `event-summary`,
|
||||
`event`.`desc` AS `event-desc`,
|
||||
`event`.`location` AS `event-location`,
|
||||
`event`.`type` AS `event-type`,
|
||||
`event`.`nofinish` AS `event-nofinish`,
|
||||
`event`.`ignore` AS `event-ignore`,
|
||||
`post-question`.`id` AS `question-id`,
|
||||
`post-question`.`multiple` AS `question-multiple`,
|
||||
`post-question`.`voters` AS `question-voters`,
|
||||
`post-question`.`end-time` AS `question-end-time`,
|
||||
EXISTS(SELECT `uri-id` FROM `post-category` WHERE `post-category`.`uri-id` = `post-thread-user`.`uri-id` AND `post-category`.`uid` = `post-thread-user`.`uid`) AS `has-categories`,
|
||||
EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread-user`.`uri-id`) AS `has-media`,
|
||||
`diaspora-interaction`.`interaction` AS `signed_text`,
|
||||
`parent-item-uri`.`guid` AS `parent-guid`,
|
||||
`post-thread-user`.`network` AS `parent-network`,
|
||||
`post-thread-user`.`author-id` AS `parent-author-id`,
|
||||
`author`.`url` AS `parent-author-link`,
|
||||
`author`.`name` AS `parent-author-name`,
|
||||
`author`.`nick` AS `parent-author-nick`,
|
||||
`author`.`network` AS `parent-author-network`
|
||||
FROM `post-origin`
|
||||
INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-origin`.`uri-id` AND `post-thread-user`.`uid` = `post-origin`.`uid`
|
||||
INNER JOIN `post-user` ON `post-user`.`id` = `post-origin`.`id`
|
||||
STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id`
|
||||
STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-thread-user`.`author-id`
|
||||
STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-thread-user`.`owner-id`
|
||||
LEFT JOIN `contact` AS `causer` ON `causer`.`id` = `post-thread-user`.`causer-id`
|
||||
LEFT JOIN `item-uri` ON `item-uri`.`id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-origin`.`thr-parent-id`
|
||||
LEFT JOIN `item-uri` AS `parent-item-uri` ON `parent-item-uri`.`id` = `post-origin`.`parent-uri-id`
|
||||
LEFT JOIN `item-uri` AS `conversation-item-uri` ON `conversation-item-uri`.`id` = `post-thread-user`.`conversation-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post-user`.`external-id`
|
||||
LEFT JOIN `verb` ON `verb`.`id` = `post-origin`.`vid`
|
||||
LEFT JOIN `event` ON `event`.`id` = `post-user`.`event-id`
|
||||
LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id`
|
||||
LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-origin`.`uri-id`
|
||||
LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-thread-user`.`psid`;
|
||||
|
||||
--
|
||||
-- VIEW post-user-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-user-view`;
|
||||
CREATE VIEW `post-user-view` AS SELECT
|
||||
CREATE VIEW `post-user-view` AS SELECT
|
||||
`post-user`.`id` AS `id`,
|
||||
`post-user`.`id` AS `post-user-id`,
|
||||
`post-user`.`uid` AS `uid`,
|
||||
|
@ -2200,6 +2652,7 @@ CREATE VIEW `post-user-view` AS SELECT
|
|||
`post-content`.`location` AS `location`,
|
||||
`post-content`.`coord` AS `coord`,
|
||||
`post-content`.`sensitive` AS `sensitive`,
|
||||
`post-user`.`restrictions` AS `restrictions`,
|
||||
`post-content`.`app` AS `app`,
|
||||
`post-content`.`object-type` AS `object-type`,
|
||||
`post-content`.`object` AS `object`,
|
||||
|
@ -2332,7 +2785,7 @@ CREATE VIEW `post-user-view` AS SELECT
|
|||
-- VIEW post-thread-user-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-thread-user-view`;
|
||||
CREATE VIEW `post-thread-user-view` AS SELECT
|
||||
CREATE VIEW `post-thread-user-view` AS SELECT
|
||||
`post-user`.`id` AS `id`,
|
||||
`post-user`.`id` AS `post-user-id`,
|
||||
`post-thread-user`.`uid` AS `uid`,
|
||||
|
@ -2385,6 +2838,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT
|
|||
`post-content`.`location` AS `location`,
|
||||
`post-content`.`coord` AS `coord`,
|
||||
`post-content`.`sensitive` AS `sensitive`,
|
||||
`post-user`.`restrictions` AS `restrictions`,
|
||||
`post-content`.`app` AS `app`,
|
||||
`post-content`.`object-type` AS `object-type`,
|
||||
`post-content`.`object` AS `object`,
|
||||
|
@ -2516,7 +2970,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT
|
|||
-- VIEW post-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-view`;
|
||||
CREATE VIEW `post-view` AS SELECT
|
||||
CREATE VIEW `post-view` AS SELECT
|
||||
`item-uri`.`uri` AS `uri`,
|
||||
`post`.`uri-id` AS `uri-id`,
|
||||
`parent-item-uri`.`uri` AS `parent-uri`,
|
||||
|
@ -2663,7 +3117,7 @@ CREATE VIEW `post-view` AS SELECT
|
|||
-- VIEW post-thread-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `post-thread-view`;
|
||||
CREATE VIEW `post-thread-view` AS SELECT
|
||||
CREATE VIEW `post-thread-view` AS SELECT
|
||||
`item-uri`.`uri` AS `uri`,
|
||||
`post-thread`.`uri-id` AS `uri-id`,
|
||||
`parent-item-uri`.`uri` AS `parent-uri`,
|
||||
|
@ -2811,7 +3265,7 @@ CREATE VIEW `post-thread-view` AS SELECT
|
|||
-- VIEW category-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `category-view`;
|
||||
CREATE VIEW `category-view` AS SELECT
|
||||
CREATE VIEW `category-view` AS SELECT
|
||||
`post-category`.`uri-id` AS `uri-id`,
|
||||
`post-category`.`uid` AS `uid`,
|
||||
`post-category`.`type` AS `type`,
|
||||
|
@ -2825,7 +3279,7 @@ CREATE VIEW `category-view` AS SELECT
|
|||
-- VIEW collection-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `collection-view`;
|
||||
CREATE VIEW `collection-view` AS SELECT
|
||||
CREATE VIEW `collection-view` AS SELECT
|
||||
`post-collection`.`uri-id` AS `uri-id`,
|
||||
`post-collection`.`type` AS `type`,
|
||||
`post-collection`.`author-id` AS `cid`,
|
||||
|
@ -2846,7 +3300,7 @@ CREATE VIEW `collection-view` AS SELECT
|
|||
-- VIEW media-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `media-view`;
|
||||
CREATE VIEW `media-view` AS SELECT
|
||||
CREATE VIEW `media-view` AS SELECT
|
||||
`post-media`.`uri-id` AS `uri-id`,
|
||||
`post-media`.`type` AS `type`,
|
||||
`post`.`received` AS `received`,
|
||||
|
@ -2864,7 +3318,7 @@ CREATE VIEW `media-view` AS SELECT
|
|||
-- VIEW tag-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `tag-view`;
|
||||
CREATE VIEW `tag-view` AS SELECT
|
||||
CREATE VIEW `tag-view` AS SELECT
|
||||
`post-tag`.`uri-id` AS `uri-id`,
|
||||
`post-tag`.`type` AS `type`,
|
||||
`post-tag`.`tid` AS `tid`,
|
||||
|
@ -2876,41 +3330,11 @@ CREATE VIEW `tag-view` AS SELECT
|
|||
LEFT JOIN `tag` ON `post-tag`.`tid` = `tag`.`id`
|
||||
LEFT JOIN `contact` ON `post-tag`.`cid` = `contact`.`id`;
|
||||
|
||||
--
|
||||
-- VIEW network-item-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `network-item-view`;
|
||||
CREATE VIEW `network-item-view` AS SELECT
|
||||
`post-user`.`uri-id` AS `uri-id`,
|
||||
`post-thread-user`.`post-user-id` AS `parent`,
|
||||
`post-user`.`received` AS `received`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
`post-user`.`created` AS `created`,
|
||||
`post-user`.`uid` AS `uid`,
|
||||
`post-thread-user`.`starred` AS `starred`,
|
||||
`post-thread-user`.`mention` AS `mention`,
|
||||
`post-user`.`network` AS `network`,
|
||||
`post-user`.`unseen` AS `unseen`,
|
||||
`post-user`.`gravity` AS `gravity`,
|
||||
`post-user`.`contact-id` AS `contact-id`,
|
||||
`ownercontact`.`contact-type` AS `contact-type`
|
||||
FROM `post-user`
|
||||
INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid`
|
||||
STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id`
|
||||
STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id`
|
||||
STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id`
|
||||
WHERE `post-user`.`visible` AND NOT `post-user`.`deleted`
|
||||
AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
|
||||
AND (`post-user`.`hidden` IS NULL OR NOT `post-user`.`hidden`)
|
||||
AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
|
||||
AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`))
|
||||
AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
|
||||
|
||||
--
|
||||
-- VIEW network-thread-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `network-thread-view`;
|
||||
CREATE VIEW `network-thread-view` AS SELECT
|
||||
CREATE VIEW `network-thread-view` AS SELECT
|
||||
`post-thread-user`.`uri-id` AS `uri-id`,
|
||||
`post-thread-user`.`post-user-id` AS `parent`,
|
||||
`post-thread-user`.`received` AS `received`,
|
||||
|
@ -2931,14 +3355,14 @@ CREATE VIEW `network-thread-view` AS SELECT
|
|||
AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`)
|
||||
AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`)
|
||||
AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked`
|
||||
AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`))
|
||||
AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
|
||||
AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`post-thread-user`.`author-id`, `post-thread-user`.`owner-id`, `post-thread-user`.`causer-id`) AND (`blocked` OR `ignored` OR `channel-only`))
|
||||
AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`);
|
||||
|
||||
--
|
||||
-- VIEW owner-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `owner-view`;
|
||||
CREATE VIEW `owner-view` AS SELECT
|
||||
CREATE VIEW `owner-view` AS SELECT
|
||||
`contact`.`id` AS `id`,
|
||||
`contact`.`uid` AS `uid`,
|
||||
`contact`.`created` AS `created`,
|
||||
|
@ -3066,7 +3490,7 @@ CREATE VIEW `owner-view` AS SELECT
|
|||
-- VIEW account-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `account-view`;
|
||||
CREATE VIEW `account-view` AS SELECT
|
||||
CREATE VIEW `account-view` AS SELECT
|
||||
`contact`.`id` AS `id`,
|
||||
`contact`.`url` AS `url`,
|
||||
`contact`.`nurl` AS `nurl`,
|
||||
|
@ -3154,7 +3578,7 @@ CREATE VIEW `account-view` AS SELECT
|
|||
-- VIEW account-user-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `account-user-view`;
|
||||
CREATE VIEW `account-user-view` AS SELECT
|
||||
CREATE VIEW `account-user-view` AS SELECT
|
||||
`ucontact`.`id` AS `id`,
|
||||
`contact`.`id` AS `pid`,
|
||||
`ucontact`.`uid` AS `uid`,
|
||||
|
@ -3260,7 +3684,7 @@ CREATE VIEW `account-user-view` AS SELECT
|
|||
-- VIEW pending-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `pending-view`;
|
||||
CREATE VIEW `pending-view` AS SELECT
|
||||
CREATE VIEW `pending-view` AS SELECT
|
||||
`register`.`id` AS `id`,
|
||||
`register`.`hash` AS `hash`,
|
||||
`register`.`created` AS `created`,
|
||||
|
@ -3282,7 +3706,7 @@ CREATE VIEW `pending-view` AS SELECT
|
|||
-- VIEW tag-search-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `tag-search-view`;
|
||||
CREATE VIEW `tag-search-view` AS SELECT
|
||||
CREATE VIEW `tag-search-view` AS SELECT
|
||||
`post-tag`.`uri-id` AS `uri-id`,
|
||||
`post-user`.`uid` AS `uid`,
|
||||
`post-user`.`id` AS `iid`,
|
||||
|
@ -3304,7 +3728,7 @@ CREATE VIEW `tag-search-view` AS SELECT
|
|||
-- VIEW workerqueue-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `workerqueue-view`;
|
||||
CREATE VIEW `workerqueue-view` AS SELECT
|
||||
CREATE VIEW `workerqueue-view` AS SELECT
|
||||
`process`.`pid` AS `pid`,
|
||||
`workerqueue`.`priority` AS `priority`
|
||||
FROM `process`
|
||||
|
@ -3315,7 +3739,7 @@ CREATE VIEW `workerqueue-view` AS SELECT
|
|||
-- VIEW profile_field-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `profile_field-view`;
|
||||
CREATE VIEW `profile_field-view` AS SELECT
|
||||
CREATE VIEW `profile_field-view` AS SELECT
|
||||
`profile_field`.`id` AS `id`,
|
||||
`profile_field`.`uid` AS `uid`,
|
||||
`profile_field`.`label` AS `label`,
|
||||
|
@ -3335,7 +3759,7 @@ CREATE VIEW `profile_field-view` AS SELECT
|
|||
-- VIEW diaspora-contact-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `diaspora-contact-view`;
|
||||
CREATE VIEW `diaspora-contact-view` AS SELECT
|
||||
CREATE VIEW `diaspora-contact-view` AS SELECT
|
||||
`diaspora-contact`.`uri-id` AS `uri-id`,
|
||||
`item-uri`.`uri` AS `url`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
|
|
|
@ -850,10 +850,6 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
|
|||
Hook::callAll('register_account', $uid);
|
||||
Hook::callAll('remove_user', $user);
|
||||
|
||||
### src/Module/Notifications/Ping.php
|
||||
|
||||
Hook::callAll('network_ping', $arr);
|
||||
|
||||
### src/Module/PermissionTooltip.php
|
||||
|
||||
Hook::callAll('lockview_content', $item);
|
||||
|
|
|
@ -23,7 +23,7 @@ Predefined Channels
|
|||
|
||||
* For you: Posts from contacts you interact with and who interact with you. In detail, it consists of:
|
||||
* Posts from people you interact with on a more than average level.
|
||||
* Posts from the accounts that you follow with a more than average number of interactions-
|
||||
* Posts from the accounts that you follow with a more than average number of interactions.
|
||||
* Posts from accounts where you activated "notify on new posts" or where you have set the channel frequency accordingly.
|
||||
* Discover: Posts from contacts you don't follow, but that might be of interest for you to follow. In detail, it consists of:
|
||||
* Posts from people you don't follow but you interact with on a more than average level.
|
||||
|
@ -48,11 +48,11 @@ Each channel is defined by these values:
|
|||
* Label: This value is mandatory and is used for the menu label.
|
||||
* Description: A short description of the content. This can help to keep the overview, when you have got a lot of channels.
|
||||
* Access Key: When you want to access this channel via an access key, you can define it here. Pay attention to not use an already used one.
|
||||
* Circle: This defines the data source for this channel. By default it is set to the public timeline. There are some predefined values, like the accounts that you follow or the accounts that follow you. Also all of your circles can be selected.
|
||||
* Circle: This defines the data source for this channel. By default it is set to the public timeline. There are some predefined values, like the accounts that you follow or the accounts that follow you. Also all of your circles can be selected.
|
||||
* Include Tags: Comma separated list of tags. A post will be used when it contains any of the listed tags.
|
||||
* Exclude Tags: Comma separated list of tags. If a post contain any of these tags, then it will not be part of nthis channel.
|
||||
* Exclude Tags: Comma separated list of tags. If a post contain any of these tags, then it will not be part of this channel.
|
||||
* Full Text Search: This can be used to include or exclude content, based on the content and some additional keywords. It uses the "boolean mode" operators from MariaDB: https://mariadb.com/kb/en/full-text-index-overview/#in-boolean-mode
|
||||
* Images, Videos, Audio: When selected, you will see content with the selected media type. This can be combined. If none of these fields are checked, you will see any content, with or without attacked media.
|
||||
* Images, Videos, Audio: When selected, you will see content with the selected media type. This can be combined. If none of these fields are checked, you will see any content, with or without attached media.
|
||||
|
||||
Additional keywords for the full text search
|
||||
---
|
||||
|
@ -61,8 +61,8 @@ Additionally to the search for content, there are keywords that can be used in t
|
|||
Alternatives are presented with "|".
|
||||
|
||||
* from - Use "from:nickname" or "from:nickname@domain.tld" to search for posts from a specific author.
|
||||
* to - Use "from:nickname" or "from:nickname@domain.tld" to search for posts with the given contact as receiver.
|
||||
* group - Use "group:nickname" or "group:nickname@domain.tld" to search for group post of the given group.
|
||||
* to - Use "to:nickname" or "to:nickname@domain.tld" to search for posts with the given contact as receiver.
|
||||
* group - Use "group:nickname" or "group:nickname@domain.tld" to search for posts of the given group.
|
||||
* application | relay - Use "application:nickname" or "application:nickname@domain.tld" to search for posts that had been reshared by the given relay application.
|
||||
* server - Use "server:hostname" to search for posts from a specific server. In the case of group postings, the search text contains both the hostname of the group server and the author's hostname.
|
||||
* source - The ActivityPub type of the post source. Use this for example to include or exclude group posts or posts from services (aka bots).
|
||||
|
@ -93,7 +93,7 @@ Alternatives are presented with "|".
|
|||
* visibility:public
|
||||
* visibility:unlisted
|
||||
* visibility:private
|
||||
* language | lang - Use "language:code" to search for posts with the given language in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
|
||||
* language | lang - Use "language:code" to search for posts with the given language in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
|
||||
|
||||
Remember that you can combine these kerywords.
|
||||
So for example you can create a channel with all posts that talk about the Fediverse - that aren't posted in the Fediverse with the search terms: "fediverse -network:apub -network:dfrn"
|
||||
Remember that you can combine these keywords.
|
||||
So for example you can create a channel with all posts that talk about the Fediverse - that aren't posted in the Fediverse with the search terms: "fediverse -network:apub -network:dfrn"
|
||||
|
|
|
@ -30,7 +30,7 @@ Due to the large variety of operating systems and PHP platforms in existence we
|
|||
* Apache with mod-rewrite enabled and "Options All" so you can use a local `.htaccess` file
|
||||
* PHP 7.4+
|
||||
* PHP *command line* access with register_argc_argv set to true in the php.ini file
|
||||
* Curl, GD, GMP, PDO, mbstrings, MySQLi, hash, xml, zip, IntlChar and OpenSSL extensions
|
||||
* Curl, GD, GMP, PDO, mbstrings, MySQLi, hash, xml, zip, IntlChar, IDN and OpenSSL extensions
|
||||
* The POSIX module of PHP needs to be activated (e.g. [RHEL, CentOS](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) have disabled it)
|
||||
* Some form of email server or email gateway such that PHP mail() works.
|
||||
If you cannot set up your own email server, you can use the [phpmailer](https://github.com/friendica/friendica-addons/tree/develop/phpmailer) addon and use a remote SMTP server.
|
||||
|
|
|
@ -68,6 +68,7 @@ Database Tables
|
|||
| [post-history](help/database/db_post-history) | Post history |
|
||||
| [post-link](help/database/db_post-link) | Post related external links |
|
||||
| [post-media](help/database/db_post-media) | Attached media |
|
||||
| [post-origin](help/database/db_post-origin) | Posts from local users |
|
||||
| [post-question](help/database/db_post-question) | Question |
|
||||
| [post-question-option](help/database/db_post-question-option) | Question option |
|
||||
| [post-searchindex](help/database/db_post-searchindex) | Content for all posts |
|
||||
|
|
|
@ -11,7 +11,7 @@ Fields
|
|||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | PRI | NULL | |
|
||||
| owner-id | Item owner | int unsigned | NO | | 0 | |
|
||||
| contact-type | Person, organisation, news, community, relay | tinyint | NO | | 0 | |
|
||||
| media-type | Type of media in a bit array (1 = image, 2 = video, 4 = audio | tinyint | NO | | 0 | |
|
||||
| media-type | Type of media in a bit array (1 = image, 2 = video, 4 = audio) | tinyint | NO | | 0 | |
|
||||
| language | Language information about this post in the ISO 639-1 format | char(2) | YES | | NULL | |
|
||||
| searchtext | Simplified text for the full text search | mediumtext | YES | | NULL | |
|
||||
| size | Body size | int unsigned | YES | | NULL | |
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
Table post-origin
|
||||
===========
|
||||
|
||||
Posts from local users
|
||||
|
||||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------------- | ------------------------------------------------------------ | ------------------ | ---- | --- | ------------------- | ----- |
|
||||
| id | | int unsigned | NO | PRI | NULL | |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | | NULL | |
|
||||
| uid | Owner id which owns this copy of the item | mediumint unsigned | NO | | NULL | |
|
||||
| parent-uri-id | Id of the item-uri table that contains the parent uri | int unsigned | YES | | NULL | |
|
||||
| thr-parent-id | Id of the item-uri table that contains the thread parent uri | int unsigned | YES | | NULL | |
|
||||
| created | Creation timestamp. | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| received | datetime | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| gravity | | tinyint unsigned | NO | | 0 | |
|
||||
| vid | Id of the verb table entry that contains the activity verbs | smallint unsigned | YES | | NULL | |
|
||||
| private | 0=public, 1=private, 2=unlisted | tinyint unsigned | NO | | 0 | |
|
||||
| wall | This item was posted to the wall of uid | boolean | NO | | 0 | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
||||
| Name | Fields |
|
||||
| ----------------- | ------------------- |
|
||||
| PRIMARY | id |
|
||||
| uid_uri-id | UNIQUE, uid, uri-id |
|
||||
| uri-id | uri-id |
|
||||
| parent-uri-id | parent-uri-id |
|
||||
| thr-parent-id | thr-parent-id |
|
||||
| vid | vid |
|
||||
| parent-uri-id_uid | parent-uri-id, uid |
|
||||
| uid_wall_received | uid, wall, received |
|
||||
|
||||
Foreign Keys
|
||||
------------
|
||||
|
||||
| Field | Target Table | Target Field |
|
||||
|-------|--------------|--------------|
|
||||
| uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| uid | [user](help/database/db_user) | uid |
|
||||
| parent-uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| thr-parent-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| vid | [verb](help/database/db_verb) | id |
|
||||
|
||||
Return to [database documentation](help/database)
|
|
@ -10,7 +10,7 @@ Fields
|
|||
| ---------- | --------------------------------------------------------------------- | ------------ | ---- | --- | ------- | ----- |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | PRI | NULL | |
|
||||
| owner-id | Item owner | int unsigned | NO | | 0 | |
|
||||
| media-type | Type of media in a bit array (1 = image, 2 = video, 4 = audio | tinyint | NO | | 0 | |
|
||||
| media-type | Type of media in a bit array (1 = image, 2 = video, 4 = audio) | tinyint | NO | | 0 | |
|
||||
| language | Language information about this post in the ISO 639-1 format | char(2) | YES | | NULL | |
|
||||
| searchtext | Simplified text for the full text search | mediumtext | YES | | NULL | |
|
||||
| size | Body size | int unsigned | YES | | NULL | |
|
||||
|
|
|
@ -25,6 +25,7 @@ Fields
|
|||
| post-reason | Reason why the post arrived at the user | tinyint unsigned | NO | | 0 | |
|
||||
| vid | Id of the verb table entry that contains the activity verbs | smallint unsigned | YES | | NULL | |
|
||||
| private | 0=public, 1=private, 2=unlisted | tinyint unsigned | NO | | 0 | |
|
||||
| restrictions | Bit array of post restrictions (1 = Reply, 2 = Like, 4 = Announce) | tinyint unsigned | YES | | NULL | |
|
||||
| global | | boolean | NO | | 0 | |
|
||||
| visible | | boolean | NO | | 0 | |
|
||||
| deleted | item has been marked for deletion | boolean | NO | | 0 | |
|
||||
|
|
|
@ -6,29 +6,30 @@ User specific public contact data
|
|||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------------------------- | ----------------------------------------------------------------------- | ------------------ | ---- | --- | ------- | ----- |
|
||||
| cid | Contact id of the linked public contact | int unsigned | NO | PRI | 0 | |
|
||||
| uid | User id | mediumint unsigned | NO | PRI | 0 | |
|
||||
| uri-id | Id of the item-uri table entry that contains the contact url | int unsigned | YES | | NULL | |
|
||||
| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | |
|
||||
| ignored | Posts from this contact are ignored | boolean | YES | | NULL | |
|
||||
| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | |
|
||||
| hidden | This contact is hidden from the others | boolean | YES | | NULL | |
|
||||
| is-blocked | User is blocked by this contact | boolean | YES | | NULL | |
|
||||
| channel-frequency | Controls the frequency of the appearance of this contact in channels | tinyint unsigned | YES | | NULL | |
|
||||
| pending | | boolean | YES | | NULL | |
|
||||
| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | |
|
||||
| info | | mediumtext | YES | | NULL | |
|
||||
| notify_new_posts | | boolean | YES | | NULL | |
|
||||
| remote_self | 0 => No mirroring, 1-2 => Mirror as own post, 3 => Mirror as reshare | tinyint unsigned | YES | | NULL | |
|
||||
| fetch_further_information | 0 => None, 1 => Fetch information, 3 => Fetch keywords, 2 => Fetch both | tinyint unsigned | YES | | NULL | |
|
||||
| ffi_keyword_denylist | | text | YES | | NULL | |
|
||||
| subhub | | boolean | YES | | NULL | |
|
||||
| hub-verify | | varbinary(383) | YES | | NULL | |
|
||||
| protocol | Protocol of the contact | char(4) | YES | | NULL | |
|
||||
| rating | Automatically detected feed poll frequency | tinyint | YES | | NULL | |
|
||||
| priority | Feed poll priority | tinyint unsigned | YES | | NULL | |
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------------------------- | -------------------------------------------------------------------------- | ------------------ | ---- | --- | ------- | ----- |
|
||||
| cid | Contact id of the linked public contact | int unsigned | NO | PRI | 0 | |
|
||||
| uid | User id | mediumint unsigned | NO | PRI | 0 | |
|
||||
| uri-id | Id of the item-uri table entry that contains the contact url | int unsigned | YES | | NULL | |
|
||||
| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | |
|
||||
| ignored | Posts from this contact are ignored | boolean | YES | | NULL | |
|
||||
| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | |
|
||||
| hidden | This contact is hidden from the others | boolean | YES | | NULL | |
|
||||
| channel-only | This contact is displayed only in channels, but not in the network stream. | boolean | YES | | NULL | |
|
||||
| is-blocked | User is blocked by this contact | boolean | YES | | NULL | |
|
||||
| channel-frequency | Controls the frequency of the appearance of this contact in channels | tinyint unsigned | YES | | NULL | |
|
||||
| pending | | boolean | YES | | NULL | |
|
||||
| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | |
|
||||
| info | | mediumtext | YES | | NULL | |
|
||||
| notify_new_posts | | boolean | YES | | NULL | |
|
||||
| remote_self | 0 => No mirroring, 1-2 => Mirror as own post, 3 => Mirror as reshare | tinyint unsigned | YES | | NULL | |
|
||||
| fetch_further_information | 0 => None, 1 => Fetch information, 3 => Fetch keywords, 2 => Fetch both | tinyint unsigned | YES | | NULL | |
|
||||
| ffi_keyword_denylist | | text | YES | | NULL | |
|
||||
| subhub | | boolean | YES | | NULL | |
|
||||
| hub-verify | | varbinary(383) | YES | | NULL | |
|
||||
| protocol | Protocol of the contact | char(4) | YES | | NULL | |
|
||||
| rating | Automatically detected feed poll frequency | tinyint | YES | | NULL | |
|
||||
| priority | Feed poll priority | tinyint unsigned | YES | | NULL | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
|
|
@ -418,10 +418,6 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
|
|||
Hook::callAll('storage_instance', $data);
|
||||
Hook::callAll('storage_config', $data);
|
||||
|
||||
### src/Module/Notifications/Ping.php
|
||||
|
||||
Hook::callAll('network_ping', $arr);
|
||||
|
||||
### src/Module/PermissionTooltip.php
|
||||
|
||||
Hook::callAll('lockview_content', $item);
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
Kanäle (Channels)
|
||||
=====
|
||||
|
||||
* [Home](help)
|
||||
|
||||
Kanäle sind eine Möglichkeit neue Inhalte zu finden, oder Inhalte anzuzeigen, die du sonst möglicherweise verpasst hättest.
|
||||
Es gibt mehrere vordefinierte Kanäle und zusätzlich kannst du deine eigenen, basierend auf ein paar Regeln, erstellen.
|
||||
Kanäle zeigen nur Beiträge aus den letzten 24 Stunden an. (Dieser Wert kann vom Administrator geändert werden.)
|
||||
|
||||
In den Anzeige-Einstellungen, im Bereich "Timelines", kannst du definieren, welche Kanäle und andere Timelines du im "Kanäle"-Widget auf der "Network"-Seite sehen möchtest und welche Kanäle in der Menüleiste oben auf der Seite erscheinen sollen.
|
||||
|
||||
Ebenfalls in den Anzeige-Einstellungen, im Bereich "Kanäle", kannst du alle die Sprachen einstellen, die du in deinen Kanälen sehen möchtest. Hier kannst du mehr als eine Sprache auswählen.
|
||||
|
||||
Auf der Profilseite kannst du die Kanal-Frequenz für jeden Kontakt definieren. Die Optionen sind:
|
||||
|
||||
* Standardhäufigkeit: Beiträge dieses Kontakts werden im "Für Dich"-Kanal angezeigt, wenn du häufig mit diesem Kontakt interagiert hast oder wenn ein Beitrag ein gewisses Maß an Interaktion erreicht hat.
|
||||
* Alle Beiträge dieses Kontakts anzeigen: Alle Beiträge dieses Kontakts werden auf dem Kanal "Für Dich" erscheinen
|
||||
* Zeige nur einige Beiträge an: Wenn ein Kontakt viele Beiträge in einem kurzen Zeitraum erstellt, reduziert diese Einstellung die Anzahl der angezeigten Beiträge in jedem Kanal.
|
||||
* Zeige keine Beiträge an: Beiträge von diesem Kontakt werden in keinem Kanal angezeigt.
|
||||
|
||||
Voreingestellte Kanäle
|
||||
---
|
||||
|
||||
* Für Dich: Beiträge von Kontakten mit denen du interagierst und die mit dir interagieren. Im Detail bestehend aus:
|
||||
* Beiträge von Leuten, mit denen du überdurchschnittlich viel interagierst.
|
||||
* Beiträge von Kontakten, denen du folgst und mit denen du überdurchschnittlich viel interagierst.
|
||||
* Beiträge von Kontakten, bei denen du "Benachrichtigung bei neuen Beiträgen" aktiviert hast oder wo du die Kanalfrequenz entsprechend eingestellt hast.
|
||||
* Entdecken: Beiträge von Kontakten denen du nicht folgst, aber denen zu folgen für dich interessant sein könnte. Im Detail bestehend aus:
|
||||
* Beiträge von Leuten denen du nicht folgst, aber mit denen du überdurchschnittlich viel interagierst.
|
||||
* Beiträge von Leuten denen du nicht folgst, aber die mit dir überdurchschnittlich viel interagieren.
|
||||
* Beliebte Beiträge von Leuten denen du nicht folgst, aber mit denen du interagiert hast oder die mit dir interagiert haben.
|
||||
* Angesagt: Beiträge mit überdurchschnittlich hoher Anzahl von Interaktionen.
|
||||
* Sprache: Beiträge in deiner Sprache.
|
||||
* Folgende: Beiträge von Leuten die dir folgen, aber denen du nicht folgst.
|
||||
* Geteilt von teilenden: Beiträge von Kontakten denen die Leute folgen, denen du folgst.
|
||||
* Ruhige teilende: Beiträge von Konten denen du folgst, aber die nicht sehr oft posten.
|
||||
* Bilder: Beiträge mit Bildern.
|
||||
* Audio: Beiträge mit Audio.
|
||||
* Videos: Beiträge mit Videos.
|
||||
|
||||
Vom Benutzer eingestellte Kanäle
|
||||
---
|
||||
|
||||
In den Einstellungen, unter "Kanäle", kannst du deine eigenen Kanäle erstellen.
|
||||
|
||||
Jeder Kanal wird durch diese Werte definiert:
|
||||
|
||||
* Bezeichnung: Dieses Feld ist notwendig und wird für die Kanalbezeichnung verwendet.
|
||||
* Beschreibung: Eine kurze Beschreibung des Inhalts. Dies kann helfen den Überblick zu behalten, wenn du viele Kanäle hast.
|
||||
* Zugriffsschlüssel: Wenn du auf diesen Kanal über einen Zugriffsschlüssel zugreifen willst, kannst du ihn hier festlegen. Achte darauf, dass du nicht einen bereits verwendeten Schlüssel benutzt.
|
||||
* Circle/Kanal: Dies definiert die Datenquelle für diesen Kanal. Voreingestellt ist die Globale Gemeinschaft. Es gibt ein paar vorgegebene Werte, wie die Konten denen du folgst, oder die Kontakte, die dir folgen. Außerdem können alle deine Circles ausgewählt werden.
|
||||
* Tags einschließen: Durch Kommata getrennte Liste von Tags. Ein Beitrag wird verwendet, wenn er eines der aufgeführten Tags enthält.
|
||||
* Tags ausschließen: Durch Kommata getrennte Liste von Tags. Wenn ein Beitrag eines dieser Tags enthält, wird er nicht Teil dieses Kanals sein.
|
||||
* Volltextsuche: Dies kann genutzt werden um Inhalte, basierend auf dem Inhalt und ein paar zusätzlichen Schlüsselwörtern, ein- oder auszuschließen. Es nutzt die "boolean mode"-Operatoren von MariaDB: https://mariadb.com/kb/en/full-text-index-overview/#in-boolean-mode
|
||||
* Bilder, Videos, Audio: Wenn ausgewählt, wirst du Inhalte mit dem gewählten Medientyp sehen. Diese Optionen können kombiniert werden. Wenn keines dieser Felder ausgewählt wurde, wirst du alle Inhalte, mit oder ohne angefügten Medien, sehen.
|
||||
|
||||
Zusätzliche Schlüsselwörter für die Volltextsuche
|
||||
---
|
||||
|
||||
Zusätzlich zu der Suche nach Inhalten, gibt es Schlüsselwörter, die in der Volltextsuche genutzt werden können.
|
||||
Alternativen werden durch "|" dargestellt.
|
||||
|
||||
* from - Verwende "from:nickname" oder "from:nickname@domain.tld" um nach Beiträgen von einem bestimmten Autor zu suchen.
|
||||
* to - Verwende "to:nickname" oder "to:nickname@domain.tld" um nach Beiträgen mit dem gegebenen Empfänger zu suchen.
|
||||
* group - Verwende "group:nickname" oder "group:nickname@domain.tld" um nach Beiträgen aus der gegebenen Gruppe zu suchen.
|
||||
* application | relay - Nutze "application:nickname" oder "application:nickname@domain.tld" um Beiträge zu finden, die von der gegebenen relay application geteilt wurden.
|
||||
* server - Verwende "server:hostname" um Beiträge von einem bestimmten Server zu suchen. Im Falle eine Gruppen-Postings enthält der Suchtext beides, den Hostname des Gruppen-Servers und den Hostname des Autors.
|
||||
* source - Der ActivityPub-Typ der Beitragsquelle. Nutze dies um beispielsweise Gruppenpostings oder Beiträge von Services (aka Bots) ein- oder auszuschließen.
|
||||
* source:person - Der Beitrag wurde von einem regulären Nutzerkonto erstellt.
|
||||
* source:organization - Der Beitrag wurde von einer Organisation erstellt.
|
||||
* source:group - Dieser Beitrag wurde über eine Gruppe erstellt oder verteilt.
|
||||
* source:service | source:news - Dieser Beitrag stammt aus einem 'service' Account. Dieser Quellen(source)-Typ wird oft genutzt um Bot Accounts zu markieren.
|
||||
* source:application | source:relay - Dieser Beitrag wurde von einer Anwendung (application) erstellt. Dies wird im Fediverse höchstwahrscheinlich für die Beitragserstellung nicht genutzt.
|
||||
* tag - Nutze "tag:tagname" um nach einem bestimmten tag (Schlagwort) zu suchen.
|
||||
* media - Mit diesem Schlüsselwort kannst du nach angefügten Medien suchen.
|
||||
* media:image | media:photo | media:picture - Dieser Beitrag enthält ein Bild
|
||||
* media:video - Dieser Beitrag enthält ein Video
|
||||
* media:audio - Dieser Beitrag enthält Audio
|
||||
* media:card - Dieser Beitrag enthält eine Linkvorschau-'card'
|
||||
* media:post - Dieser Beitrag verweist auf einen anderen Beitrag, was bedeutet, es ist ein zitierter Beitrag
|
||||
* network | net - Verwende dies um Netzwerke in deinen Kanal einzuschließen oder von ihm auszuschließen.
|
||||
* network:apub | network:activitypub - ActivityPub (verwendet von den Systemen im Fediverse)
|
||||
* network:dfrn | network:friendica - altes Friendica-Protokoll. Heutzutage nutzt Friendica meist ActivityPub.
|
||||
* network:dspr | network:diaspora - Das Diaspora-Protokoll wird hauptsächlich von Diaspora selbst genutzt. Ein paar andere Systeme unterstützen dieses Protokoll ebenfalls, wie Hubzilla, Socialhome or Ganggo.
|
||||
* network:feed - RSS/Atom feeds
|
||||
* network:mail - Mails die via IMAP importiert worden sind.
|
||||
* network:stat | network:ostatus - Das OStatus-Protokoll wird hauptsächlich von alten GNU Social-Installationen genutzt.
|
||||
* network:dscs | network:discourse - Beiträge, die über den Discourse connector empfangen werden.
|
||||
* network:tmbl | network:tumblr - Beiträge, die über den Tumblr connector empfangen werden.
|
||||
* network:bsky | network:bluesky - Beiträge, die über den Bluesky connector empfangen werden.
|
||||
* platform - Benutze dies, um Plattformen in deinen Kanal einzuschließen, oder von ihm auszuschließen, d.h. "+platform:friendica". Im Falle eines Gruppen-Postings enthält der Suchtext beides, die Plattform des Gruppen-Servers und die Plattform des Autors.
|
||||
* visibility - Du hast die Wahl zwischen verschiedenen Sichtbarkeiten. Du kannst nur die ungelisteten oder privaten Beiträge sehen, zu denen du Zugang hast.
|
||||
* visibility:public - (öffentlich)
|
||||
* visibility:unlisted - (ungelistet)
|
||||
* visibility:private - (privat)
|
||||
* language | lang - Verwende "language:code" um nach Beiträgen in der gewünschten Sprache (im [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format) zu suchen.
|
||||
|
||||
Denke daran, dass du diese Schlüsselwörter kombinieren kannst.
|
||||
So kannst du zum Beispiel einen Kanal erstellen, mit allen Beiträgen, die über das Fediverse sprechen, aber nicht im Fediverse veröffentlich wurden, mit diesen Suchbegriffen: "fediverse -network:apub -network:dfrn".
|
|
@ -17,7 +17,7 @@ Friendica - Dokumentation und Ressourcen
|
|||
* [Circles und Privatsphäre](help/Circles-and-Privacy)
|
||||
* [Tags und Erwähnungen](help/Tags-and-Mentions)
|
||||
* [Community-Gruppen](help/Groups)
|
||||
* [Channels](help/Channels)
|
||||
* [Kanäle (Channels)](help/Channels)
|
||||
* [Chats](help/Chats)
|
||||
* Weiterführende Informationen
|
||||
* [Account umziehen](help/Move-Account)
|
||||
|
|
|
@ -27,7 +27,7 @@ Requirements
|
|||
* Apache mit einer aktiverten mod-rewrite-Funktion und dem Eintrag "Options All", so dass du die lokale .htaccess-Datei nutzen kannst
|
||||
* PHP 7.4+
|
||||
* PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei
|
||||
* Curl, GD, GMP, PDO, mbstrings, MySQLi, hash, xml, zip, IntlChar and OpenSSL-Erweiterung
|
||||
* Curl, GD, GMP, PDO, mbstrings, MySQLi, hash, xml, zip, IntlChar, IDN und OpenSSL-Erweiterung
|
||||
* Das POSIX Modul muss aktiviert sein ([CentOS, RHEL](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) haben dies z.B. deaktiviert)
|
||||
* Einen E-Mail Server, so dass PHP `mail()` funktioniert.
|
||||
Wenn kein eigener E-Mail Server zur Verfügung steht, kann alternativ das [phpmailer](https://github.com/friendica/friendica-addons/tree/develop/phpmailer) Addon mit einem externen SMTP Account verwendet werden.
|
||||
|
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 400 KiB After Width: | Height: | Size: 371 KiB |
Before Width: | Height: | Size: 1011 KiB After Width: | Height: | Size: 707 KiB |
|
@ -45,7 +45,8 @@ use Friendica\Model\Post;
|
|||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
||||
function item_post(App $a) {
|
||||
function item_post()
|
||||
{
|
||||
$uid = DI::userSession()->getLocalUserId();
|
||||
|
||||
if (!$uid) {
|
||||
|
@ -248,7 +249,7 @@ function item_process(array $post, array $request, bool $preview, string $return
|
|||
$post['body'] .= DI::contentItem()->storeAttachmentFromRequest($request);
|
||||
}
|
||||
|
||||
$post = DI::contentItem()->finalizePost($post);
|
||||
$post = DI::contentItem()->finalizePost($post, $preview);
|
||||
|
||||
if (!strlen($post['body'])) {
|
||||
if ($preview) {
|
||||
|
@ -279,13 +280,14 @@ function item_process(array $post, array $request, bool $preview, string $return
|
|||
$post['body'] = BBCode::removeSharedData(Item::setHashtags($post['body']));
|
||||
$post['writable'] = true;
|
||||
$post['sensitive'] = false;
|
||||
$post['post-reason'] = Item::PR_LOCAL;
|
||||
|
||||
$o = DI::conversation()->render([$post], Conversation::MODE_SEARCH, false, true);
|
||||
|
||||
System::jsonExit(['preview' => $o]);
|
||||
}
|
||||
|
||||
Hook::callAll('post_local',$post);
|
||||
Hook::callAll('post_local', $post);
|
||||
|
||||
unset($post['edit']);
|
||||
unset($post['self']);
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Content\Pager;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
|
@ -34,7 +33,7 @@ use Friendica\Util\DateTimeFormat;
|
|||
use Friendica\Util\Strings;
|
||||
use Friendica\Util\Temporal;
|
||||
|
||||
function message_init(App $a)
|
||||
function message_init()
|
||||
{
|
||||
$tabs = '';
|
||||
|
||||
|
@ -61,7 +60,7 @@ function message_init(App $a)
|
|||
]);
|
||||
}
|
||||
|
||||
function message_post(App $a)
|
||||
function message_post()
|
||||
{
|
||||
if (!DI::userSession()->getLocalUserId()) {
|
||||
DI::sysmsg()->addNotice(DI::l10n()->t('Permission denied.'));
|
||||
|
@ -104,7 +103,7 @@ function message_post(App $a)
|
|||
}
|
||||
}
|
||||
|
||||
function message_content(App $a)
|
||||
function message_content()
|
||||
{
|
||||
$o = '';
|
||||
Nav::setSelected('messages');
|
||||
|
@ -114,7 +113,7 @@ function message_content(App $a)
|
|||
return Login::form();
|
||||
}
|
||||
|
||||
$myprofile = DI::baseUrl() . '/profile/' . $a->getLoggedInUserNickname();
|
||||
$myprofile = DI::baseUrl() . '/profile/' . DI::userSession()->getLocalUserNickname();
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate('mail_head.tpl');
|
||||
if (DI::args()->getArgc() > 1 && DI::args()->getArgv()[1] == 'new') {
|
||||
|
@ -177,7 +176,7 @@ function message_content(App $a)
|
|||
|
||||
$tpl = Renderer::getMarkupTemplate('msg-header.tpl');
|
||||
DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [
|
||||
'$nickname' => $a->getLoggedInUserNickname(),
|
||||
'$nickname' => DI::userSession()->getLocalUserNickname(),
|
||||
'$linkurl' => DI::l10n()->t('Please enter a link URL:')
|
||||
]);
|
||||
|
||||
|
@ -282,7 +281,7 @@ function message_content(App $a)
|
|||
|
||||
$tpl = Renderer::getMarkupTemplate('msg-header.tpl');
|
||||
DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [
|
||||
'$nickname' => $a->getLoggedInUserNickname(),
|
||||
'$nickname' => DI::userSession()->getLocalUserNickname(),
|
||||
'$linkurl' => DI::l10n()->t('Please enter a link URL:')
|
||||
]);
|
||||
|
||||
|
@ -415,12 +414,10 @@ function get_messages(int $uid, int $start, int $limit): array
|
|||
|
||||
function render_messages(array $msg, string $t): string
|
||||
{
|
||||
$a = DI::app();
|
||||
|
||||
$tpl = Renderer::getMarkupTemplate($t);
|
||||
$rslt = '';
|
||||
|
||||
$myprofile = DI::baseUrl() . '/profile/' . $a->getLoggedInUserNickname();
|
||||
$myprofile = DI::baseUrl() . '/profile/' . DI::userSession()->getLocalUserNickname();
|
||||
|
||||
foreach ($msg as $rr) {
|
||||
if ($rr['unknown']) {
|
||||
|
|
|
@ -46,7 +46,7 @@ function notes_content(App $a, bool $update = false)
|
|||
return;
|
||||
}
|
||||
|
||||
$o = BaseProfile::getTabsHTML('notes', true, $a->getLoggedInUserNickname(), false);
|
||||
$o = BaseProfile::getTabsHTML('notes', true, DI::userSession()->getLocalUserNickname(), false);
|
||||
|
||||
if (!$update) {
|
||||
$o .= '<h3>' . DI::l10n()->t('Personal Notes') . '</h3>';
|
||||
|
|
|
@ -19,11 +19,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Content\Pager;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Content\Widget;
|
||||
use Friendica\Core\ACL;
|
||||
use Friendica\Core\Addon;
|
||||
use Friendica\Core\Hook;
|
||||
|
@ -53,7 +51,7 @@ use Friendica\Util\Strings;
|
|||
use Friendica\Util\Temporal;
|
||||
use Friendica\Util\XML;
|
||||
|
||||
function photos_init(App $a)
|
||||
function photos_init()
|
||||
{
|
||||
if (DI::config()->get('system', 'block_public') && !DI::userSession()->isAuthenticated()) {
|
||||
return;
|
||||
|
@ -67,8 +65,6 @@ function photos_init(App $a)
|
|||
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
|
||||
}
|
||||
|
||||
$is_owner = (DI::userSession()->getLocalUserId() && (DI::userSession()->getLocalUserId() == $owner['uid']));
|
||||
|
||||
$albums = Photo::getAlbums($owner['uid']);
|
||||
|
||||
$albums_visible = ((intval($owner['hidewall']) && !DI::userSession()->isAuthenticated()) ? false : true);
|
||||
|
@ -125,7 +121,7 @@ function photos_init(App $a)
|
|||
return;
|
||||
}
|
||||
|
||||
function photos_post(App $a)
|
||||
function photos_post()
|
||||
{
|
||||
$user = User::getByNickname(DI::args()->getArgv()[1]);
|
||||
if (!DBA::isResult($user)) {
|
||||
|
@ -136,7 +132,7 @@ function photos_post(App $a)
|
|||
$visitor = 0;
|
||||
|
||||
$page_owner_uid = intval($user['uid']);
|
||||
$community_page = $user['page-flags'] == User::PAGE_FLAGS_COMMUNITY;
|
||||
$community_page = in_array($user['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_COMM_MAN]);
|
||||
|
||||
if (DI::userSession()->getLocalUserId() && (DI::userSession()->getLocalUserId() == $page_owner_uid)) {
|
||||
$can_post = true;
|
||||
|
@ -200,7 +196,7 @@ function photos_post(App $a)
|
|||
// Update the photo albums cache
|
||||
Photo::clearAlbumCache($page_owner_uid);
|
||||
|
||||
DI::baseUrl()->redirect('photos/' . $a->getLoggedInUserNickname() . '/album/' . bin2hex($newalbum));
|
||||
DI::baseUrl()->redirect('photos/' . DI::userSession()->getLocalUserNickname() . '/album/' . bin2hex($newalbum));
|
||||
return; // NOTREACHED
|
||||
}
|
||||
|
||||
|
@ -559,7 +555,7 @@ function photos_post(App $a)
|
|||
}
|
||||
}
|
||||
|
||||
function photos_content(App $a)
|
||||
function photos_content()
|
||||
{
|
||||
// URLs:
|
||||
// photos/name/upload
|
||||
|
@ -618,7 +614,7 @@ function photos_content(App $a)
|
|||
|
||||
$owner_uid = $user['uid'];
|
||||
|
||||
$community_page = (($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY) ? true : false);
|
||||
$community_page = in_array($user['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_COMM_MAN]);
|
||||
|
||||
if (DI::userSession()->getLocalUserId() && (DI::userSession()->getLocalUserId() == $owner_uid)) {
|
||||
$can_post = true;
|
||||
|
@ -672,18 +668,14 @@ function photos_content(App $a)
|
|||
|
||||
$selname = (!is_null($datum) && Strings::isHex($datum)) ? hex2bin($datum) : '';
|
||||
|
||||
$albumselect = '';
|
||||
$albumselect = ['' => '<current year>'];
|
||||
|
||||
$albumselect .= '<option value="" ' . (!$selname ? ' selected="selected" ' : '') . '><current year></option>';
|
||||
$albums = Photo::getAlbums($owner_uid);
|
||||
if (!empty($albums)) {
|
||||
foreach ($albums as $album) {
|
||||
if ($album['album'] === '') {
|
||||
continue;
|
||||
}
|
||||
$selected = (($selname === $album['album']) ? ' selected="selected" ' : '');
|
||||
$albumselect .= '<option value="' . $album['album'] . '"' . $selected . '>' . $album['album'] . '</option>';
|
||||
foreach (Photo::getAlbums($owner_uid) as $album) {
|
||||
if ($album['album'] === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$albumselect[$album['album']] = $album['album'];
|
||||
}
|
||||
|
||||
$uploader = '';
|
||||
|
@ -718,7 +710,7 @@ function photos_content(App $a)
|
|||
|
||||
$tpl = Renderer::getMarkupTemplate('photos_upload.tpl');
|
||||
|
||||
$aclselect_e = ($visitor ? '' : ACL::getFullSelectorHTML(DI::page(), $a->getLoggedInUserId()));
|
||||
$aclselect_e = ($visitor ? '' : ACL::getFullSelectorHTML(DI::page(), DI::userSession()->getLocalUserId()));
|
||||
|
||||
$o .= Renderer::replaceMacros($tpl, [
|
||||
'$pagename' => DI::l10n()->t('Upload Photos'),
|
||||
|
@ -729,9 +721,10 @@ function photos_content(App $a)
|
|||
'$existalbumtext' => DI::l10n()->t('or select existing album:'),
|
||||
'$nosharetext' => DI::l10n()->t('Do not show a status post for this upload'),
|
||||
'$albumselect' => $albumselect,
|
||||
'$selname' => $selname,
|
||||
'$permissions' => DI::l10n()->t('Permissions'),
|
||||
'$aclselect' => $aclselect_e,
|
||||
'$lockstate' => ACL::getLockstateForUserId($a->getLoggedInUserId()) ? 'lock' : 'unlock',
|
||||
'$lockstate' => ACL::getLockstateForUserId(DI::userSession()->getLocalUserId()) ? 'lock' : 'unlock',
|
||||
'$alt_uploader' => $ret['addon_text'],
|
||||
'$default_upload_box' => ($ret['default_upload'] ? $default_upload_box : ''),
|
||||
'$default_upload_submit' => ($ret['default_upload'] ? $default_upload_submit : ''),
|
||||
|
@ -1077,7 +1070,7 @@ function photos_content(App $a)
|
|||
|
||||
$album_e = $ph[0]['album'];
|
||||
$caption_e = $ph[0]['desc'];
|
||||
$aclselect_e = ACL::getFullSelectorHTML(DI::page(), $a->getLoggedInUserId(), false, ACL::getDefaultUserPermissions($ph[0]));
|
||||
$aclselect_e = ACL::getFullSelectorHTML(DI::page(), DI::userSession()->getLocalUserId(), false, ACL::getDefaultUserPermissions($ph[0]));
|
||||
|
||||
$edit = Renderer::replaceMacros($edit_tpl, [
|
||||
'$id' => $ph[0]['id'],
|
||||
|
|
53
src/App.php
|
@ -43,6 +43,7 @@ use Friendica\Model\Contact;
|
|||
use Friendica\Model\Profile;
|
||||
use Friendica\Module\Special\HTTPException as ModuleHTTPException;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Protocol\ATProtocol\DID;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\HTTPInputData;
|
||||
use Friendica\Util\HTTPSignature;
|
||||
|
@ -64,7 +65,7 @@ class App
|
|||
{
|
||||
const PLATFORM = 'Friendica';
|
||||
const CODENAME = 'Yellow Archangel';
|
||||
const VERSION = '2024.03';
|
||||
const VERSION = '2024.06-dev';
|
||||
|
||||
// Allow themes to control internal parameters
|
||||
// by changing App values in theme.php
|
||||
|
@ -133,42 +134,6 @@ class App
|
|||
*/
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::isAuthenticated()
|
||||
*/
|
||||
public function isLoggedIn(): bool
|
||||
{
|
||||
return $this->session->isAuthenticated();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::isSiteAdmin()
|
||||
*/
|
||||
public function isSiteAdmin(): bool
|
||||
{
|
||||
return $this->session->isSiteAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::getLocalUserId()
|
||||
*/
|
||||
public function getLoggedInUserId(): int
|
||||
{
|
||||
return $this->session->getLocalUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 2022.03
|
||||
* @see IHandleUserSessions::getLocalUserNickname()
|
||||
*/
|
||||
public function getLoggedInUserNickname(): string
|
||||
{
|
||||
return $this->session->getLocalUserNickname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the profile owner ID
|
||||
*
|
||||
|
@ -565,8 +530,8 @@ class App
|
|||
*/
|
||||
public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, Nav $nav, ModuleHTTPException $httpException, HTTPInputData $httpInput, float $start_time, array $server)
|
||||
{
|
||||
$requeststring = ($_SERVER['REQUEST_METHOD'] ?? '') . ' ' . ($_SERVER['REQUEST_URI'] ?? '') . ' ' . ($_SERVER['SERVER_PROTOCOL'] ?? '');
|
||||
$this->logger->debug('Request received', ['address' => $_SERVER['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $_SERVER['HTTP_REFERER'] ?? '', 'user-agent' => $_SERVER['HTTP_USER_AGENT'] ?? '']);
|
||||
$requeststring = ($server['REQUEST_METHOD'] ?? '') . ' ' . ($server['REQUEST_URI'] ?? '') . ' ' . ($server['SERVER_PROTOCOL'] ?? '');
|
||||
$this->logger->debug('Request received', ['address' => $server['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $server['HTTP_REFERER'] ?? '', 'user-agent' => $server['HTTP_USER_AGENT'] ?? '']);
|
||||
$request_start = microtime(true);
|
||||
|
||||
$this->profiler->set($start_time, 'start');
|
||||
|
@ -593,8 +558,10 @@ class App
|
|||
Core\Hook::callAll('init_1');
|
||||
}
|
||||
|
||||
DID::routeRequest($this->args->getCommand(), $server);
|
||||
|
||||
if ($this->mode->isNormal() && !$this->mode->isBackend()) {
|
||||
$requester = HTTPSignature::getSigner('', $_SERVER);
|
||||
$requester = HTTPSignature::getSigner('', $server);
|
||||
if (!empty($requester)) {
|
||||
Profile::addVisitorCookieForHandle($requester);
|
||||
}
|
||||
|
@ -713,13 +680,13 @@ class App
|
|||
|
||||
// Wrapping HTML responses in the theme template
|
||||
if ($response->getHeaderLine(ICanCreateResponses::X_HEADER) === ICanCreateResponses::TYPE_HTML) {
|
||||
$response = $page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId());
|
||||
$response = $page->run($this, $this->session, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId());
|
||||
}
|
||||
|
||||
$this->logger->debug('Request processed sucessfully', ['response' => $response->getStatusCode(), 'address' => $_SERVER['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $_SERVER['HTTP_REFERER'] ?? '', 'user-agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
$this->logger->debug('Request processed sucessfully', ['response' => $response->getStatusCode(), 'address' => $server['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $server['HTTP_REFERER'] ?? '', 'user-agent' => $server['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
System::echoResponse($response);
|
||||
} catch (HTTPException $e) {
|
||||
$this->logger->debug('Request processed with exception', ['response' => $e->getCode(), 'address' => $_SERVER['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $_SERVER['HTTP_REFERER'] ?? '', 'user-agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
$this->logger->debug('Request processed with exception', ['response' => $e->getCode(), 'address' => $server['REMOTE_ADDR'] ?? '', 'request' => $requeststring, 'referer' => $server['HTTP_REFERER'] ?? '', 'user-agent' => $server['HTTP_USER_AGENT'] ?? '', 'duration' => number_format(microtime(true) - $request_start, 3)]);
|
||||
$httpException->rawContent($e);
|
||||
}
|
||||
$page->logRuntime($this->config, 'runFrontend');
|
||||
|
|
|
@ -32,6 +32,7 @@ use Friendica\Core\L10n;
|
|||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Session\Model\UserSession;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Core\Theme;
|
||||
use Friendica\Module\Response;
|
||||
|
@ -325,13 +326,13 @@ class Page implements ArrayAccess
|
|||
*
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private function initFooter(App $app, Mode $mode, L10n $l10n)
|
||||
private function initFooter(UserSession $session, Mode $mode, L10n $l10n)
|
||||
{
|
||||
// If you're just visiting, let javascript take you home
|
||||
if (!empty($_SESSION['visitor_home'])) {
|
||||
$homebase = $_SESSION['visitor_home'];
|
||||
} elseif (!empty($app->getLoggedInUserNickname())) {
|
||||
$homebase = 'profile/' . $app->getLoggedInUserNickname();
|
||||
} elseif (!empty($session->getLocalUserNickname())) {
|
||||
$homebase = 'profile/' . $session->getLocalUserNickname();
|
||||
}
|
||||
|
||||
if (isset($homebase)) {
|
||||
|
@ -420,7 +421,7 @@ class Page implements ArrayAccess
|
|||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws HTTPException\ServiceUnavailableException
|
||||
*/
|
||||
public function run(App $app, BaseURL $baseURL, Arguments $args, Mode $mode, ResponseInterface $response, L10n $l10n, Profiler $profiler, IManageConfigValues $config, IManagePersonalConfigValues $pconfig, Nav $nav, int $localUID)
|
||||
public function run(App $app, UserSession $session, BaseURL $baseURL, Arguments $args, Mode $mode, ResponseInterface $response, L10n $l10n, Profiler $profiler, IManageConfigValues $config, IManagePersonalConfigValues $pconfig, Nav $nav, int $localUID)
|
||||
{
|
||||
$moduleName = $args->getModuleName();
|
||||
|
||||
|
@ -459,7 +460,7 @@ class Page implements ArrayAccess
|
|||
/* Build the page ending -- this is stuff that goes right before
|
||||
* the closing </body> tag
|
||||
*/
|
||||
$this->initFooter($app, $mode, $l10n);
|
||||
$this->initFooter($session, $mode, $l10n);
|
||||
|
||||
$profiler->set(microtime(true) - $timestamp, 'aftermath');
|
||||
|
||||
|
|
|
@ -356,7 +356,7 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
*/
|
||||
public static function getFormSecurityToken(string $typename = ''): string
|
||||
{
|
||||
$user = User::getById(DI::app()->getLoggedInUserId(), ['guid', 'prvkey']);
|
||||
$user = User::getById(DI::userSession()->getLocalUserId(), ['guid', 'prvkey']);
|
||||
$timestamp = time();
|
||||
$sec_hash = hash('whirlpool', ($user['guid'] ?? '') . ($user['prvkey'] ?? '') . session_id() . $timestamp . $typename);
|
||||
|
||||
|
@ -390,7 +390,7 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
|
||||
$max_livetime = 10800; // 3 hours
|
||||
|
||||
$user = User::getById(DI::app()->getLoggedInUserId(), ['guid', 'prvkey']);
|
||||
$user = User::getById(DI::userSession()->getLocalUserId(), ['guid', 'prvkey']);
|
||||
|
||||
$x = explode('.', $hash);
|
||||
if (time() > (intval($x[0]) + $max_livetime)) {
|
||||
|
@ -410,7 +410,7 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
public static function checkFormSecurityTokenRedirectOnError(string $err_redirect, string $typename = '', string $formname = 'form_security_token')
|
||||
{
|
||||
if (!self::checkFormSecurityToken($typename, $formname)) {
|
||||
Logger::notice('checkFormSecurityToken failed: user ' . DI::app()->getLoggedInUserNickname() . ' - form element ' . $typename);
|
||||
Logger::notice('checkFormSecurityToken failed: user ' . DI::userSession()->getLocalUserNickname() . ' - form element ' . $typename);
|
||||
Logger::debug('checkFormSecurityToken failed', ['request' => $_REQUEST]);
|
||||
DI::sysmsg()->addNotice(self::getFormSecurityStandardErrorMessage());
|
||||
DI::baseUrl()->redirect($err_redirect);
|
||||
|
@ -420,7 +420,7 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
public static function checkFormSecurityTokenForbiddenOnError(string $typename = '', string $formname = 'form_security_token')
|
||||
{
|
||||
if (!self::checkFormSecurityToken($typename, $formname)) {
|
||||
Logger::notice('checkFormSecurityToken failed: user ' . DI::app()->getLoggedInUserNickname() . ' - form element ' . $typename);
|
||||
Logger::notice('checkFormSecurityToken failed: user ' . DI::userSession()->getLocalUserNickname() . ' - form element ' . $typename);
|
||||
Logger::debug('checkFormSecurityToken failed', ['request' => $_REQUEST]);
|
||||
|
||||
throw new \Friendica\Network\HTTPException\ForbiddenException();
|
||||
|
|
|
@ -57,7 +57,7 @@ class Avatar
|
|||
return $fields;
|
||||
}
|
||||
|
||||
if (Network::isLocalLink($avatar) || empty($avatar)) {
|
||||
if (DI::baseUrl()->isLocalUrl($avatar) || empty($avatar)) {
|
||||
self::deleteCache($contact);
|
||||
return $fields;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ class Avatar
|
|||
return $fields;
|
||||
}
|
||||
|
||||
if (Network::isLocalLink($contact['avatar']) || empty($contact['avatar'])) {
|
||||
if (DI::baseUrl()->isLocalUrl($contact['avatar']) || empty($contact['avatar'])) {
|
||||
self::deleteCache($contact);
|
||||
return $fields;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace Friendica\Content;
|
|||
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
|
||||
/**
|
||||
* This pager should be used by lists using the min_id†/max_id† parameters
|
||||
|
@ -67,7 +67,7 @@ class BoundariesPager extends Pager
|
|||
|
||||
$parsed['query'] = http_build_query($queryParameters);
|
||||
|
||||
$url = Network::unparseURL($parsed);
|
||||
$url = (string)Uri::fromParts((array)$parsed);
|
||||
|
||||
$this->setQueryString($url);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ use Friendica\Core\Hook;
|
|||
use Friendica\Core\Protocol;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
|
||||
/**
|
||||
* ContactSelector class
|
||||
|
@ -102,7 +102,7 @@ class ContactSelector
|
|||
// Create the server url out of the profile url
|
||||
$parts = parse_url($profile);
|
||||
unset($parts['path']);
|
||||
$server_url = Strings::normaliseLink(Network::unparseURL($parts));
|
||||
$server_url = Strings::normaliseLink((string)Uri::fromParts((array)$parts));
|
||||
}
|
||||
|
||||
self::$server_url[$profile] = $server_url;
|
||||
|
|
|
@ -308,7 +308,7 @@ class Conversation
|
|||
|
||||
public function statusEditor(array $x = [], int $notes_cid = 0, bool $popup = false): string
|
||||
{
|
||||
$user = User::getById($this->app->getLoggedInUserId(), ['uid', 'nickname', 'allow_location', 'default-location']);
|
||||
$user = User::getById($this->session->getLocalUserId(), ['uid', 'nickname', 'allow_location', 'default-location']);
|
||||
if (empty($user['uid'])) {
|
||||
return '';
|
||||
}
|
||||
|
@ -332,7 +332,6 @@ class Conversation
|
|||
$tpl = Renderer::getMarkupTemplate('jot-header.tpl');
|
||||
$this->page['htmlhead'] .= Renderer::replaceMacros($tpl, [
|
||||
'$newpost' => 'true',
|
||||
'$baseurl' => $this->baseURL,
|
||||
'$geotag' => $geotag,
|
||||
'$nickname' => $x['nickname'],
|
||||
'$ispublic' => $this->l10n->t('Visible to <strong>everybody</strong>'),
|
||||
|
@ -389,7 +388,7 @@ class Conversation
|
|||
'$title' => $x['title'] ?? '',
|
||||
'$placeholdertitle' => $this->l10n->t('Set title'),
|
||||
'$category' => $x['category'] ?? '',
|
||||
'$placeholdercategory' => Feature::isEnabled($this->session->getLocalUserId(), 'categories') ? $this->l10n->t("Categories \x28comma-separated list\x29") : '',
|
||||
'$placeholdercategory' => Feature::isEnabled($this->session->getLocalUserId(), Feature::CATEGORIES) ? $this->l10n->t("Categories \x28comma-separated list\x29") : '',
|
||||
'$scheduled_at' => Temporal::getDateTimeField(
|
||||
new \DateTime(),
|
||||
new \DateTime('now + 6 months'),
|
||||
|
@ -405,7 +404,6 @@ class Conversation
|
|||
'$posttype' => $notes_cid ? ItemModel::PT_PERSONAL_NOTE : ItemModel::PT_ARTICLE,
|
||||
'$content' => $x['content'] ?? '',
|
||||
'$post_id' => $x['post_id'] ?? '',
|
||||
'$baseurl' => $this->baseURL,
|
||||
'$defloc' => $x['default_location'],
|
||||
'$visitor' => $x['visitor'],
|
||||
'$pvisit' => $notes_cid ? 'none' : $x['visitor'],
|
||||
|
@ -591,7 +589,6 @@ class Conversation
|
|||
}
|
||||
|
||||
$o = Renderer::replaceMacros($page_template, [
|
||||
'$baseurl' => $this->baseURL,
|
||||
'$return_path' => $this->args->getQueryString(),
|
||||
'$live_update' => $live_update_div,
|
||||
'$remove' => $this->l10n->t('remove'),
|
||||
|
@ -1517,14 +1514,6 @@ class Conversation
|
|||
|
||||
[$categories, $folders] = $this->item->determineCategoriesTerms($item, $this->session->getLocalUserId());
|
||||
|
||||
if (!empty($item['title'])) {
|
||||
$title = $item['title'];
|
||||
} elseif (!empty($item['content-warning']) && $this->pConfig->get($this->session->getLocalUserId(), 'system', 'disable_cw', false)) {
|
||||
$title = ucfirst($item['content-warning']);
|
||||
} else {
|
||||
$title = '';
|
||||
}
|
||||
|
||||
if (!empty($item['featured'])) {
|
||||
$pinned = $this->l10n->t('Pinned item');
|
||||
} else {
|
||||
|
@ -1550,7 +1539,8 @@ class Conversation
|
|||
'sparkle' => $sparkle,
|
||||
'lock' => false,
|
||||
'thumb' => $this->baseURL->remove($this->item->getAuthorAvatar($item)),
|
||||
'title' => $title,
|
||||
'title' => $item['title'],
|
||||
'summary' => $item['content-warning'],
|
||||
'body_html' => $body_html,
|
||||
'tags' => $tags['tags'],
|
||||
'hashtags' => $tags['hashtags'],
|
||||
|
|
|
@ -26,6 +26,25 @@ use Friendica\DI;
|
|||
|
||||
class Feature
|
||||
{
|
||||
const ACCOUNTS = 'accounts';
|
||||
const ADD_ABSTRACT = 'add_abstract';
|
||||
const ARCHIVE = 'archive';
|
||||
const CATEGORIES = 'categories';
|
||||
const CHANNELS = 'channels';
|
||||
const CIRCLES = 'circles';
|
||||
const COMMUNITY = 'community';
|
||||
const EXPLICIT_MENTIONS = 'explicit_mentions';
|
||||
const FOLDERS = 'folders';
|
||||
const GROUPS = 'forumlist_profile';
|
||||
const MEMBER_SINCE = 'profile_membersince';
|
||||
const NETWORKS = 'networks';
|
||||
const NOSHARER = 'nosharer';
|
||||
const PHOTO_LOCATION = 'photo_location';
|
||||
const PUBLIC_CALENDAR = 'public_calendar';
|
||||
const SEARCHES = 'searches';
|
||||
const TAGCLOUD = 'tagadelic';
|
||||
const TRENDING_TAGS = 'trending_tags';
|
||||
|
||||
/**
|
||||
* check if feature is enabled
|
||||
*
|
||||
|
@ -34,25 +53,18 @@ class Feature
|
|||
* @return boolean
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function isEnabled(int $uid, $feature)
|
||||
public static function isEnabled(int $uid, $feature): bool
|
||||
{
|
||||
$x = DI::config()->get('feature_lock', $feature, false);
|
||||
|
||||
if ($x === false) {
|
||||
$x = DI::pConfig()->get($uid, 'feature', $feature, false);
|
||||
if (!DI::config()->get('feature_lock', $feature, false)) {
|
||||
$enabled = DI::config()->get('feature', $feature) ?? self::getDefault($feature);
|
||||
$enabled = DI::pConfig()->get($uid, 'feature', $feature) ?? $enabled;
|
||||
} else {
|
||||
$enabled = true;
|
||||
}
|
||||
|
||||
if ($x === false) {
|
||||
$x = DI::config()->get('feature', $feature, false);
|
||||
}
|
||||
|
||||
if ($x === false) {
|
||||
$x = self::getDefault($feature);
|
||||
}
|
||||
|
||||
$arr = ['uid' => $uid, 'feature' => $feature, 'enabled' => $x];
|
||||
$arr = ['uid' => $uid, 'feature' => $feature, 'enabled' => $enabled];
|
||||
Hook::callAll('isEnabled', $arr);
|
||||
return($arr['enabled']);
|
||||
return (bool)$arr['enabled'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,8 +76,7 @@ class Feature
|
|||
*/
|
||||
private static function getDefault($feature)
|
||||
{
|
||||
$f = self::get();
|
||||
foreach ($f as $cat) {
|
||||
foreach (self::get() as $cat) {
|
||||
foreach ($cat as $feat) {
|
||||
if (is_array($feat) && $feat[0] === $feature) {
|
||||
return $feat[3];
|
||||
|
@ -95,36 +106,49 @@ class Feature
|
|||
'general' => [
|
||||
DI::l10n()->t('General Features'),
|
||||
//array('expire', DI::l10n()->t('Content Expiration'), DI::l10n()->t('Remove old posts/comments after a period of time')),
|
||||
['photo_location', DI::l10n()->t('Photo Location'), DI::l10n()->t("Photo metadata is normally stripped. This extracts the location \x28if present\x29 prior to stripping metadata and links it to a map."), false, DI::config()->get('feature_lock', 'photo_location', false)],
|
||||
['trending_tags', DI::l10n()->t('Trending Tags'), DI::l10n()->t('Show a community page widget with a list of the most popular tags in recent public posts.'), false, DI::config()->get('feature_lock', 'trending_tags', false)],
|
||||
[self::PHOTO_LOCATION, DI::l10n()->t('Photo Location'), DI::l10n()->t("Photo metadata is normally stripped. This extracts the location \x28if present\x29 prior to stripping metadata and links it to a map."), false, DI::config()->get('feature_lock', self::PHOTO_LOCATION, false)],
|
||||
[self::COMMUNITY, DI::l10n()->t('Display the community in the navigation'), DI::l10n()->t('If enabled, the community can be accessed via the navigation menu. Independent from this setting, the community timelines can always be accessed via the channels.'), true, DI::config()->get('feature_lock', self::COMMUNITY, false)],
|
||||
],
|
||||
|
||||
// Post composition
|
||||
'composition' => [
|
||||
DI::l10n()->t('Post Composition Features'),
|
||||
['aclautomention', DI::l10n()->t('Auto-mention Groups'), DI::l10n()->t('Add/remove mention when a group page is selected/deselected in ACL window.'), false, DI::config()->get('feature_lock', 'aclautomention', false)],
|
||||
['explicit_mentions', DI::l10n()->t('Explicit Mentions'), DI::l10n()->t('Add explicit mentions to comment box for manual control over who gets mentioned in replies.'), false, DI::config()->get('feature_lock', 'explicit_mentions', false)],
|
||||
['add_abstract', DI::l10n()->t('Add an abstract from ActivityPub content warnings'), DI::l10n()->t('Add an abstract when commenting on ActivityPub posts with a content warning. Abstracts are displayed as content warning on systems like Mastodon or Pleroma.'), false, DI::config()->get('feature_lock', 'add_abstract', false)],
|
||||
[self::EXPLICIT_MENTIONS, DI::l10n()->t('Explicit Mentions'), DI::l10n()->t('Add explicit mentions to comment box for manual control over who gets mentioned in replies.'), false, DI::config()->get('feature_lock', Feature::EXPLICIT_MENTIONS, false)],
|
||||
[self::ADD_ABSTRACT, DI::l10n()->t('Add an abstract from ActivityPub content warnings'), DI::l10n()->t('Add an abstract when commenting on ActivityPub posts with a content warning. Abstracts are displayed as content warning on systems like Mastodon or Pleroma.'), false, DI::config()->get('feature_lock', self::ADD_ABSTRACT, false)],
|
||||
],
|
||||
|
||||
// Item tools
|
||||
'tools' => [
|
||||
DI::l10n()->t('Post/Comment Tools'),
|
||||
['categories', DI::l10n()->t('Post Categories'), DI::l10n()->t('Add categories to your posts'), false, DI::config()->get('feature_lock', 'categories', false)],
|
||||
[self::CATEGORIES, DI::l10n()->t('Post Categories'), DI::l10n()->t('Add categories to your posts'), false, DI::config()->get('feature_lock', self::CATEGORIES, false)],
|
||||
],
|
||||
|
||||
// Widget visibility on the network stream
|
||||
'network' => [
|
||||
DI::l10n()->t('Network Widgets'),
|
||||
[self::CIRCLES, DI::l10n()->t('Circles'), DI::l10n()->t('Display posts that have been created by accounts of the selected circle.'), true, DI::config()->get('feature_lock', self::CIRCLES, false)],
|
||||
[self::GROUPS, DI::l10n()->t('Groups'), DI::l10n()->t('Display posts that have been distributed by the selected group.'), true, DI::config()->get('feature_lock', self::GROUPS, false)],
|
||||
[self::ARCHIVE, DI::l10n()->t('Archives'), DI::l10n()->t('Display an archive where posts can be selected by month and year.'), true, DI::config()->get('feature_lock', self::ARCHIVE, false)],
|
||||
[self::NETWORKS, DI::l10n()->t('Protocols'), DI::l10n()->t('Display posts with the selected protocols.'), true, DI::config()->get('feature_lock', self::NETWORKS, false)],
|
||||
[self::ACCOUNTS, DI::l10n()->t('Account Types'), DI::l10n()->t('Display posts done by accounts with the selected account type.'), true, DI::config()->get('feature_lock', self::ACCOUNTS, false)],
|
||||
[self::CHANNELS, DI::l10n()->t('Channels'), DI::l10n()->t('Display posts in the system channels and user defined channels.'), true, DI::config()->get('feature_lock', self::CHANNELS, false)],
|
||||
[self::SEARCHES, DI::l10n()->t('Saved Searches'), DI::l10n()->t('Display posts that contain subscribed hashtags.'), true, DI::config()->get('feature_lock', self::SEARCHES, false)],
|
||||
[self::FOLDERS, DI::l10n()->t('Saved Folders'), DI::l10n()->t('Display a list of folders in which posts are stored.'), true, DI::config()->get('feature_lock', self::FOLDERS, false)],
|
||||
[self::NOSHARER, DI::l10n()->t('Own Contacts'), DI::l10n()->t('Include or exclude posts from subscribed accounts. This widget is not visible on all channels.'), true, DI::config()->get('feature_lock', self::NOSHARER, false)],
|
||||
[self::TRENDING_TAGS, DI::l10n()->t('Trending Tags'), DI::l10n()->t('Display a list of the most popular tags in recent public posts.'), false, DI::config()->get('feature_lock', self::TRENDING_TAGS, false)],
|
||||
],
|
||||
|
||||
// Advanced Profile Settings
|
||||
'advanced_profile' => [
|
||||
DI::l10n()->t('Advanced Profile Settings'),
|
||||
['forumlist_profile', DI::l10n()->t('List Groups'), DI::l10n()->t('Show visitors public groups at the Advanced Profile Page'), false, DI::config()->get('feature_lock', 'forumlist_profile', false)],
|
||||
['tagadelic', DI::l10n()->t('Tag Cloud'), DI::l10n()->t('Provide a personal tag cloud on your profile page'), false, DI::config()->get('feature_lock', 'tagadelic', false)],
|
||||
['profile_membersince', DI::l10n()->t('Display Membership Date'), DI::l10n()->t('Display membership date in profile'), false, DI::config()->get('feature_lock', 'profile_membersince', false)],
|
||||
[self::TAGCLOUD, DI::l10n()->t('Tag Cloud'), DI::l10n()->t('Provide a personal tag cloud on your profile page'), false, DI::config()->get('feature_lock', self::TAGCLOUD, false)],
|
||||
[self::MEMBER_SINCE, DI::l10n()->t('Display Membership Date'), DI::l10n()->t('Display membership date in profile'), false, DI::config()->get('feature_lock', self::MEMBER_SINCE, false)],
|
||||
],
|
||||
|
||||
//Advanced Calendar Settings
|
||||
'advanced_calendar' => [
|
||||
DI::l10n()->t('Advanced Calendar Settings'),
|
||||
['public_calendar', DI::l10n()->t('Allow anonymous access to your calendar'), DI::l10n()->t('Allows anonymous visitors to consult your calendar and your public events. Contact birthday events are private to you.'), false, DI::config()->get('feature_lock', 'public_calendar', false)],
|
||||
[self::PUBLIC_CALENDAR, DI::l10n()->t('Allow anonymous access to your calendar'), DI::l10n()->t('Allows anonymous visitors to consult your calendar and your public events. Contact birthday events are private to you.'), false, DI::config()->get('feature_lock', self::PUBLIC_CALENDAR, false)],
|
||||
]
|
||||
];
|
||||
|
||||
|
|
|
@ -172,8 +172,7 @@ class GroupManager
|
|||
*/
|
||||
public static function profileAdvanced($uid)
|
||||
{
|
||||
$profile = intval(Feature::isEnabled($uid, 'forumlist_profile'));
|
||||
if (!$profile) {
|
||||
if (!Feature::isEnabled($uid, Feature::GROUPS)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ use Friendica\Model\User;
|
|||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Object\EMail\ItemCCEMail;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Util\ACLFormatter;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Emailer;
|
||||
|
@ -440,9 +439,11 @@ class Item
|
|||
];
|
||||
|
||||
if (!empty($item['language'])) {
|
||||
$menu[$this->l10n->t('Languages')] = 'javascript:alert(\'' . ItemModel::getLanguageMessage($item) . '\');';
|
||||
$menu[$this->l10n->t('Languages')] = 'javascript:displayLanguage(' . $item['uri-id'] . ');';
|
||||
}
|
||||
|
||||
$menu[$this->l10n->t('Search Text')] = 'javascript:displaySearchText(' . $item['uri-id'] . ');';
|
||||
|
||||
if ((($cid == 0) || ($rel == Contact::FOLLOWER)) &&
|
||||
in_array($item['network'], Protocol::FEDERATED)
|
||||
) {
|
||||
|
@ -800,14 +801,14 @@ class Item
|
|||
*/
|
||||
public function addShareLink(string $body, int $quote_uri_id): string
|
||||
{
|
||||
$post = Post::selectFirstPost(['uri', 'plink'], ['uri-id' => $quote_uri_id]);
|
||||
$post = Post::selectFirstPost(['uri'], ['uri-id' => $quote_uri_id]);
|
||||
if (empty($post)) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
$body = BBCode::removeSharedData($body);
|
||||
|
||||
$body .= "\n♲ " . ($post['plink'] ?: $post['uri']);
|
||||
$body .= "\nRE: " . $post['uri'];
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
@ -910,40 +911,6 @@ class Item
|
|||
return $post;
|
||||
}
|
||||
|
||||
public function moveAttachmentsFromBodyToAttach(array $post): array
|
||||
{
|
||||
if (!preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/', $post['body'], $match)) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
foreach ($match[2] as $attachment_id) {
|
||||
$attachment = Attach::selectFirst(['id', 'uid', 'filename', 'filesize', 'filetype'], ['id' => $attachment_id, 'uid' => $post['uid']]);
|
||||
if (empty($attachment)) {
|
||||
continue;
|
||||
}
|
||||
if ($post['attach']) {
|
||||
$post['attach'] .= ',';
|
||||
}
|
||||
$post['attach'] .= Post\Media::getAttachElement(
|
||||
$this->baseURL . '/attach/' . $attachment['id'],
|
||||
$attachment['filesize'],
|
||||
$attachment['filetype'],
|
||||
$attachment['filename'] ?? ''
|
||||
);
|
||||
|
||||
$fields = [
|
||||
'allow_cid' => $post['allow_cid'], 'allow_gid' => $post['allow_gid'],
|
||||
'deny_cid' => $post['deny_cid'], 'deny_gid' => $post['deny_gid']
|
||||
];
|
||||
$condition = ['id' => $attachment_id];
|
||||
Attach::update($fields, $condition);
|
||||
}
|
||||
|
||||
$post['body'] = str_replace($match[1], '', $post['body']);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
private function setObjectType(array $post): array
|
||||
{
|
||||
if (empty($post['post-type'])) {
|
||||
|
@ -1023,8 +990,13 @@ class Item
|
|||
return $post;
|
||||
}
|
||||
|
||||
public function finalizePost(array $post): array
|
||||
public function finalizePost(array $post, bool $preview): array
|
||||
{
|
||||
if ($preview) {
|
||||
$post['body'] = Attach::addAttachmentToBody($post['body'], $post['uid']);
|
||||
} else {
|
||||
Attach::setPermissionFromBody($post);
|
||||
}
|
||||
if (preg_match("/\[attachment\](.*?)\[\/attachment\]/ism", $post['body'], $matches)) {
|
||||
$post['body'] = preg_replace("/\[attachment].*?\[\/attachment\]/ism", PageInfo::getFooterFromUrl($matches[1]), $post['body']);
|
||||
}
|
||||
|
@ -1045,7 +1017,7 @@ class Item
|
|||
|
||||
public function postProcessPost(array $post, array $recipients = [])
|
||||
{
|
||||
if (!\Friendica\Content\Feature::isEnabled($post['uid'], 'explicit_mentions') && ($post['gravity'] == ItemModel::GRAVITY_COMMENT)) {
|
||||
if (!Feature::isEnabled($post['uid'], Feature::EXPLICIT_MENTIONS) && ($post['gravity'] == ItemModel::GRAVITY_COMMENT)) {
|
||||
Tag::createImplicitMentions($post['uri-id'], $post['thr-parent-id']);
|
||||
}
|
||||
|
||||
|
@ -1078,7 +1050,7 @@ class Item
|
|||
$to_author = DBA::selectFirst('account-view', ['ap-followers'], ['id' => $to['author-id']]);
|
||||
$parent = Post::selectFirstPost(['author-id'], ['uri-id' => $parentUriId]);
|
||||
$parent_author = DBA::selectFirst('account-view', ['ap-followers'], ['id' => $parent['author-id']]);
|
||||
|
||||
|
||||
$followers = '';
|
||||
foreach (array_column(Tag::getByURIId($parentUriId, [Tag::TO, Tag::CC, Tag::BCC]), 'url') as $url) {
|
||||
if ($url == $parent_author['ap-followers']) {
|
||||
|
|
|
@ -251,7 +251,7 @@ class Nav
|
|||
$nav['home'] = [$homelink, $this->l10n->t('Home'), '', $this->l10n->t('Home Page')];
|
||||
}
|
||||
|
||||
if (intval($this->config->get('config', 'register_policy')) === \Friendica\Module\Register::OPEN && !$this->session->isAuthenticated()) {
|
||||
if (\Friendica\Module\Register::getPolicy() === \Friendica\Module\Register::OPEN && !$this->session->isAuthenticated()) {
|
||||
$nav['register'] = ['register', $this->l10n->t('Register'), '', $this->l10n->t('Create an account')];
|
||||
}
|
||||
|
||||
|
@ -284,8 +284,8 @@ class Nav
|
|||
$gdirpath = Profile::zrl($this->config->get('system', 'directory'), true);
|
||||
}
|
||||
|
||||
if (($this->session->getLocalUserId() || $this->config->get('system', 'community_page_style') != Community::DISABLED_VISITOR) &&
|
||||
!($this->config->get('system', 'community_page_style') == Community::DISABLED)) {
|
||||
if (Feature::isEnabled($this->session->getLocalUserId(), Feature::COMMUNITY) && (($this->session->getLocalUserId() || $this->config->get('system', 'community_page_style') != Community::DISABLED_VISITOR) &&
|
||||
!($this->config->get('system', 'community_page_style') == Community::DISABLED))) {
|
||||
$nav['community'] = ['community', $this->l10n->t('Community'), '', $this->l10n->t('Conversations on this and other servers')];
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ use Friendica\Database\Database;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\ParseUrl;
|
||||
|
@ -86,7 +87,7 @@ class OEmbed
|
|||
|
||||
if (!in_array($ext, $noexts)) {
|
||||
// try oembed autodiscovery
|
||||
$html_text = DI::httpClient()->fetch($embedurl, HttpClientAccept::HTML, 15);
|
||||
$html_text = DI::httpClient()->fetch($embedurl, HttpClientAccept::HTML, 15, '', HttpClientRequest::SITEINFO);
|
||||
if (!empty($html_text)) {
|
||||
$dom = new DOMDocument();
|
||||
if (@$dom->loadHTML($html_text)) {
|
||||
|
@ -100,7 +101,7 @@ class OEmbed
|
|||
// but their OEmbed endpoint is only accessible by HTTPS ¯\_(ツ)_/¯
|
||||
$href = str_replace(['http://www.youtube.com/', 'http://player.vimeo.com/'],
|
||||
['https://www.youtube.com/', 'https://player.vimeo.com/'], $href);
|
||||
$result = DI::httpClient()->fetchFull($href . '&maxwidth=' . $a->getThemeInfoValue('videowidth'));
|
||||
$result = DI::httpClient()->fetchFull($href . '&maxwidth=' . $a->getThemeInfoValue('videowidth'), HttpClientAccept::DEFAULT, 0, '', HttpClientRequest::SITEINFO);
|
||||
if ($result->isSuccess()) {
|
||||
$json_string = $result->getBodyString();
|
||||
break;
|
||||
|
|
|
@ -29,9 +29,9 @@ use Friendica\Core\Renderer;
|
|||
use Friendica\Core\Search;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Strings;
|
||||
use Friendica\Util\XML;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use League\HTMLToMarkdown\HtmlConverter;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
|
@ -253,13 +253,14 @@ class HTML
|
|||
self::tagToBBCode($doc, 'span', ['class' => 'type-link'], '[class=type-link]', '[/class]');
|
||||
self::tagToBBCode($doc, 'span', ['class' => 'type-video'], '[class=type-video]', '[/class]');
|
||||
|
||||
self::tagToBBCode($doc, 'strong', [], '[b]', '[/b]');
|
||||
self::tagToBBCode($doc, 'em', [], '[i]', '[/i]');
|
||||
self::tagToBBCode($doc, 'b', [], '[b]', '[/b]');
|
||||
self::tagToBBCode($doc, 'i', [], '[i]', '[/i]');
|
||||
self::tagToBBCode($doc, 'u', [], '[u]', '[/u]');
|
||||
self::tagToBBCode($doc, 's', [], '[s]', '[/s]');
|
||||
self::tagToBBCode($doc, 'del', [], '[s]', '[/s]');
|
||||
$elements = [
|
||||
'b', 'del', 'em', 'i', 'ins', 'kbd', 'mark',
|
||||
's', 'samp', 'strong', 'sub', 'sup', 'u', 'var'
|
||||
];
|
||||
foreach ($elements as $element) {
|
||||
self::tagToBBCode($doc, $element, [], '[' . $element . ']', '[/' . $element . ']');
|
||||
}
|
||||
|
||||
self::tagToBBCode($doc, 'strike', [], '[s]', '[/s]');
|
||||
|
||||
self::tagToBBCode($doc, 'big', [], "[size=large]", "[/size]");
|
||||
|
@ -406,7 +407,7 @@ class HTML
|
|||
}
|
||||
|
||||
$parts = array_merge($base, parse_url($url));
|
||||
$url2 = Network::unparseURL($parts);
|
||||
$url2 = (string)Uri::fromParts((array)$parts);
|
||||
|
||||
return str_replace($url, $url2, $link);
|
||||
}
|
||||
|
@ -1060,4 +1061,15 @@ class HTML
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a document contains HTML or entities
|
||||
*
|
||||
* @param string $text
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isHTML(string $text): bool
|
||||
{
|
||||
return ($text != html_entity_decode($text)) || ($text != strip_tags($text));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ class Widget
|
|||
|
||||
if (DI::config()->get('system', 'invitation_only')) {
|
||||
$x = intval(DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'invites_remaining'));
|
||||
if ($x || DI::app()->isSiteAdmin()) {
|
||||
if ($x || DI::userSession()->isSiteAdmin()) {
|
||||
DI::page()['aside'] .= '<div class="side-link widget" id="side-invite-remain">'
|
||||
. DI::l10n()->tt('%d invitation available', '%d invitations available', $x)
|
||||
. '</div>';
|
||||
|
@ -336,7 +336,7 @@ class Widget
|
|||
*/
|
||||
public static function categories(int $uid, string $baseurl, string $selected = ''): string
|
||||
{
|
||||
if (!Feature::isEnabled($uid, 'categories')) {
|
||||
if (!Feature::isEnabled($uid, Feature::CATEGORIES)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@ -428,7 +428,7 @@ class Widget
|
|||
return '';
|
||||
}
|
||||
|
||||
if (Feature::isEnabled($uid, 'tagadelic')) {
|
||||
if (Feature::isEnabled($uid, Feature::TAGCLOUD)) {
|
||||
$owner_id = Contact::getPublicIdByUserId($uid);
|
||||
|
||||
if (!$owner_id) {
|
||||
|
@ -598,4 +598,4 @@ class Widget
|
|||
$channelname
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace Friendica\Content\Widget;
|
||||
|
||||
use Friendica\Content\Conversation\Entity\Community;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Tag;
|
||||
|
@ -39,9 +40,9 @@ class TrendingTags
|
|||
* @return string Formatted HTML code
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getHTML(string $content = 'global', int $period = 24): string
|
||||
public static function getHTML(string $content = Community::GLOBAL, int $period = 24): string
|
||||
{
|
||||
if ($content == 'local') {
|
||||
if ($content == Community::LOCAL) {
|
||||
$tags = Tag::getLocalTrendingHashtags($period, 20);
|
||||
} else {
|
||||
$tags = Tag::getGlobalTrendingHashtags($period, 20);
|
||||
|
|
|
@ -43,9 +43,10 @@ class VCard
|
|||
* @template widget/vcard.tpl
|
||||
* @param array $contact
|
||||
* @param bool $hide_mention
|
||||
* @param bool $hide_follow
|
||||
* @return string
|
||||
*/
|
||||
public static function getHTML(array $contact, bool $hide_mention = false): string
|
||||
public static function getHTML(array $contact, bool $hide_mention = false, bool $hide_follow = false): string
|
||||
{
|
||||
if (!isset($contact['network']) || !isset($contact['id'])) {
|
||||
Logger::warning('Incomplete contact', ['contact' => $contact ?? []]);
|
||||
|
@ -87,7 +88,7 @@ class VCard
|
|||
}
|
||||
}
|
||||
|
||||
if (empty($contact['self']) && Protocol::supportsFollow($contact['network'])) {
|
||||
if (!$hide_follow && empty($contact['self']) && Protocol::supportsFollow($contact['network'])) {
|
||||
if (in_array($rel, [Contact::SHARING, Contact::FRIEND])) {
|
||||
$unfollow_link = 'contact/unfollow?url=' . urlencode($contact_url) . '&auto=1';
|
||||
} elseif (!$pending) {
|
||||
|
|
|
@ -140,7 +140,8 @@ class Addon
|
|||
$func();
|
||||
}
|
||||
|
||||
Hook::delete(['file' => 'addon/' . $addon . '/' . $addon . '.php']);
|
||||
// Handles both relative and absolute file paths
|
||||
Hook::delete(['`file` LIKE ?', "%addon/$addon/$addon.php"]);
|
||||
|
||||
unset(self::$addons[array_search($addon, self::$addons)]);
|
||||
}
|
||||
|
|
|
@ -495,6 +495,13 @@ class Installer
|
|||
);
|
||||
$returnVal = $returnVal ? $status : false;
|
||||
|
||||
$status = $this->checkFunction('idn_to_ascii',
|
||||
DI::l10n()->t('IDN Functions PHP module'),
|
||||
DI::l10n()->t('Error: IDN Functions PHP module required but not installed.'),
|
||||
true
|
||||
);
|
||||
$returnVal = $returnVal ? $status : false;
|
||||
|
||||
return $returnVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,8 +75,11 @@ class Renderer
|
|||
{
|
||||
DI::profiler()->startRecording('rendering');
|
||||
|
||||
// pass $baseurl to all templates if it isn't set
|
||||
$vars = array_merge(['$baseurl' => DI::baseUrl(), '$APP' => DI::app()], $vars);
|
||||
// Default template variables
|
||||
$vars = array_merge([
|
||||
'$baseurl' => DI::baseUrl(),
|
||||
'$VERSION' => \Friendica\App::VERSION,
|
||||
], $vars);
|
||||
|
||||
$t = self::getTemplateEngine();
|
||||
|
||||
|
@ -84,7 +87,7 @@ class Renderer
|
|||
$output = $t->replaceMacros($template, $vars);
|
||||
} catch (Exception $e) {
|
||||
DI::logger()->critical($e->getMessage(), ['template' => $template, 'vars' => $vars]);
|
||||
$message = DI::app()->isSiteAdmin() ?
|
||||
$message = DI::userSession()->isSiteAdmin() ?
|
||||
$e->getMessage() :
|
||||
DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.');
|
||||
throw new ServiceUnavailableException($message);
|
||||
|
@ -113,7 +116,7 @@ class Renderer
|
|||
$template = $t->getTemplateFile($file, $subDir);
|
||||
} catch (Exception $e) {
|
||||
DI::logger()->critical($e->getMessage(), ['file' => $file, 'subDir' => $subDir]);
|
||||
$message = DI::app()->isSiteAdmin() ?
|
||||
$message = DI::userSession()->isSiteAdmin() ?
|
||||
$e->getMessage() :
|
||||
DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.');
|
||||
throw new ServiceUnavailableException($message);
|
||||
|
@ -142,7 +145,7 @@ class Renderer
|
|||
} else {
|
||||
$admin_message = DI::l10n()->t('template engine cannot be registered without a name.');
|
||||
DI::logger()->critical($admin_message, ['class' => $class]);
|
||||
$message = DI::app()->isSiteAdmin() ?
|
||||
$message = DI::userSession()->isSiteAdmin() ?
|
||||
$admin_message :
|
||||
DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.');
|
||||
throw new ServiceUnavailableException($message);
|
||||
|
@ -176,7 +179,7 @@ class Renderer
|
|||
|
||||
$admin_message = DI::l10n()->t('template engine is not registered!');
|
||||
DI::logger()->critical($admin_message, ['template_engine' => $template_engine]);
|
||||
$message = DI::app()->isSiteAdmin() ?
|
||||
$message = DI::userSession()->isSiteAdmin() ?
|
||||
$admin_message :
|
||||
DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.');
|
||||
throw new ServiceUnavailableException($message);
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace Friendica\Core;
|
|||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Object\Search\ContactResult;
|
||||
use Friendica\Object\Search\ResultList;
|
||||
|
@ -125,7 +127,7 @@ class Search
|
|||
$searchUrl .= '&page=' . $page;
|
||||
}
|
||||
|
||||
$resultJson = DI::httpClient()->fetch($searchUrl, HttpClientAccept::JSON);
|
||||
$resultJson = DI::httpClient()->fetch($searchUrl, HttpClientAccept::JSON, 0, '', HttpClientRequest::CONTACTDISCOVER);
|
||||
|
||||
$results = json_decode($resultJson, true);
|
||||
|
||||
|
@ -232,7 +234,7 @@ class Search
|
|||
$return = Contact::searchByName($search, $mode, true);
|
||||
} else {
|
||||
$p = $page > 1 ? 'p=' . $page : '';
|
||||
$curlResult = DI::httpClient()->get(self::getGlobalDirectory() . '/search/people?' . $p . '&q=' . urlencode($search), HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get(self::getGlobalDirectory() . '/search/people?' . $p . '&q=' . urlencode($search), HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::CONTACTDISCOVER]);
|
||||
if ($curlResult->isSuccess()) {
|
||||
$searchResult = json_decode($curlResult->getBodyString(), true);
|
||||
if (!empty($searchResult['profiles'])) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace Friendica\Core;
|
||||
|
||||
use Friendica\Core\Cache\Enum\Duration;
|
||||
use Friendica\Core\Worker\Entity\Process;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
|
@ -54,7 +55,8 @@ class Worker
|
|||
const FAST_COMMANDS = ['APDelivery', 'Delivery'];
|
||||
|
||||
const LOCK_PROCESS = 'worker_process';
|
||||
const LOCK_WORKER = 'worker';
|
||||
const LOCK_WORKER = 'worker';
|
||||
const LAST_CHECK = 'worker::check';
|
||||
|
||||
private static $up_start;
|
||||
private static $db_duration = 0;
|
||||
|
@ -832,6 +834,17 @@ class Worker
|
|||
} else {
|
||||
self::spawnWorker();
|
||||
}
|
||||
} elseif (($active > $queues) && ($active < $maxqueues) && ($load < $maxsysload)) {
|
||||
$max_idletime = DI::config()->get('system', 'worker_max_idletime');
|
||||
$last_check = DI::cache()->get(self::LAST_CHECK);
|
||||
$last_date = $last_check ? date('c', $last_check) : '';
|
||||
if (($max_idletime > 0) && (time() > $last_check + $max_idletime) && !DBA::exists('workerqueue', ["`done` AND `executed` > ?", DateTimeFormat::utc('now - ' . $max_idletime . ' second')])) {
|
||||
DI::cache()->set(self::LAST_CHECK, time(), Duration::HOUR);
|
||||
Logger::info('The last worker execution had been too long ago.', ['last' => $last_check, 'last-check' => $last_date, 'seconds' => $max_idletime, 'load' => $load, 'max_load' => $maxsysload, 'active_worker' => $active, 'max_worker' => $maxqueues]);
|
||||
return false;
|
||||
} elseif ($max_idletime > 0) {
|
||||
Logger::debug('Maximum idletime not reached.', ['last' => $last_check, 'last-check' => $last_date, 'seconds' => $max_idletime, 'load' => $load, 'max_load' => $maxsysload, 'active_worker' => $active, 'max_worker' => $maxqueues]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,6 @@ class Activities extends BaseFactory
|
|||
break;
|
||||
|
||||
default:
|
||||
$this->logger->warning('Unsupported verb in parent item:', ['parent_item' => $parent_item]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
namespace Friendica\Factory\Api\Mastodon;
|
||||
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Content\Conversation\Entity\Timeline;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
@ -45,4 +46,14 @@ class ListEntity extends BaseFactory
|
|||
$circle = $this->dba->selectFirst('group', ['name'], ['id' => $id, 'deleted' => false]);
|
||||
return new \Friendica\Object\Api\Mastodon\ListEntity($id, $circle['name'] ?? '', 'list');
|
||||
}
|
||||
|
||||
public function createFromChannel(Timeline $channel): \Friendica\Object\Api\Mastodon\ListEntity
|
||||
{
|
||||
return new \Friendica\Object\Api\Mastodon\ListEntity('channel:' . $channel->code, $channel->label, 'followed');
|
||||
}
|
||||
|
||||
public function createFromGroup(array $group): \Friendica\Object\Api\Mastodon\ListEntity
|
||||
{
|
||||
return new \Friendica\Object\Api\Mastodon\ListEntity('group:' . $group['id'], $group['name'], 'followed');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,14 +105,12 @@ class APContact
|
|||
/**
|
||||
* Fetches a profile from a given url
|
||||
*
|
||||
* @param string $url profile url
|
||||
* @param boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||
* @param string $url profile url
|
||||
* @param ?boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||
* @return array profile array
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
* @todo Rewrite parameter $update to avoid true|false|null (boolean is binary, null adds a third case)
|
||||
*/
|
||||
public static function getByURL(string $url, $update = null): array
|
||||
public static function getByURL(string $url, bool $update = null): array
|
||||
{
|
||||
if (empty($url) || Network::isUrlBlocked($url)) {
|
||||
Logger::info('Domain is blocked', ['url' => $url]);
|
||||
|
@ -184,7 +182,7 @@ class APContact
|
|||
DI::cache()->set($cachekey, System::callstack(20), Duration::FIVE_MINUTES);
|
||||
}
|
||||
|
||||
if (Network::isLocalLink($url) && ($local_uid = User::getIdForURL($url))) {
|
||||
if (DI::baseUrl()->isLocalUrl($url) && ($local_uid = User::getIdForURL($url))) {
|
||||
try {
|
||||
$data = Transmitter::getProfile($local_uid);
|
||||
$local_owner = User::getOwnerDataById($local_uid);
|
||||
|
|
|
@ -30,6 +30,7 @@ use Friendica\Object\Image;
|
|||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Mimetype;
|
||||
use Friendica\Security\Security;
|
||||
use Friendica\Util\Network;
|
||||
|
||||
/**
|
||||
* Class to handle attach database table
|
||||
|
@ -109,16 +110,17 @@ class Attach
|
|||
/**
|
||||
* Retrieve a single record given the ID
|
||||
*
|
||||
* @param int $id Row id of the record
|
||||
* @param int $id Row id of the record
|
||||
* @param int $uid User-Id
|
||||
*
|
||||
* @return bool|array
|
||||
*
|
||||
* @throws \Exception
|
||||
* @see \Friendica\Database\DBA::select
|
||||
*/
|
||||
public static function getById(int $id)
|
||||
public static function getById(int $id, int $uid)
|
||||
{
|
||||
return self::selectFirst([], ['id' => $id]);
|
||||
return self::selectFirst([], ['id' => $id, 'uid' => $uid]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,7 +199,7 @@ class Attach
|
|||
* @return boolean|integer Row id on success, False on errors
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function store(string $data, int $uid, string $filename, string $filetype = '' , int $filesize = null, string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '')
|
||||
public static function store(string $data, int $uid, string $filename, string $filetype = '', int $filesize = null, string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '')
|
||||
{
|
||||
if ($filetype === '') {
|
||||
$filetype = Mimetype::getContentType($filename);
|
||||
|
@ -279,9 +281,9 @@ class Attach
|
|||
{
|
||||
if (!is_null($img)) {
|
||||
// get items to update
|
||||
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
|
||||
$items = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
|
||||
|
||||
foreach($items as $item) {
|
||||
foreach ($items as $item) {
|
||||
try {
|
||||
$backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
|
||||
$fields['backend-ref'] = $backend_class->put($img->asString(), $item['backend-ref'] ?? '');
|
||||
|
@ -313,9 +315,9 @@ class Attach
|
|||
public static function delete(array $conditions, array $options = []): bool
|
||||
{
|
||||
// get items to delete data info
|
||||
$items = self::selectToArray(['backend-class','backend-ref'], $conditions);
|
||||
$items = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
|
||||
|
||||
foreach($items as $item) {
|
||||
foreach ($items as $item) {
|
||||
try {
|
||||
$backend_class = DI::storageManager()->getWritableStorageByName($item['backend-class'] ?? '');
|
||||
$backend_class->delete($item['backend-ref'] ?? '');
|
||||
|
@ -328,4 +330,41 @@ class Attach
|
|||
|
||||
return DBA::delete('attach', $conditions, $options);
|
||||
}
|
||||
|
||||
public static function setPermissionFromBody(array $post)
|
||||
{
|
||||
preg_match_all("/\[attachment\](.*?)\[\/attachment\]/ism", $post['body'], $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $attachment) {
|
||||
if (DI::baseUrl()->isLocalUrl($attachment[1]) && preg_match('|.*?/attach/(\d+)|', $attachment[1], $match)) {
|
||||
$fields = [
|
||||
'allow_cid' => $post['allow_cid'], 'allow_gid' => $post['allow_gid'],
|
||||
'deny_cid' => $post['deny_cid'], 'deny_gid' => $post['deny_gid']
|
||||
];
|
||||
self::update($fields, ['id' => $match[1], 'uid' => $post['uid']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function addAttachmentToBody(string $body, int $uid): string
|
||||
{
|
||||
preg_match_all("/\[attachment\](.*?)\[\/attachment\]/ism", $body, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $attachment) {
|
||||
if (DI::baseUrl()->isLocalUrl($attachment[1]) && preg_match('|.*?/attach/(\d+)|', $attachment[1], $match)) {
|
||||
$attach = self::getById($match[1], $uid);
|
||||
if (empty($attach)) {
|
||||
return $body;
|
||||
}
|
||||
$media = [
|
||||
'type' => Post\Media::DOCUMENT,
|
||||
'url' => $attachment[1],
|
||||
'size' => $attach['filesize'],
|
||||
'mimetype' => $attach['filetype'],
|
||||
'description' => $attach['filename']
|
||||
];
|
||||
$media = Post\Media::addType($media);
|
||||
$body = str_replace($attachment[0], Post\Media::addAttachmentToBody($media, ''), $body);
|
||||
}
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,15 +113,6 @@ class Contact
|
|||
* @}
|
||||
*/
|
||||
|
||||
/** @deprecated Use Entity\LocalRelationship::MIRROR_DEACTIVATED instead */
|
||||
const MIRROR_DEACTIVATED = LocalRelationship::MIRROR_DEACTIVATED;
|
||||
/** @deprecated Now does the same as MIRROR_OWN_POST */
|
||||
const MIRROR_FORWARDED = 1;
|
||||
/** @deprecated Use Entity\LocalRelationship::MIRROR_OWN_POST instead */
|
||||
const MIRROR_OWN_POST = LocalRelationship::MIRROR_OWN_POST;
|
||||
/** @deprecated Use Entity\LocalRelationship::MIRROR_NATIVE_RESHARE instead */
|
||||
const MIRROR_NATIVE_RESHARE = LocalRelationship::MIRROR_NATIVE_RESHARE;
|
||||
|
||||
/**
|
||||
* @param array $fields Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
|
@ -892,10 +883,10 @@ class Contact
|
|||
|
||||
$fields['avatar'] = User::getAvatarUrl($user);
|
||||
$fields['header'] = User::getBannerUrl($user);
|
||||
$fields['forum'] = $user['page-flags'] == User::PAGE_FLAGS_COMMUNITY;
|
||||
$fields['forum'] = in_array($user['page-flags'], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_COMM_MAN]);
|
||||
$fields['prv'] = $user['page-flags'] == User::PAGE_FLAGS_PRVGROUP;
|
||||
$fields['unsearchable'] = !$profile['net-publish'];
|
||||
$fields['manually-approve'] = in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP]);
|
||||
$fields['manually-approve'] = in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP, User::PAGE_FLAGS_COMM_MAN]);
|
||||
$fields['baseurl'] = DI::baseUrl();
|
||||
$fields['gsid'] = GServer::getID($fields['baseurl'], true);
|
||||
|
||||
|
@ -1793,7 +1784,7 @@ class Contact
|
|||
return;
|
||||
}
|
||||
|
||||
if (Network::isLocalLink($contact['url'])) {
|
||||
if (DI::baseUrl()->isLocalUrl($contact['url'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1910,7 +1901,7 @@ class Contact
|
|||
return $contact;
|
||||
}
|
||||
|
||||
$local = !empty($contact['url']) && Network::isLocalLink($contact['url']);
|
||||
$local = !empty($contact['url']) && DI::baseUrl()->isLocalUrl($contact['url']);
|
||||
|
||||
if (!$local && !empty($contact['id']) && !empty($contact['avatar'])) {
|
||||
self::updateAvatar($contact['id'], $contact['avatar'], true);
|
||||
|
@ -2300,7 +2291,7 @@ class Contact
|
|||
if (($uid == 0) && !$force && empty($contact['thumb']) && empty($contact['micro']) && !$create_cache) {
|
||||
if (($contact['avatar'] != $avatar) || empty($contact['blurhash'])) {
|
||||
$update_fields = ['avatar' => $avatar];
|
||||
if (!Network::isLocalLink($avatar)) {
|
||||
if (!DI::baseUrl()->isLocalUrl($avatar)) {
|
||||
try {
|
||||
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
|
||||
|
||||
|
@ -2348,7 +2339,7 @@ class Contact
|
|||
$cache_avatar = DI::config()->get('system', 'cache_contact_avatar');
|
||||
|
||||
// Local contact avatars don't need to be cached
|
||||
if ($cache_avatar && Network::isLocalLink($contact['url'])) {
|
||||
if ($cache_avatar && DI::baseUrl()->isLocalUrl($contact['url'])) {
|
||||
$cache_avatar = !DBA::exists('contact', ['nurl' => $contact['nurl'], 'self' => true]);
|
||||
}
|
||||
|
||||
|
|
|
@ -364,6 +364,53 @@ class User
|
|||
return $frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channel only value for contact id and user id
|
||||
*
|
||||
* @param int $cid Either public contact id or user's contact id
|
||||
* @param int $uid User ID
|
||||
* @param int $isChannelOnly Is channel only
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function setChannelOnly(int $cid, int $uid, bool $isChannelOnly)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['channel-only' => $isChannelOnly], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the contact is channel only for contact id and user id
|
||||
*
|
||||
* @param int $cid Either public contact id or user's contact id
|
||||
* @param int $uid User ID
|
||||
* @return bool Contact is channel only
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function getChannelOnly(int $cid, int $uid): bool
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$isChannelOnly = false;
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-only'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
$isChannelOnly = $public_contact['channel-only'] ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isChannelOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/Release that the user is blocked by the contact
|
||||
*
|
||||
|
|
|
@ -516,7 +516,7 @@ class Event
|
|||
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Access to this profile has been restricted.'));
|
||||
}
|
||||
|
||||
if (!DI::userSession()->isAuthenticated() && !Feature::isEnabled($owner['uid'], 'public_calendar')) {
|
||||
if (!DI::userSession()->isAuthenticated() && !Feature::isEnabled($owner['uid'], Feature::PUBLIC_CALENDAR)) {
|
||||
throw new HTTPException\UnauthorizedException(DI::l10n()->t('Permission denied.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ use Friendica\Module\Register;
|
|||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Capability\ICanHandleHttpResponses;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Protocol\Relay;
|
||||
|
@ -611,7 +612,7 @@ class GServer
|
|||
$in_webroot = empty(parse_url($url, PHP_URL_PATH));
|
||||
|
||||
// When a nodeinfo is present, we don't need to dig further
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/x-nodeinfo2', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/x-nodeinfo2', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if ($curlResult->isTimeout()) {
|
||||
self::setFailureByUrl($url);
|
||||
return false;
|
||||
|
@ -622,7 +623,7 @@ class GServer
|
|||
} else {
|
||||
$serverdata = self::parseNodeinfo210($curlResult);
|
||||
if (empty($serverdata)) {
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/nodeinfo', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/nodeinfo', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$serverdata = self::fetchNodeinfo($url, $curlResult);
|
||||
}
|
||||
}
|
||||
|
@ -640,9 +641,9 @@ class GServer
|
|||
if ($in_webroot) {
|
||||
// Fetch the landing page, possibly it reveals some data
|
||||
$accept = 'application/activity+json,application/ld+json,application/json,*/*;q=0.9';
|
||||
$curlResult = DI::httpClient()->get($url, $accept);
|
||||
$curlResult = DI::httpClient()->get($url, $accept, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() && $curlResult->getReturnCode() == '406') {
|
||||
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML);
|
||||
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$html_fetched = true;
|
||||
} else {
|
||||
$html_fetched = false;
|
||||
|
@ -655,10 +656,10 @@ class GServer
|
|||
$serverdata = $data['server'];
|
||||
$systemactor = $data['actor'];
|
||||
if (!$html_fetched && !in_array($serverdata['detection-method'], [self::DETECT_SYSTEM_ACTOR, self::DETECT_AP_COLLECTION])) {
|
||||
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML);
|
||||
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
}
|
||||
} elseif (!$html_fetched && (strlen($curlResult->getBodyString()) < 1000)) {
|
||||
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML);
|
||||
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
}
|
||||
|
||||
if ($serverdata['detection-method'] != self::DETECT_SYSTEM_ACTOR) {
|
||||
|
@ -867,7 +868,7 @@ class GServer
|
|||
{
|
||||
Logger::info('Discover relay data', ['server' => $server_url]);
|
||||
|
||||
$curlResult = DI::httpClient()->get($server_url . '/.well-known/x-social-relay', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($server_url . '/.well-known/x-social-relay', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return;
|
||||
}
|
||||
|
@ -962,7 +963,7 @@ class GServer
|
|||
*/
|
||||
private static function fetchStatistics(string $url, array $serverdata): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/statistics.json', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/statistics.json', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1109,7 +1110,7 @@ class GServer
|
|||
*/
|
||||
private static function parseNodeinfo1(string $nodeinfo_url): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return [];
|
||||
}
|
||||
|
@ -1209,7 +1210,7 @@ class GServer
|
|||
*/
|
||||
private static function parseNodeinfo2(string $nodeinfo_url): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return [];
|
||||
}
|
||||
|
@ -1429,7 +1430,7 @@ class GServer
|
|||
*/
|
||||
private static function fetchSiteinfo(string $url, array $serverdata): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/siteinfo.json', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/siteinfo.json', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1586,8 +1587,11 @@ class GServer
|
|||
private static function getNomadName(string $url): string
|
||||
{
|
||||
$name = 'nomad';
|
||||
$curlResult = DI::httpClient()->get($url . '/manifest', 'application/manifest+json');
|
||||
$curlResult = DI::httpClient()->get($url . '/manifest', 'application/manifest+json', [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBodyString() == '')) {
|
||||
if ($curlResult->getReturnCode() == 418) {
|
||||
$name = 'streams';
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
@ -1607,7 +1611,7 @@ class GServer
|
|||
*/
|
||||
private static function getNomadVersion(string $url): string
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/api/z/1.0/version', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/z/1.0/version', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBodyString() == '')) {
|
||||
return '';
|
||||
}
|
||||
|
@ -1629,7 +1633,7 @@ class GServer
|
|||
private static function validHostMeta(string $url): bool
|
||||
{
|
||||
$xrd_timeout = DI::config()->get('system', 'xrd_timeout');
|
||||
$curlResult = DI::httpClient()->get($url . Probe::HOST_META, HttpClientAccept::XRD_XML, [HttpClientOptions::TIMEOUT => $xrd_timeout]);
|
||||
$curlResult = DI::httpClient()->get($url . Probe::HOST_META, HttpClientAccept::XRD_XML, [HttpClientOptions::TIMEOUT => $xrd_timeout, HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1728,7 +1732,7 @@ class GServer
|
|||
{
|
||||
$serverdata['poco'] = '';
|
||||
|
||||
$curlResult = DI::httpClient()->get($url . '/poco', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/poco', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1758,7 +1762,7 @@ class GServer
|
|||
*/
|
||||
public static function checkMastodonDirectory(string $url, array $serverdata): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/directory?limit=1', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/directory?limit=1', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1785,7 +1789,7 @@ class GServer
|
|||
*/
|
||||
private static function detectPeertube(string $url, array $serverdata): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/config', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/config', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBodyString() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1833,7 +1837,7 @@ class GServer
|
|||
*/
|
||||
private static function detectNextcloud(string $url, array $serverdata, bool $validHostMeta): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/status.php', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/status.php', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBodyString() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1869,7 +1873,7 @@ class GServer
|
|||
*/
|
||||
private static function fetchWeeklyUsage(string $url, array $serverdata): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/instance/activity', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/instance/activity', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBodyString() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1909,7 +1913,7 @@ class GServer
|
|||
*/
|
||||
private static function detectMastodonAlikes(string $url, array $serverdata): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/instance', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/v1/instance', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBodyString() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -1981,7 +1985,7 @@ class GServer
|
|||
*/
|
||||
private static function detectHubzilla(string $url, array $serverdata): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($url . '/api/statusnet/config.json', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/statusnet/config.json', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess() || ($curlResult->getBodyString() == '')) {
|
||||
return $serverdata;
|
||||
}
|
||||
|
@ -2078,7 +2082,7 @@ class GServer
|
|||
private static function detectGNUSocial(string $url, array $serverdata): array
|
||||
{
|
||||
// Test for GNU Social
|
||||
$curlResult = DI::httpClient()->get($url . '/api/gnusocial/version.json', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/gnusocial/version.json', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if ($curlResult->isSuccess() && ($curlResult->getBodyString() != '{"error":"not implemented"}') &&
|
||||
($curlResult->getBodyString() != '') && (strlen($curlResult->getBodyString()) < 30)) {
|
||||
$serverdata['platform'] = 'gnusocial';
|
||||
|
@ -2096,7 +2100,7 @@ class GServer
|
|||
}
|
||||
|
||||
// Test for Statusnet
|
||||
$curlResult = DI::httpClient()->get($url . '/api/statusnet/version.json', HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->get($url . '/api/statusnet/version.json', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if ($curlResult->isSuccess() && ($curlResult->getBodyString() != '{"error":"not implemented"}') &&
|
||||
($curlResult->getBodyString() != '') && (strlen($curlResult->getBodyString()) < 30)) {
|
||||
|
||||
|
@ -2134,9 +2138,9 @@ class GServer
|
|||
{
|
||||
// There is a bug in some versions of Friendica that will return an ActivityStream actor when the content type "application/json" is requested.
|
||||
// Because of this me must not use ACCEPT_JSON here.
|
||||
$curlResult = DI::httpClient()->get($url . '/friendica/json');
|
||||
$curlResult = DI::httpClient()->get($url . '/friendica/json', HttpClientAccept::DEFAULT, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
$curlResult = DI::httpClient()->get($url . '/friendika/json');
|
||||
$curlResult = DI::httpClient()->get($url . '/friendika/json', HttpClientAccept::DEFAULT, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$friendika = true;
|
||||
$platform = 'Friendika';
|
||||
} else {
|
||||
|
@ -2447,7 +2451,7 @@ class GServer
|
|||
$protocols = ['activitypub', 'diaspora', 'dfrn', 'ostatus'];
|
||||
foreach ($protocols as $protocol) {
|
||||
$query = '{nodes(protocol:"' . $protocol . '"){host}}';
|
||||
$curlResult = DI::httpClient()->fetch('https://the-federation.info/graphql?query=' . urlencode($query), HttpClientAccept::JSON);
|
||||
$curlResult = DI::httpClient()->fetch('https://the-federation.info/graphql?query=' . urlencode($query), HttpClientAccept::JSON, 0, '', HttpClientRequest::SERVERDISCOVER);
|
||||
if (!empty($curlResult)) {
|
||||
$data = json_decode($curlResult, true);
|
||||
if (!empty($data['data']['nodes'])) {
|
||||
|
@ -2464,7 +2468,7 @@ class GServer
|
|||
|
||||
if (!empty($accesstoken)) {
|
||||
$api = 'https://instances.social/api/1.0/instances/list?count=0';
|
||||
$curlResult = DI::httpClient()->get($api, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => ['Authorization' => ['Bearer ' . $accesstoken]]]);
|
||||
$curlResult = DI::httpClient()->get($api, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => ['Authorization' => ['Bearer ' . $accesstoken], HttpClientOptions::REQUEST => HttpClientRequest::SERVERDISCOVER]]);
|
||||
if ($curlResult->isSuccess()) {
|
||||
$servers = json_decode($curlResult->getBodyString(), true);
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ use Friendica\DI;
|
|||
use Friendica\Model\Post\Category;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Network\HTTPException\ServiceUnavailableException;
|
||||
use Friendica\Protocol\Activity;
|
||||
|
@ -108,7 +109,7 @@ class Item
|
|||
'owner-id', 'owner-link', 'owner-alias', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'owner-updated', 'owner-gsid',
|
||||
'causer-id', 'causer-link', 'causer-alias', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', 'causer-gsid',
|
||||
'contact-id', 'contact-uid', 'contact-link', 'contact-name', 'contact-avatar',
|
||||
'writable', 'self', 'cid', 'alias',
|
||||
'writable', 'restrictions', 'self', 'cid', 'alias', 'post-reason',
|
||||
'event-created', 'event-edited', 'event-start', 'event-finish',
|
||||
'event-summary', 'event-desc', 'event-location', 'event-type',
|
||||
'event-nofinish', 'event-ignore', 'event-id',
|
||||
|
@ -121,7 +122,7 @@ class Item
|
|||
const DELIVER_FIELDLIST = [
|
||||
'uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid',
|
||||
'parent-guid', 'conversation', 'received', 'created', 'edited', 'verb', 'object-type', 'object', 'target',
|
||||
'private', 'title', 'body', 'raw-body', 'language', 'location', 'coord', 'app', 'sensitive',
|
||||
'private', 'title', 'content-warning', 'body', 'raw-body', 'language', 'location', 'coord', 'app', 'sensitive',
|
||||
'inform', 'deleted', 'extid', 'post-type', 'post-reason', 'gravity',
|
||||
'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
|
||||
'author-id', 'author-addr', 'author-link', 'author-name', 'author-avatar', 'owner-id', 'owner-link', 'contact-uid',
|
||||
|
@ -168,6 +169,11 @@ class Item
|
|||
const GRAVITY_COMMENT = 6;
|
||||
const GRAVITY_UNKNOWN = 9;
|
||||
|
||||
// Restrictions
|
||||
const CANT_REPLY = 1;
|
||||
const CANT_LIKE = 2;
|
||||
const CANT_ANNOUNCE = 4;
|
||||
|
||||
/**
|
||||
* Update existing item entries
|
||||
*
|
||||
|
@ -759,7 +765,7 @@ class Item
|
|||
{
|
||||
$fields = [
|
||||
'uid', 'uri', 'parent-uri', 'id', 'deleted',
|
||||
'uri-id', 'parent-uri-id',
|
||||
'uri-id', 'parent-uri-id', 'restrictions', 'verb',
|
||||
'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
|
||||
'wall', 'private', 'origin', 'author-id'
|
||||
];
|
||||
|
@ -783,6 +789,11 @@ class Item
|
|||
return [];
|
||||
}
|
||||
|
||||
if (self::hasRestrictions($item, $parent['author-id'], $parent['restrictions'])) {
|
||||
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;
|
||||
}
|
||||
|
@ -838,7 +849,7 @@ class Item
|
|||
private static function prepareOriginPost(array $item): array
|
||||
{
|
||||
$item = DI::contentItem()->initializePost($item);
|
||||
$item = DI::contentItem()->finalizePost($item);
|
||||
$item = DI::contentItem()->finalizePost($item, false);
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
@ -1034,7 +1045,7 @@ class Item
|
|||
$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) {
|
||||
|
@ -1078,8 +1089,6 @@ class Item
|
|||
) {
|
||||
$item['object-type'] = Activity\ObjectType::IMAGE;
|
||||
}
|
||||
|
||||
$item = DI::contentItem()->moveAttachmentsFromBodyToAttach($item);
|
||||
}
|
||||
|
||||
$item['parent-uri-id'] = ItemURI::getIdByURI($item['parent-uri']);
|
||||
|
@ -1325,6 +1334,8 @@ class Item
|
|||
return 0;
|
||||
}
|
||||
|
||||
Post\Origin::insert($posted_item);
|
||||
|
||||
// update the commented timestamp on the parent
|
||||
if (DI::config()->get('system', 'like_no_comment')) {
|
||||
// Update when it is a comment
|
||||
|
@ -1439,6 +1450,27 @@ class Item
|
|||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!DI::config()->get('system', 'allow_relay_channels')) {
|
||||
|
@ -3315,7 +3347,6 @@ class Item
|
|||
$item['tags'] = $tags['tags'];
|
||||
$item['hashtags'] = $tags['hashtags'];
|
||||
$item['mentions'] = $tags['mentions'];
|
||||
$sensitive = $item['sensitive'] && !DI::pConfig()->get($uid, 'system', 'display_sensitive', false);
|
||||
|
||||
if (!$is_preview) {
|
||||
$item['body'] = preg_replace("#\s*\[attachment .*?].*?\[/attachment]\s*#ism", "\n", $item['body']);
|
||||
|
@ -3383,11 +3414,11 @@ class Item
|
|||
$shared_links = array_merge($shared_links, $sharedSplitAttachments['visual']->column('url'));
|
||||
$shared_links = array_merge($shared_links, $sharedSplitAttachments['link']->column('url'));
|
||||
$shared_links = array_merge($shared_links, $sharedSplitAttachments['additional']->column('url'));
|
||||
$item['body'] = self::replaceVisualAttachments($sharedSplitAttachments['visual'], $item['body'], $sensitive);
|
||||
$item['body'] = self::replaceVisualAttachments($sharedSplitAttachments['visual'], $item['body']);
|
||||
}
|
||||
|
||||
$itemSplitAttachments = DI::postMediaRepository()->splitAttachments($item['uri-id'], $shared_links, $item['has-media'] ?? false);
|
||||
$item['body'] = self::replaceVisualAttachments($itemSplitAttachments['visual'], $item['body'] ?? '', $sensitive);
|
||||
$item['body'] = self::replaceVisualAttachments($itemSplitAttachments['visual'], $item['body'] ?? '');
|
||||
|
||||
self::putInCache($item);
|
||||
$item['body'] = $body;
|
||||
|
@ -3408,8 +3439,8 @@ class Item
|
|||
$filter_reasons[] = DI::l10n()->t('Content from %s is collapsed', $item['author-name']);
|
||||
}
|
||||
|
||||
if (!empty($item['content-warning']) && (!$uid || !DI::pConfig()->get($uid, 'system', 'disable_cw', false))) {
|
||||
$filter_reasons[] = DI::l10n()->t('Content warning: %s', $item['content-warning']);
|
||||
if ($item['sensitive'] && (!$uid || !DI::pConfig()->get($uid, 'system', 'disable_cw', false))) {
|
||||
$filter_reasons[] = DI::l10n()->t('Sensitive content');
|
||||
}
|
||||
|
||||
$item['attachments'] = $itemSplitAttachments;
|
||||
|
@ -3442,9 +3473,9 @@ class Item
|
|||
}
|
||||
|
||||
if (!empty($sharedSplitAttachments)) {
|
||||
$s = self::addGallery($s, $sharedSplitAttachments['visual'], $sensitive);
|
||||
$s = self::addVisualAttachments($sharedSplitAttachments['visual'], $shared_item, $s, true, $sensitive);
|
||||
$s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $sharedSplitAttachments, $body, $s, true, $quote_shared_links, $sensitive);
|
||||
$s = self::addGallery($s, $sharedSplitAttachments['visual']);
|
||||
$s = self::addVisualAttachments($sharedSplitAttachments['visual'], $shared_item, $s, true);
|
||||
$s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $sharedSplitAttachments, $body, $s, true, $quote_shared_links);
|
||||
$s = self::addNonVisualAttachments($sharedSplitAttachments['additional'], $item, $s, true);
|
||||
$body = BBCode::removeSharedData($body);
|
||||
}
|
||||
|
@ -3455,9 +3486,9 @@ class Item
|
|||
$s = substr($s, 0, $pos);
|
||||
}
|
||||
|
||||
$s = self::addGallery($s, $itemSplitAttachments['visual'], $sensitive);
|
||||
$s = self::addVisualAttachments($itemSplitAttachments['visual'], $item, $s, false, $sensitive);
|
||||
$s = self::addLinkAttachment($item['uri-id'], $itemSplitAttachments, $body, $s, false, $shared_links, $sensitive);
|
||||
$s = self::addGallery($s, $itemSplitAttachments['visual']);
|
||||
$s = self::addVisualAttachments($itemSplitAttachments['visual'], $item, $s, false);
|
||||
$s = self::addLinkAttachment($item['uri-id'], $itemSplitAttachments, $body, $s, false, $shared_links);
|
||||
$s = self::addNonVisualAttachments($itemSplitAttachments['additional'], $item, $s, false);
|
||||
$s = self::addQuestions($item, $s);
|
||||
|
||||
|
@ -3491,10 +3522,9 @@ class Item
|
|||
*
|
||||
* @param string $s
|
||||
* @param PostMedias $PostMedias
|
||||
* @param bool $sensitive
|
||||
* @return string
|
||||
*/
|
||||
private static function addGallery(string $s, PostMedias $PostMedias, bool $sensitive): string
|
||||
private static function addGallery(string $s, PostMedias $PostMedias): string
|
||||
{
|
||||
foreach ($PostMedias as $PostMedia) {
|
||||
if (!$PostMedia->preview || ($PostMedia->type !== Post\Media::IMAGE)) {
|
||||
|
@ -3504,10 +3534,9 @@ class Item
|
|||
if ($PostMedia->hasDimensions()) {
|
||||
$pattern = '#<a href="' . preg_quote($PostMedia->url) . '">(.*?)"></a>#';
|
||||
|
||||
$s = preg_replace_callback($pattern, function () use ($PostMedia, $sensitive) {
|
||||
$s = preg_replace_callback($pattern, function () use ($PostMedia) {
|
||||
return Renderer::replaceMacros(Renderer::getMarkupTemplate('content/image/single_with_height_allocation.tpl'), [
|
||||
'$image' => $PostMedia,
|
||||
'$sensitive' => $sensitive,
|
||||
'$allocated_height' => $PostMedia->getAllocatedHeight(),
|
||||
'$allocated_max_width' => ($PostMedia->previewWidth ?? $PostMedia->width) . 'px',
|
||||
]);
|
||||
|
@ -3576,10 +3605,9 @@ class Item
|
|||
*
|
||||
* @param PostMedias $PostMedias
|
||||
* @param string $body
|
||||
* @param bool $sensitive
|
||||
* @return string modified body
|
||||
*/
|
||||
private static function replaceVisualAttachments(PostMedias $PostMedias, string $body, bool $sensitive): string
|
||||
private static function replaceVisualAttachments(PostMedias $PostMedias, string $body): string
|
||||
{
|
||||
DI::profiler()->startRecording('rendering');
|
||||
|
||||
|
@ -3588,7 +3616,7 @@ class Item
|
|||
if (DI::baseUrl()->isLocalUri($PostMedia->preview)) {
|
||||
continue;
|
||||
}
|
||||
$proxy = DI::baseUrl() . $PostMedia->getPreviewPath(Proxy::SIZE_LARGE, $sensitive);
|
||||
$proxy = DI::baseUrl() . $PostMedia->getPreviewPath(Proxy::SIZE_LARGE);
|
||||
$search = ['[img=' . $PostMedia->preview . ']', ']' . $PostMedia->preview . '[/img]'];
|
||||
$replace = ['[img=' . $proxy . ']', ']' . $proxy . '[/img]'];
|
||||
|
||||
|
@ -3597,7 +3625,7 @@ class Item
|
|||
if (DI::baseUrl()->isLocalUri($PostMedia->url)) {
|
||||
continue;
|
||||
}
|
||||
$proxy = DI::baseUrl() . $PostMedia->getPreviewPath(Proxy::SIZE_LARGE, $sensitive);
|
||||
$proxy = DI::baseUrl() . $PostMedia->getPreviewPath(Proxy::SIZE_LARGE);
|
||||
$search = ['[img=' . $PostMedia->url . ']', ']' . $PostMedia->url . '[/img]'];
|
||||
$replace = ['[img=' . $proxy . ']', ']' . $proxy . '[/img]'];
|
||||
|
||||
|
@ -3615,11 +3643,10 @@ class Item
|
|||
* @param array $item
|
||||
* @param string $content
|
||||
* @param bool $shared
|
||||
* @param bool $sensitive
|
||||
* @return string modified content
|
||||
* @throws ServiceUnavailableException
|
||||
*/
|
||||
private static function addVisualAttachments(PostMedias $PostMedias, array $item, string $content, bool $shared, bool $sensitive): string
|
||||
private static function addVisualAttachments(PostMedias $PostMedias, array $item, string $content, bool $shared): string
|
||||
{
|
||||
DI::profiler()->startRecording('rendering');
|
||||
$leading = '';
|
||||
|
@ -3634,7 +3661,7 @@ class Item
|
|||
|
||||
if ($PostMedia->mimetype->type == 'image' || $PostMedia->preview) {
|
||||
$preview_size = Proxy::SIZE_MEDIUM;
|
||||
$preview_url = DI::baseUrl() . $PostMedia->getPreviewPath($preview_size, $sensitive);
|
||||
$preview_url = DI::baseUrl() . $PostMedia->getPreviewPath($preview_size);
|
||||
} else {
|
||||
$preview_size = 0;
|
||||
$preview_url = '';
|
||||
|
@ -3655,13 +3682,14 @@ class Item
|
|||
/// @todo Move the template to /content as well
|
||||
$media = Renderer::replaceMacros(Renderer::getMarkupTemplate('video_top.tpl'), [
|
||||
'$video' => [
|
||||
'id' => $PostMedia->id,
|
||||
'src' => (string)$PostMedia->url,
|
||||
'name' => $PostMedia->name ?: $PostMedia->url,
|
||||
'preview' => $preview_url,
|
||||
'mime' => (string)$PostMedia->mimetype,
|
||||
'height' => $height,
|
||||
'width' => $width,
|
||||
'id' => $PostMedia->id,
|
||||
'src' => (string)$PostMedia->url,
|
||||
'name' => $PostMedia->name ?: $PostMedia->url,
|
||||
'preview' => $preview_url,
|
||||
'mime' => (string)$PostMedia->mimetype,
|
||||
'height' => $height,
|
||||
'width' => $width,
|
||||
'description' => $PostMedia->description,
|
||||
],
|
||||
]);
|
||||
if (($item['post-type'] ?? null) == Item::PT_VIDEO) {
|
||||
|
@ -3728,12 +3756,11 @@ class Item
|
|||
* @param string $content
|
||||
* @param bool $shared
|
||||
* @param array $ignore_links A list of URLs to ignore
|
||||
* @param bool $sensitive
|
||||
* @return string modified content
|
||||
* @throws InternalServerErrorException
|
||||
* @throws ServiceUnavailableException
|
||||
*/
|
||||
private static function addLinkAttachment(int $uriid, array $attachments, string $body, string $content, bool $shared, array $ignore_links, bool $sensitive): string
|
||||
private static function addLinkAttachment(int $uriid, array $attachments, string $body, string $content, bool $shared, array $ignore_links): string
|
||||
{
|
||||
DI::profiler()->startRecording('rendering');
|
||||
// Don't show a preview when there is a visual attachment (audio or video)
|
||||
|
@ -3776,9 +3803,9 @@ class Item
|
|||
|
||||
if ($preview && $attachment->preview) {
|
||||
if ($attachment->previewWidth >= 500) {
|
||||
$data['image'] = DI::baseUrl() . $attachment->getPreviewPath(Proxy::SIZE_MEDIUM, $sensitive);
|
||||
$data['image'] = DI::baseUrl() . $attachment->getPreviewPath(Proxy::SIZE_MEDIUM);
|
||||
} else {
|
||||
$data['preview'] = DI::baseUrl() . $attachment->getPreviewPath(Proxy::SIZE_MEDIUM, $sensitive);
|
||||
$data['preview'] = DI::baseUrl() . $attachment->getPreviewPath(Proxy::SIZE_MEDIUM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3803,11 +3830,6 @@ class Item
|
|||
$data = BBCode::getAttachmentData($match[1]);
|
||||
}
|
||||
|
||||
if ($sensitive) {
|
||||
$data['image'] = '';
|
||||
$data['preview'] = '';
|
||||
}
|
||||
|
||||
DI::profiler()->stopRecording();
|
||||
|
||||
if (isset($data['url']) && !in_array(strtolower($data['url']), $ignore_links)) {
|
||||
|
@ -3830,6 +3852,11 @@ class Item
|
|||
$preview_mode = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'preview_mode', BBCode::PREVIEW_LARGE);
|
||||
if ($preview_mode != BBCode::PREVIEW_NONE) {
|
||||
$rendered = BBCode::convertAttachment('', BBCode::INTERNAL, false, $data, $uriid, $preview_mode);
|
||||
} elseif (!self::containsLink($content, $data['url'], Post\Media::HTML)) {
|
||||
$rendered = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/link.tpl'), [
|
||||
'$url' => $data['url'],
|
||||
'$title' => $data['title'],
|
||||
]);
|
||||
} else {
|
||||
$rendered = '';
|
||||
}
|
||||
|
@ -3950,10 +3977,17 @@ class Item
|
|||
{
|
||||
if (!empty($item['plink']) && Network::isValidHttpUrl($item['plink'])) {
|
||||
$plink = $item['plink'];
|
||||
} elseif (!empty($item['uri']) && Network::isValidHttpUrl($item['uri']) && !Network::isLocalLink($item['uri'])) {
|
||||
} elseif (!empty($item['uri']) && Network::isValidHttpUrl($item['uri']) && !DI::baseUrl()->isLocalUrl($item['uri'])) {
|
||||
$plink = $item['uri'];
|
||||
}
|
||||
|
||||
if (($item['post-reason'] == self::PR_ANNOUNCEMENT) && ($item['owner-contact-type'] == Contact::TYPE_COMMUNITY) && ($item['owner-network'] == Protocol::DFRN)) {
|
||||
$contact = Contact::getById($item['owner-id'], ['baseurl']);
|
||||
if (!empty($contact['baseurl'])) {
|
||||
$plink = $contact['baseurl'] . '/display/' . $item['guid'];
|
||||
}
|
||||
}
|
||||
|
||||
if (DI::userSession()->getLocalUserId()) {
|
||||
$ret = [
|
||||
'href' => "display/" . $item['guid'],
|
||||
|
@ -4096,9 +4130,14 @@ class Item
|
|||
return is_numeric($hookData['item_id']) ? $hookData['item_id'] : 0;
|
||||
}
|
||||
|
||||
$curlResult = DI::httpClient()->head($uri, [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::JSON_AS]);
|
||||
if (HTTPSignature::isValidContentType($curlResult->getContentType(), $uri)) {
|
||||
$fetched_uri = ActivityPub\Processor::fetchMissingActivity($uri, [], '', $completion, $uid);
|
||||
try {
|
||||
$curlResult = DI::httpClient()->head($uri, [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::JSON_AS, HttpClientOptions::REQUEST => HttpClientRequest::ACTIVITYPUB]);
|
||||
if (HTTPSignature::isValidContentType($curlResult->getContentType(), $uri)) {
|
||||
$fetched_uri = ActivityPub\Processor::fetchMissingActivity($uri, [], '', $completion, $uid);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
Logger::info('Invalid link', ['uid' => $uid, 'uri' => $uri, 'code' => $th->getCode(), 'message' => $th->getMessage()]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!empty($fetched_uri)) {
|
||||
|
|
|
@ -32,6 +32,8 @@ use Friendica\Core\Storage\Exception\ReferenceStorageException;
|
|||
use Friendica\Core\Storage\Exception\StorageException;
|
||||
use Friendica\Core\Storage\Type\SystemResource;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Images;
|
||||
|
@ -234,7 +236,8 @@ class Photo
|
|||
FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?) $sqlExtra
|
||||
GROUP BY `resource-id` $sqlExtra2",
|
||||
$values
|
||||
));
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -549,7 +552,7 @@ class Photo
|
|||
// get photo to update
|
||||
$photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions);
|
||||
|
||||
foreach($photos as $photo) {
|
||||
foreach ($photos as $photo) {
|
||||
try {
|
||||
$backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? '');
|
||||
$fields['backend-ref'] = $backend_class->put($image->asString(), $photo['backend-ref']);
|
||||
|
@ -580,7 +583,9 @@ class Photo
|
|||
$micro = '';
|
||||
|
||||
$photo = DBA::selectFirst(
|
||||
'photo', ['resource-id'], ['uid' => $uid, 'contact-id' => $cid, 'scale' => 4, 'photo-type' => self::CONTACT_AVATAR]
|
||||
'photo',
|
||||
['resource-id'],
|
||||
['uid' => $uid, 'contact-id' => $cid, 'scale' => 4, 'photo-type' => self::CONTACT_AVATAR]
|
||||
);
|
||||
if (!empty($photo['resource-id'])) {
|
||||
$resource_id = $photo['resource-id'];
|
||||
|
@ -597,7 +602,7 @@ class Photo
|
|||
|
||||
$filename = basename($image_url);
|
||||
if (!empty($image_url)) {
|
||||
$ret = DI::httpClient()->get($image_url, HttpClientAccept::IMAGE);
|
||||
$ret = DI::httpClient()->get($image_url, HttpClientAccept::IMAGE, [HttpClientOptions::REQUEST => HttpClientRequest::MEDIAPROXY]);
|
||||
Logger::debug('Got picture', ['Content-Type' => $ret->getHeader('Content-Type'), 'url' => $image_url]);
|
||||
$img_str = $ret->getBodyString();
|
||||
$type = $ret->getContentType();
|
||||
|
@ -681,7 +686,9 @@ class Photo
|
|||
}
|
||||
|
||||
$photo = DBA::selectFirst(
|
||||
'photo', ['blurhash'], ['uid' => $uid, 'contact-id' => $cid, 'scale' => 4, 'photo-type' => self::CONTACT_AVATAR]
|
||||
'photo',
|
||||
['blurhash'],
|
||||
['uid' => $uid, 'contact-id' => $cid, 'scale' => 4, 'photo-type' => self::CONTACT_AVATAR]
|
||||
);
|
||||
|
||||
return [$image_url, $thumb, $micro, $photo['blurhash']];
|
||||
|
@ -751,7 +758,8 @@ class Photo
|
|||
if (!DI::config()->get('system', 'no_count', false)) {
|
||||
/// @todo This query needs to be renewed. It is really slow
|
||||
// At this time we just store the data in the cache
|
||||
$albums = DBA::toArray(DBA::p("SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`, MIN(`created`) AS `created`
|
||||
$albums = DBA::toArray(DBA::p(
|
||||
"SELECT COUNT(DISTINCT `resource-id`) AS `total`, `album`, MIN(`created`) AS `created`
|
||||
FROM `photo`
|
||||
WHERE `uid` = ? AND `photo-type` IN (?, ?, ?) $sql_extra
|
||||
GROUP BY `album` ORDER BY `created` DESC",
|
||||
|
@ -762,7 +770,8 @@ class Photo
|
|||
));
|
||||
} else {
|
||||
// This query doesn't do the count and is much faster
|
||||
$albums = DBA::toArray(DBA::p("SELECT '' AS `total`, `album`, MIN(`created`) AS `created`
|
||||
$albums = DBA::toArray(DBA::p(
|
||||
"SELECT '' AS `total`, `album`, MIN(`created`) AS `created`
|
||||
FROM `photo` USE INDEX (`uid_album_scale_created`)
|
||||
WHERE `uid` = ? AND `photo-type` IN (?, ?, ?) $sql_extra
|
||||
GROUP BY `album` ORDER BY `created` DESC",
|
||||
|
@ -902,9 +911,11 @@ class Photo
|
|||
*/
|
||||
public static function setPermissionForResource(string $image_rid, int $uid, string $str_contact_allow, string $str_circle_allow, string $str_contact_deny, string $str_circle_deny)
|
||||
{
|
||||
$fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_circle_allow,
|
||||
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_circle_deny,
|
||||
'accessible' => DI::pConfig()->get($uid, 'system', 'accessible-photos', false)];
|
||||
$fields = [
|
||||
'allow_cid' => $str_contact_allow, 'allow_gid' => $str_circle_allow,
|
||||
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_circle_deny,
|
||||
'accessible' => DI::pConfig()->get($uid, 'system', 'accessible-photos', false)
|
||||
];
|
||||
|
||||
$condition = ['resource-id' => $image_rid, 'uid' => $uid];
|
||||
Logger::info('Set permissions', ['condition' => $condition, 'permissions' => $fields]);
|
||||
|
@ -1046,7 +1057,7 @@ class Photo
|
|||
{
|
||||
$filename = basename($image_url);
|
||||
if (!empty($image_url)) {
|
||||
$ret = DI::httpClient()->get($image_url, HttpClientAccept::IMAGE);
|
||||
$ret = DI::httpClient()->get($image_url, HttpClientAccept::IMAGE, [HttpClientOptions::REQUEST => HttpClientRequest::MEDIAPROXY]);
|
||||
Logger::debug('Got picture', ['Content-Type' => $ret->getHeader('Content-Type'), 'url' => $image_url]);
|
||||
$img_str = $ret->getBodyString();
|
||||
$type = $ret->getContentType();
|
||||
|
|
|
@ -379,6 +379,21 @@ class Post
|
|||
return self::selectView('post-user-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-origin-view view
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
* @return boolean|object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function selectOrigin(array $selected = [], array $condition = [], array $params = [])
|
||||
{
|
||||
return self::selectView('post-origin-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-view view
|
||||
*
|
||||
|
@ -424,6 +439,21 @@ class Post
|
|||
return self::selectView('post-thread-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-thread-origin-view view
|
||||
*
|
||||
* @param array $selected Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
* @return boolean|object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function selectOriginThread(array $selected = [], array $condition = [], array $params = [])
|
||||
{
|
||||
return self::selectView('post-thread-origin-view', $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the given view for a given user
|
||||
*
|
||||
|
@ -513,6 +543,11 @@ class Post
|
|||
return self::selectViewForUser('post-timeline-view', $uid, $selected, $condition, $params);
|
||||
}
|
||||
|
||||
public static function selectLocalTimelineForUser(int $uid, array $selected = [], array $condition = [], array $params = [])
|
||||
{
|
||||
return self::selectViewForUser('post-timeline-origin-view', $uid, $selected, $condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select rows from the post-thread-user-view view for a given user
|
||||
*
|
||||
|
|
|
@ -418,4 +418,12 @@ class Engagement
|
|||
}
|
||||
return $fullTextSearch;
|
||||
}
|
||||
|
||||
public static function unescapeKeywords(string $fullTextSearch): string
|
||||
{
|
||||
foreach (self::KEYWORDS as $keyword) {
|
||||
$fullTextSearch = preg_replace('~(' . $keyword . ')_(.[\w\*@\.-]+)~', '$1:$2', $fullTextSearch);
|
||||
}
|
||||
return $fullTextSearch;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ use Friendica\Core\Protocol;
|
|||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Attach;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\ItemURI;
|
||||
|
@ -35,6 +36,7 @@ use Friendica\Model\Photo;
|
|||
use Friendica\Model\Post;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Protocol\ActivityPub;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Network;
|
||||
|
@ -180,14 +182,20 @@ class Media
|
|||
*/
|
||||
public static function fetchAdditionalData(array $media): array
|
||||
{
|
||||
if (Network::isLocalLink($media['url'])) {
|
||||
if (DI::baseUrl()->isLocalUrl($media['url'])) {
|
||||
$media = self::fetchLocalData($media);
|
||||
if (preg_match('|.*?/search\?(.+)|', $media['url'], $matches)) {
|
||||
return $media;
|
||||
}
|
||||
if (empty($media['mimetype']) || empty($media['size'])) {
|
||||
Logger::debug('Unknown local link', ['url' => $media['url']]);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the mimetype or size if missing.
|
||||
if (Network::isValidHttpUrl($media['url']) && (empty($media['mimetype']) || empty($media['size']))) {
|
||||
$timeout = DI::config()->get('system', 'xrd_timeout');
|
||||
$curlResult = DI::httpClient()->head($media['url'], [HttpClientOptions::TIMEOUT => $timeout]);
|
||||
$curlResult = DI::httpClient()->head($media['url'], [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::REQUEST => HttpClientRequest::CONTENTTYPE]);
|
||||
|
||||
// Workaround for systems that can't handle a HEAD request
|
||||
if (!$curlResult->isSuccess() && ($curlResult->getReturnCode() == 405)) {
|
||||
|
@ -389,7 +397,17 @@ class Media
|
|||
*/
|
||||
private static function fetchLocalData(array $media): array
|
||||
{
|
||||
if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['url'] ?? '', $matches)) {
|
||||
if (preg_match('|.*?/attach/(\d+)|', $media['url'], $matches)) {
|
||||
$attachment = Attach::selectFirst(['filename', 'filetype', 'filesize'], ['id' => $matches[1]]);
|
||||
if (!empty($attachment)) {
|
||||
$media['name'] = $attachment['filename'];
|
||||
$media['mimetype'] = $attachment['filetype'];
|
||||
$media['size'] = $attachment['filesize'];
|
||||
}
|
||||
return $media;
|
||||
}
|
||||
|
||||
if (!preg_match('|.*?/photo/(.*[a-fA-F0-9])\-(.*[0-9])\..*[\w]|', $media['url'], $matches)) {
|
||||
return $media;
|
||||
}
|
||||
$photo = Photo::selectFirst([], ['resource-id' => $matches[1], 'scale' => $matches[2]]);
|
||||
|
@ -902,19 +920,7 @@ class Media
|
|||
$body = BBCode::removeAttachment($body);
|
||||
|
||||
foreach (self::getByURIId($uriid, $types) as $media) {
|
||||
if (Item::containsLink($body, $media['preview'] ?? $media['url'], $media['type'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($media['type'] == self::IMAGE) {
|
||||
$body .= "\n" . Images::getBBCodeByUrl($media['url'], $media['preview'], $media['description'] ?? '');
|
||||
} elseif ($media['type'] == self::AUDIO) {
|
||||
$body .= "\n[audio]" . $media['url'] . "[/audio]\n";
|
||||
} elseif ($media['type'] == self::VIDEO) {
|
||||
$body .= "\n[video]" . $media['url'] . "[/video]\n";
|
||||
} else {
|
||||
$body .= "\n[url]" . $media['url'] . "[/url]\n";
|
||||
}
|
||||
$body = self::addAttachmentToBody($media, $body);
|
||||
}
|
||||
|
||||
if (preg_match("/.*(\[attachment.*?\].*?\[\/attachment\]).*/ism", $original_body, $match)) {
|
||||
|
@ -924,6 +930,24 @@ class Media
|
|||
return $body;
|
||||
}
|
||||
|
||||
public static function addAttachmentToBody(array $media, string $body): string
|
||||
{
|
||||
if (Item::containsLink($body, $media['preview'] ?? $media['url'], $media['type'])) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
if ($media['type'] == self::IMAGE) {
|
||||
$body .= "\n" . Images::getBBCodeByUrl($media['url'], $media['preview'], $media['description'] ?? '');
|
||||
} elseif ($media['type'] == self::AUDIO) {
|
||||
$body .= "\n[audio]" . $media['url'] . "[/audio]\n";
|
||||
} elseif ($media['type'] == self::VIDEO) {
|
||||
$body .= "\n[video]" . $media['url'] . "[/video]\n";
|
||||
} else {
|
||||
$body .= "\n[url]" . $media['url'] . "[/url]\n";
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an [attachment] element to the body for a given uri-id with a HTML media element
|
||||
*
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2024, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Model\Post;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use \BadMethodCallException;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\DI;
|
||||
|
||||
class Origin
|
||||
{
|
||||
/**
|
||||
* Insert a new post origin entry
|
||||
*
|
||||
* @param array $fields
|
||||
* @return boolean was the insert successful?
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function insert(array $data = []): bool
|
||||
{
|
||||
if (!$data['origin'] || ($data['uid'] == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fields = DI::dbaDefinition()->truncateFieldsForTable('post-origin', $data);
|
||||
|
||||
return DBA::insert('post-origin', $fields, Database::INSERT_IGNORE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a post origin entry
|
||||
*
|
||||
* @param integer $uri_id
|
||||
* @param integer $uid
|
||||
* @param array $data
|
||||
* @param bool $insert_if_missing
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function update(int $uri_id, int $uid, array $data = [], bool $insert_if_missing = false)
|
||||
{
|
||||
if (empty($uri_id)) {
|
||||
throw new BadMethodCallException('Empty URI_id');
|
||||
}
|
||||
|
||||
$fields = DI::dbaDefinition()->truncateFieldsForTable('post-origin', $data);
|
||||
|
||||
// Remove the key fields
|
||||
unset($fields['uri-id']);
|
||||
unset($fields['uid']);
|
||||
|
||||
if (empty($fields)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return DBA::update('post-origin', $fields, ['uri-id' => $uri_id, 'uid' => $uid], $insert_if_missing ? true : []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a row from the post-origin table
|
||||
*
|
||||
* @param array $conditions Field condition(s)
|
||||
* @param array $options
|
||||
* - cascade: If true we delete records in other tables that depend on the one we're deleting through
|
||||
* relations (default: true)
|
||||
*
|
||||
* @return boolean was the delete successful?
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function delete(array $conditions, array $options = [])
|
||||
{
|
||||
return DBA::delete('post-origin', $conditions, $options);
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ use Friendica\Database\DBA;
|
|||
use Friendica\DI;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Protocol\Activity;
|
||||
|
@ -296,7 +297,7 @@ class Profile
|
|||
if (DI::userSession()->getLocalUserId() && ($profile['uid'] ?? 0) != DI::userSession()->getLocalUserId()) {
|
||||
$profile_contact = Contact::getByURL($profile['nurl'], null, [], DI::userSession()->getLocalUserId());
|
||||
}
|
||||
if (!empty($profile['cid']) && self::getMyURL()) {
|
||||
if (!empty($profile['cid']) && DI::userSession()->getMyUrl()) {
|
||||
$profile_contact = Contact::selectFirst([], ['id' => $profile['cid']]);
|
||||
}
|
||||
|
||||
|
@ -321,19 +322,19 @@ class Profile
|
|||
|
||||
// Who is the logged-in user to this profile?
|
||||
$visitor_contact = [];
|
||||
if (!empty($profile['uid']) && self::getMyURL()) {
|
||||
$visitor_contact = Contact::selectFirst(['rel'], ['uid' => $profile['uid'], 'nurl' => Strings::normaliseLink(self::getMyURL())]);
|
||||
if (!empty($profile['uid']) && DI::userSession()->getMyUrl()) {
|
||||
$visitor_contact = Contact::selectFirst(['rel'], ['uid' => $profile['uid'], 'nurl' => Strings::normaliseLink(DI::userSession()->getMyUrl())]);
|
||||
}
|
||||
|
||||
$local_user_is_self = self::getMyURL() && ($profile['url'] == self::getMyURL());
|
||||
$visitor_is_authenticated = (bool)self::getMyURL();
|
||||
$local_user_is_self = DI::userSession()->getMyUrl() && ($profile['url'] == DI::userSession()->getMyUrl());
|
||||
$visitor_is_authenticated = (bool)DI::userSession()->getMyUrl();
|
||||
$visitor_is_following =
|
||||
in_array($visitor_contact['rel'] ?? 0, [Contact::FOLLOWER, Contact::FRIEND])
|
||||
|| in_array($profile_contact['rel'] ?? 0, [Contact::SHARING, Contact::FRIEND]);
|
||||
$visitor_is_followed =
|
||||
in_array($visitor_contact['rel'] ?? 0, [Contact::SHARING, Contact::FRIEND])
|
||||
|| in_array($profile_contact['rel'] ?? 0, [Contact::FOLLOWER, Contact::FRIEND]);
|
||||
$visitor_base_path = self::getMyURL() ? preg_replace('=/profile/(.*)=ism', '', self::getMyURL()) : '';
|
||||
$visitor_base_path = DI::userSession()->getMyUrl() ? preg_replace('=/profile/(.*)=ism', '', DI::userSession()->getMyUrl()) : '';
|
||||
|
||||
if (!$local_user_is_self) {
|
||||
if (!$visitor_is_authenticated) {
|
||||
|
@ -695,17 +696,6 @@ class Profile
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the my_url session variable
|
||||
*
|
||||
* @return string
|
||||
* @deprecated since version 2022.12, please use UserSession->getMyUrl instead
|
||||
*/
|
||||
public static function getMyURL(): string
|
||||
{
|
||||
return DI::userSession()->getMyUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the 'zrl' parameter and initiate the remote authentication.
|
||||
*
|
||||
|
@ -729,7 +719,7 @@ class Profile
|
|||
*/
|
||||
public static function zrlInit(App $a)
|
||||
{
|
||||
$my_url = self::getMyURL();
|
||||
$my_url = DI::userSession()->getMyUrl();
|
||||
$my_url = Network::isUrlValid($my_url);
|
||||
|
||||
if (empty($my_url) || DI::userSession()->getLocalUserId()) {
|
||||
|
@ -781,7 +771,7 @@ class Profile
|
|||
$magic_path = $basepath . '/magic' . '?owa=1&dest=' . $dest . '&' . $addr_request;
|
||||
|
||||
// We have to check if the remote server does understand /magic without invoking something
|
||||
$serverret = DI::httpClient()->head($basepath . '/magic', [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::HTML]);
|
||||
$serverret = DI::httpClient()->head($basepath . '/magic', [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::HTML, HttpClientOptions::REQUEST => HttpClientRequest::MAGICAUTH]);
|
||||
if ($serverret->isSuccess()) {
|
||||
Logger::info('Doing magic auth for visitor ' . $my_url . ' to ' . $magic_path);
|
||||
System::externalRedirect($magic_path);
|
||||
|
@ -915,7 +905,7 @@ class Profile
|
|||
}
|
||||
|
||||
$achar = strpos($url, '?') ? '&' : '?';
|
||||
$mine = self::getMyURL();
|
||||
$mine = DI::userSession()->getMyUrl();
|
||||
|
||||
if ($mine && !Strings::compareLink($mine, $url)) {
|
||||
return $url . $achar . 'zrl=' . urlencode($mine);
|
||||
|
|
|
@ -25,7 +25,7 @@ use Friendica\Core\Logger;
|
|||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Network;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
|
||||
class PushSubscriber
|
||||
{
|
||||
|
@ -179,7 +179,7 @@ class PushSubscriber
|
|||
|
||||
$parts = parse_url($subscriber['callback_url']);
|
||||
unset($parts['path']);
|
||||
$server_url = Network::unparseURL($parts);
|
||||
$server_url = (string)Uri::fromParts((array)$parts);
|
||||
$gsid = GServer::getID($server_url, true);
|
||||
if (!empty($gsid)) {
|
||||
GServer::setProtocol($gsid, Post\DeliveryData::OSTATUS);
|
||||
|
|
|
@ -25,6 +25,7 @@ use DivineOmega\DOFileCachePSR6\CacheItemPool;
|
|||
use DivineOmega\PasswordExposed;
|
||||
use ErrorException;
|
||||
use Exception;
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Pager;
|
||||
use Friendica\Core\Hook;
|
||||
use Friendica\Core\L10n;
|
||||
|
@ -37,6 +38,8 @@ use Friendica\Database\DBA;
|
|||
use Friendica\DI;
|
||||
use Friendica\Module;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Protocol\Delivery;
|
||||
|
@ -72,6 +75,7 @@ class User
|
|||
const PAGE_FLAGS_FREELOVE = 3;
|
||||
const PAGE_FLAGS_BLOG = 4;
|
||||
const PAGE_FLAGS_PRVGROUP = 5;
|
||||
const PAGE_FLAGS_COMM_MAN = 6;
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -161,6 +165,7 @@ class User
|
|||
}
|
||||
}
|
||||
|
||||
$system['name'] = App::PLATFORM . " '" . App::CODENAME . "' " . App::VERSION . '-' . DB_UPDATE_VERSION;
|
||||
$system['sprvkey'] = $system['uprvkey'] = $system['prvkey'];
|
||||
$system['spubkey'] = $system['upubkey'] = $system['pubkey'];
|
||||
$system['nickname'] = $system['nick'];
|
||||
|
@ -1397,7 +1402,7 @@ class User
|
|||
$photo_failure = false;
|
||||
|
||||
$filename = basename($photo);
|
||||
$curlResult = DI::httpClient()->get($photo, HttpClientAccept::IMAGE);
|
||||
$curlResult = DI::httpClient()->get($photo, HttpClientAccept::IMAGE, [HttpClientOptions::REQUEST => HttpClientRequest::CONTENTTYPE]);
|
||||
if ($curlResult->isSuccess()) {
|
||||
Logger::debug('Got picture', ['Content-Type' => $curlResult->getHeader('Content-Type'), 'url' => $photo]);
|
||||
$img_str = $curlResult->getBodyString();
|
||||
|
|
|
@ -77,6 +77,11 @@ class Inbox extends BaseApi
|
|||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
}
|
||||
|
||||
if (!HTTPSignature::isValidContentType($this->server['CONTENT_TYPE'] ?? '')) {
|
||||
Logger::notice('Unexpected content type', ['content-type' => $this->server['CONTENT_TYPE'] ?? '', 'agent' => $this->server['HTTP_USER_AGENT'] ?? '']);
|
||||
throw new \Friendica\Network\HTTPException\UnsupportedMediaTypeException();
|
||||
}
|
||||
|
||||
if (DI::config()->get('debug', 'ap_inbox_log')) {
|
||||
if (HTTPSignature::getSigner($postdata, $_SERVER)) {
|
||||
$filename = 'signed-activitypub';
|
||||
|
|
|
@ -51,7 +51,7 @@ class Whoami extends BaseApi
|
|||
$data['name'] = $owner['name'];
|
||||
$data['preferredUsername'] = $owner['nick'];
|
||||
$data['alsoKnownAs'] = [];
|
||||
$data['manuallyApprovesFollowers'] = in_array($owner['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP]);
|
||||
$data['manuallyApprovesFollowers'] = in_array($owner['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP, User::PAGE_FLAGS_COMM_MAN]);
|
||||
$data['discoverable'] = (bool)$owner['net-publish'];
|
||||
$data['tag'] = [];
|
||||
|
||||
|
|
|
@ -34,25 +34,24 @@ class Features extends BaseAdmin
|
|||
|
||||
self::checkFormSecurityTokenRedirectOnError('/admin/features', 'admin_manage_features');
|
||||
|
||||
$features = Feature::get(false);
|
||||
|
||||
foreach ($features as $fname => $fdata) {
|
||||
foreach (Feature::get(false) as $fdata) {
|
||||
foreach (array_slice($fdata, 1) as $f) {
|
||||
$feature = $f[0];
|
||||
$feature_state = 'feature_' . $feature;
|
||||
$featurelock = 'featurelock_' . $feature;
|
||||
switch ($_POST['featureselect_' . $feature]) {
|
||||
case 0:
|
||||
DI::config()->set('feature', $feature, false);
|
||||
DI::config()->delete('feature_lock', $feature);
|
||||
break;
|
||||
|
||||
if (!empty($_POST[$feature_state])) {
|
||||
$val = intval($_POST[$feature_state]);
|
||||
} else {
|
||||
$val = 0;
|
||||
}
|
||||
DI::config()->set('feature', $feature, $val);
|
||||
case 1:
|
||||
DI::config()->set('feature', $feature, true);
|
||||
DI::config()->delete('feature_lock', $feature);
|
||||
break;
|
||||
|
||||
if (!empty($_POST[$featurelock])) {
|
||||
DI::config()->set('feature_lock', $feature, 1);
|
||||
} else {
|
||||
DI::config()->delete('feature_lock', $feature);
|
||||
case 2:
|
||||
DI::config()->delete('feature', $feature);
|
||||
DI::config()->set('feature_lock', $feature, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,17 +63,15 @@ class Features extends BaseAdmin
|
|||
{
|
||||
parent::content();
|
||||
|
||||
$features = [];
|
||||
|
||||
$features = [];
|
||||
$selection = [DI::l10n()->t('No'), DI::l10n()->t('Yes'), DI::l10n()->t('Locked')];
|
||||
foreach (Feature::get(false) as $fname => $fdata) {
|
||||
$features[$fname] = [];
|
||||
$features[$fname][0] = $fdata[0];
|
||||
foreach (array_slice($fdata, 1) as $f) {
|
||||
$set = DI::config()->get('feature', $f[0], $f[3]);
|
||||
$features[$fname][1][] = [
|
||||
['feature_' . $f[0], $f[1], $set, $f[2]],
|
||||
['featurelock_' . $f[0], DI::l10n()->t('Lock feature %s', $f[1]), $f[4], '']
|
||||
];
|
||||
$selected = $f[4] ? 2 : (int)$set;
|
||||
$features[$fname][1][] = ['featureselect_' . $f[0], $f[1], $selected, $f[2], $selection];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -221,7 +221,6 @@ class Federation extends BaseAdmin
|
|||
'$page' => DI::l10n()->t('Federation Statistics'),
|
||||
'$intro' => $intro,
|
||||
'$counts' => $counts,
|
||||
'$version' => App::VERSION,
|
||||
'$legendtext' => DI::l10n()->tt('Currently this node is aware of %2$s node (%3$s active users last month, %4$s active users last six months, %5$s registered users in total) from the following platforms:', 'Currently this node is aware of %2$s nodes (%3$s active users last month, %4$s active users last six months, %5$s registered users in total) from the following platforms:', $total, number_format($total), number_format($month), number_format($halfyear), number_format($users)),
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -66,11 +66,14 @@ class Settings extends BaseAdmin
|
|||
parent::content();
|
||||
|
||||
$log_choices = [
|
||||
LogLevel::ERROR => 'Error',
|
||||
LogLevel::WARNING => 'Warning',
|
||||
LogLevel::NOTICE => 'Notice',
|
||||
LogLevel::INFO => 'Info',
|
||||
LogLevel::DEBUG => 'Debug',
|
||||
LogLevel::EMERGENCY => 'Emergency',
|
||||
LogLevel::ALERT => 'Alert',
|
||||
LogLevel::CRITICAL => 'Critical',
|
||||
LogLevel::ERROR => 'Error',
|
||||
LogLevel::WARNING => 'Warning',
|
||||
LogLevel::NOTICE => 'Notice',
|
||||
LogLevel::INFO => 'Info',
|
||||
LogLevel::DEBUG => 'Debug',
|
||||
];
|
||||
|
||||
if (ini_get('log_errors')) {
|
||||
|
|
|
@ -47,6 +47,8 @@ class View extends BaseAdmin
|
|||
$filters_valid_values = [
|
||||
'level' => [
|
||||
'',
|
||||
LogLevel::EMERGENCY,
|
||||
LogLevel::ALERT,
|
||||
LogLevel::CRITICAL,
|
||||
LogLevel::ERROR,
|
||||
LogLevel::WARNING,
|
||||
|
@ -54,7 +56,7 @@ class View extends BaseAdmin
|
|||
LogLevel::INFO,
|
||||
LogLevel::DEBUG,
|
||||
],
|
||||
'context' => ['', 'index', 'worker'],
|
||||
'context' => ['', 'index', 'worker', 'daemon'],
|
||||
];
|
||||
$filters = [
|
||||
'level' => $_GET['level'] ?? '',
|
||||
|
@ -71,10 +73,10 @@ class View extends BaseAdmin
|
|||
} else {
|
||||
try {
|
||||
$data = DI::parsedLogIterator()
|
||||
->open($f)
|
||||
->withLimit(self::LIMIT)
|
||||
->withFilters($filters)
|
||||
->withSearch($search);
|
||||
->open($f)
|
||||
->withLimit(self::LIMIT)
|
||||
->withFilters($filters)
|
||||
->withSearch($search);
|
||||
} catch (\Exception $e) {
|
||||
$error = DI::l10n()->t('Couldn\'t open <strong>%1$s</strong> log file.<br/>Check to see if file %1$s is readable.', $f);
|
||||
}
|
||||
|
|
|
@ -56,13 +56,14 @@ class Queue extends BaseAdmin
|
|||
}
|
||||
|
||||
// @TODO Move to Model\WorkerQueue::getEntries()
|
||||
$entries = DBA::select('workerqueue', ['id', 'parameter', 'created', 'priority', 'command'], $condition, ['limit' => 999, 'order' => ['created']]);
|
||||
$entries = DBA::select('workerqueue', ['id', 'parameter', 'created', 'next_try', 'priority', 'command'], $condition, ['limit' => 999, 'order' => ['created']]);
|
||||
|
||||
$r = [];
|
||||
while ($entry = DBA::fetch($entries)) {
|
||||
// fix GH-5469. ref: src/Core/Worker.php:217
|
||||
$entry['parameter'] = Arrays::recursiveImplode(json_decode($entry['parameter'], true), ': ');
|
||||
$entry['created'] = DateTimeFormat::local($entry['created']);
|
||||
$entry['next_try'] = DateTimeFormat::local($entry['next_try']);
|
||||
$r[] = $entry;
|
||||
}
|
||||
DBA::close($entries);
|
||||
|
@ -76,8 +77,10 @@ class Queue extends BaseAdmin
|
|||
'$command_header' => DI::l10n()->t('Command'),
|
||||
'$param_header' => DI::l10n()->t('Job Parameters'),
|
||||
'$created_header' => DI::l10n()->t('Created'),
|
||||
'$next_try_header' => DI::l10n()->t('Next Try'),
|
||||
'$prio_header' => DI::l10n()->t('Priority'),
|
||||
'$info' => $info,
|
||||
'$status' => $status,
|
||||
'$entries' => $r,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,6 @@ class Site extends BaseAdmin
|
|||
$adjust_poll_frequency = !empty($_POST['adjust_poll_frequency']);
|
||||
$min_poll_interval = (!empty($_POST['min_poll_interval']) ? intval(trim($_POST['min_poll_interval'])) : 0);
|
||||
$explicit_content = !empty($_POST['explicit_content']);
|
||||
$proxify_content = !empty($_POST['proxify_content']);
|
||||
$local_search = !empty($_POST['local_search']);
|
||||
$blocked_tags = (!empty($_POST['blocked_tags']) ? trim($_POST['blocked_tags']) : '');
|
||||
$cache_contact_avatar = !empty($_POST['cache_contact_avatar']);
|
||||
|
@ -271,7 +270,6 @@ class Site extends BaseAdmin
|
|||
$transactionConfig->set('system', 'adjust_poll_frequency' , $adjust_poll_frequency);
|
||||
$transactionConfig->set('system', 'min_poll_interval' , $min_poll_interval);
|
||||
$transactionConfig->set('system', 'explicit_content' , $explicit_content);
|
||||
$transactionConfig->set('system', 'proxify_content' , $proxify_content);
|
||||
$transactionConfig->set('system', 'local_search' , $local_search);
|
||||
$transactionConfig->set('system', 'blocked_tags' , Strings::cleanTags($blocked_tags));
|
||||
$transactionConfig->set('system', 'cache_contact_avatar' , $cache_contact_avatar);
|
||||
|
@ -518,7 +516,6 @@ class Site extends BaseAdmin
|
|||
'$private_addons' => ['private_addons', DI::l10n()->t('Disallow public access to addons listed in the apps menu.'), DI::config()->get('config', 'private_addons'), DI::l10n()->t('Checking this box will restrict addons listed in the apps menu to members only.')],
|
||||
'$disable_embedded' => ['disable_embedded', DI::l10n()->t('Don\'t embed private images in posts'), DI::config()->get('system', 'disable_embedded'), DI::l10n()->t('Don\'t replace locally-hosted private photos in posts with an embedded copy of the image. This means that contacts who receive posts containing private photos will have to authenticate and load each image, which may take a while.')],
|
||||
'$explicit_content' => ['explicit_content', DI::l10n()->t('Explicit Content'), DI::config()->get('system', 'explicit_content'), DI::l10n()->t('Set this to announce that your node is used mostly for explicit content that might not be suited for minors. This information will be published in the node information and might be used, e.g. by the global directory, to filter your node from listings of nodes to join. Additionally a note about this will be shown at the user registration page.')],
|
||||
'$proxify_content' => ['proxify_content', DI::l10n()->t('Proxify external content'), DI::config()->get('system', 'proxify_content'), DI::l10n()->t('Route external content via the proxy functionality. This is used for example for some OEmbed accesses and in some other rare cases.')],
|
||||
'$local_search' => ['local_search', DI::l10n()->t('Only local search'), DI::config()->get('system', 'local_search'), DI::l10n()->t('Blocks search for users who are not logged in to prevent crawlers from blocking your system.')],
|
||||
'$blocked_tags' => ['blocked_tags', DI::l10n()->t('Blocked tags for trending tags'), DI::config()->get('system', 'blocked_tags'), DI::l10n()->t("Comma separated list of hashtags that shouldn't be displayed in the trending tags.")],
|
||||
'$cache_contact_avatar' => ['cache_contact_avatar', DI::l10n()->t('Cache contact avatars'), DI::config()->get('system', 'cache_contact_avatar'), DI::l10n()->t('Locally store the avatar pictures of the contacts. This uses a lot of storage space but it increases the performance.')],
|
||||
|
|
|
@ -196,7 +196,7 @@ class Summary extends BaseAdmin
|
|||
'$title' => DI::l10n()->t('Administration'),
|
||||
'$page' => DI::l10n()->t('Summary'),
|
||||
'$queues' => $queues,
|
||||
'$version' => [DI::l10n()->t('Version'), App::VERSION],
|
||||
'$version_label' => DI::l10n()->t('Version'),
|
||||
'$platform' => App::PLATFORM,
|
||||
'$codename' => App::CODENAME,
|
||||
'$build' => DI::config()->get('system', 'build'),
|
||||
|
|
|
@ -47,7 +47,7 @@ class Config extends BaseApi
|
|||
'broughtby' => '',
|
||||
'broughtbyurl' => '',
|
||||
'timezone' => DI::config()->get('system', 'default_timezone'),
|
||||
'closed' => (DI::config()->get('config', 'register_policy') == Register::CLOSED),
|
||||
'closed' => Register::getPolicy() === Register::CLOSED,
|
||||
'inviteonly' => (bool)DI::config()->get('system', 'invitation_only'),
|
||||
'private' => (bool)DI::config()->get('system', 'block_public'),
|
||||
'textlimit' => (string) DI::config()->get('config', 'api_import_size', DI::config()->get('config', 'max_import_size')),
|
||||
|
|
|
@ -71,6 +71,7 @@ class UpdateCredentials extends BaseApi
|
|||
}
|
||||
|
||||
if ($user['account-type'] == Contact::TYPE_COMMUNITY) {
|
||||
// @todo Support for PAGE_FLAGS_COMM_MAN
|
||||
$user['page-flags'] = $request['locked'] ? User::PAGE_FLAGS_PRVGROUP : User::PAGE_FLAGS_COMMUNITY;
|
||||
} elseif ($user['account-type'] == Contact::TYPE_PERSON) {
|
||||
if ($request['locked']) {
|
||||
|
|
|
@ -26,7 +26,7 @@ use Friendica\Database\DBA;
|
|||
use Friendica\Model\GServer;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Network;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
|
||||
/**
|
||||
* Undocumented API endpoint that is implemented by both Mastodon and Pleroma
|
||||
|
@ -47,7 +47,7 @@ class Peers extends BaseApi
|
|||
while ($instance = DBA::fetch($instances)) {
|
||||
$urldata = parse_url($instance['url']);
|
||||
unset($urldata['scheme']);
|
||||
$return[] = ltrim(Network::unparseURL($urldata), '/');
|
||||
$return[] = ltrim((string)Uri::fromParts((array)$urldata), '/');
|
||||
}
|
||||
DBA::close($instances);
|
||||
|
||||
|
|
|
@ -166,9 +166,9 @@ class InstanceV2 extends BaseApi
|
|||
|
||||
private function buildRegistrationsInfo(): InstanceEntity\Registrations
|
||||
{
|
||||
$register_policy = intval($this->config->get('config', 'register_policy'));
|
||||
$enabled = ($register_policy != Register::CLOSED);
|
||||
$approval_required = ($register_policy == Register::APPROVE);
|
||||
$register_policy = Register::getPolicy();
|
||||
$enabled = $register_policy !== Register::CLOSED;
|
||||
$approval_required = $register_policy === Register::APPROVE;
|
||||
|
||||
return new InstanceEntity\Registrations($enabled, $approval_required);
|
||||
}
|
||||
|
|
|
@ -21,16 +21,36 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\DI;
|
||||
use Friendica\Content\Conversation\Factory\Channel as ChannelFactory;
|
||||
use Friendica\Content\Conversation\Repository;
|
||||
use Friendica\Content\GroupManager;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Model\Circle;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/timelines/lists/
|
||||
*/
|
||||
class Lists extends BaseApi
|
||||
{
|
||||
/** @var ChannelFactory */
|
||||
protected $channel;
|
||||
/** @var Repository\UserDefinedChannel */
|
||||
protected $userDefinedChannel;
|
||||
|
||||
public function __construct(Repository\UserDefinedChannel $userDefinedChannel, ChannelFactory $channel, \Friendica\Factory\Api\Mastodon\Error $errorFactory, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($errorFactory, $app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->channel = $channel;
|
||||
$this->userDefinedChannel = $userDefinedChannel;
|
||||
}
|
||||
|
||||
protected function delete(array $request = [])
|
||||
{
|
||||
$this->checkAllowedScope(self::SCOPE_WRITE);
|
||||
|
@ -102,6 +122,18 @@ class Lists extends BaseApi
|
|||
foreach (Circle::getByUserId($uid) as $circle) {
|
||||
$lists[] = DI::mstdnList()->createFromCircleId($circle['id']);
|
||||
}
|
||||
|
||||
foreach ($this->channel->getTimelines($uid) as $channel) {
|
||||
$lists[] = DI::mstdnList()->createFromChannel($channel);
|
||||
}
|
||||
|
||||
foreach ($this->userDefinedChannel->selectByUid($uid) as $channel) {
|
||||
$lists[] = DI::mstdnList()->createFromChannel($channel);
|
||||
}
|
||||
|
||||
foreach (GroupManager::getList($uid, true, true, true) as $group) {
|
||||
$lists[] = DI::mstdnList()->createFromGroup($group);
|
||||
}
|
||||
} else {
|
||||
$id = $this->parameters['id'];
|
||||
|
||||
|
|
|
@ -83,6 +83,10 @@ class Statuses extends BaseApi
|
|||
$item['network'] = $post['network'];
|
||||
$item['gravity'] = $post['gravity'];
|
||||
$item['verb'] = $post['verb'];
|
||||
$item['allow_cid'] = $post['allow_cid'];
|
||||
$item['allow_gid'] = $post['allow_gid'];
|
||||
$item['deny_cid'] = $post['deny_cid'];
|
||||
$item['deny_gid'] = $post['deny_gid'];
|
||||
$item['app'] = $this->getApp();
|
||||
$item['sensitive'] = $request['sensitive'];
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon\Statuses;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
|
@ -54,7 +53,7 @@ class Bookmark extends BaseApi
|
|||
if ($item['uid'] == 0) {
|
||||
$stored = Item::storeForUserByUriId($item['uri-id'], $uid, ['post-reason' => Item::PR_ACTIVITY]);
|
||||
if (!empty($stored)) {
|
||||
$item = Post::selectFirst(['id', 'gravity'], ['id' => $stored]);
|
||||
$item = Post::selectFirst(['id', 'uri-id', 'gravity'], ['id' => $stored]);
|
||||
if (!DBA::isResult($item)) {
|
||||
$this->logAndJsonError(404, $this->errorFactory->RecordNotFound());
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class Reblog extends BaseApi
|
|||
|
||||
if ($item['network'] == Protocol::DIASPORA) {
|
||||
Diaspora::performReshare($this->parameters['id'], $uid);
|
||||
} elseif (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) {
|
||||
} elseif (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::BLUESKY, Protocol::TUMBLR, Protocol::TWITTER])) {
|
||||
$this->logAndJsonError(
|
||||
422,
|
||||
$this->errorFactory->UnprocessableEntity($this->t("Posts from %s can't be shared", ContactSelector::networkToName($item['network'])))
|
||||
|
|
|
@ -58,7 +58,7 @@ class Unreblog extends BaseApi
|
|||
if (!Item::markForDeletionById($item['id'])) {
|
||||
$this->logAndJsonError(404, $this->errorFactory->RecordNotFound());
|
||||
}
|
||||
} elseif (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::TWITTER])) {
|
||||
} elseif (!in_array($item['network'], [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::BLUESKY, Protocol::TUMBLR, Protocol::TWITTER])) {
|
||||
$this->logAndJsonError(
|
||||
422,
|
||||
$this->errorFactory->UnprocessableEntity($this->t("Posts from %s can't be unshared", ContactSelector::networkToName($item['network'])))
|
||||
|
|
|
@ -21,21 +21,39 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon\Timelines;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Conversation;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Verb;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Module\Conversation\Timeline;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Object\Api\Mastodon\TimelineOrderByTypes;
|
||||
use Friendica\Protocol\Activity;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/timelines/
|
||||
*/
|
||||
class ListTimeline extends BaseApi
|
||||
{
|
||||
/** @var Timeline */
|
||||
protected $timeline;
|
||||
|
||||
public function __construct(Timeline $timeline, \Friendica\Factory\Api\Mastodon\Error $errorFactory, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($errorFactory, $app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
$this->timeline = $timeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
|
@ -61,6 +79,70 @@ class ListTimeline extends BaseApi
|
|||
'friendica_order' => TimelineOrderByTypes::ID, // Sort order options (defaults to ID)
|
||||
], $request);
|
||||
|
||||
$display_quotes = self::appSupportsQuotes();
|
||||
|
||||
if (substr($this->parameters['id'], 0, 6) == 'group:') {
|
||||
$items = $this->getStatusesForGroup($uid, $request);
|
||||
} elseif (substr($this->parameters['id'], 0, 8) == 'channel:') {
|
||||
$items = $this->getStatusesForChannel($uid, $request);
|
||||
} else{
|
||||
$items = $this->getStatusesForCircle($uid, $request);
|
||||
}
|
||||
|
||||
$statuses = [];
|
||||
foreach ($items as $item) {
|
||||
try {
|
||||
$status = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||
$this->updateBoundaries($status, $item, $request['friendica_order']);
|
||||
$statuses[] = $status;
|
||||
} catch (\Throwable $th) {
|
||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($request['min_id'])) {
|
||||
$statuses = array_reverse($statuses);
|
||||
}
|
||||
|
||||
self::setLinkHeader($request['friendica_order'] != TimelineOrderByTypes::ID);
|
||||
$this->jsonExit($statuses);
|
||||
}
|
||||
|
||||
private function getStatusesForGroup(int $uid, array $request): array
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID((int)substr($this->parameters['id'], 6), $uid);
|
||||
$cid = $cdata['public'];
|
||||
|
||||
$condition = ["(`uid` = ? OR (`uid` = ? AND NOT `global`))", 0, $uid];
|
||||
|
||||
$condition1 = DBA::mergeConditions($condition, ["`owner-id` = ? AND `gravity` = ?", $cid, Item::GRAVITY_PARENT]);
|
||||
|
||||
$condition2 = DBA::mergeConditions($condition, [
|
||||
"`author-id` = ? AND `gravity` = ? AND `vid` = ? AND `protocol` != ? AND `thr-parent-id` = `parent-uri-id`",
|
||||
$cid, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), Conversation::PARCEL_DIASPORA
|
||||
]);
|
||||
|
||||
$condition1 = $this->addPagingConditions($request, $condition1);
|
||||
$condition2 = $this->addPagingConditions($request, $condition2);
|
||||
|
||||
$sql1 = "SELECT `uri-id` FROM `post-thread-user-view` WHERE " . array_shift($condition1);
|
||||
$sql2 = "SELECT `thr-parent-id` AS `uri-id` FROM `post-user-view` WHERE " . array_shift($condition2);
|
||||
|
||||
$condition = array_merge($condition1, $condition2);
|
||||
$sql = $sql1 . " UNION " . $sql2 . " GROUP BY `uri-id` " . DBA::buildParameter($this->buildOrderAndLimitParams($request));
|
||||
|
||||
return Post::toArray(DBA::p($sql, $condition));
|
||||
}
|
||||
|
||||
private function getStatusesForChannel(int $uid, array $request): array
|
||||
{
|
||||
$request['friendica_order'] = TimelineOrderByTypes::ID;
|
||||
|
||||
return $this->timeline->getChannelItemsForAPI(substr($this->parameters['id'], 8), $uid, $request['limit'], $request['min_id'], $request['max_id']);
|
||||
}
|
||||
|
||||
private function getStatusesForCircle(int $uid, array $request): array
|
||||
{
|
||||
$condition = [
|
||||
"`uid` = ? AND `gravity` IN (?, ?) AND `contact-id` IN (SELECT `contact-id` FROM `group_member` WHERE `gid` = ?)",
|
||||
$uid, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, $this->parameters['id']
|
||||
|
@ -89,26 +171,6 @@ class ListTimeline extends BaseApi
|
|||
}
|
||||
|
||||
$items = Post::selectTimelineForUser($uid, ['uri-id'], $condition, $params);
|
||||
|
||||
$display_quotes = self::appSupportsQuotes();
|
||||
|
||||
$statuses = [];
|
||||
while ($item = Post::fetch($items)) {
|
||||
try {
|
||||
$status = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
|
||||
$this->updateBoundaries($status, $item, $request['friendica_order']);
|
||||
$statuses[] = $status;
|
||||
} catch (\Throwable $th) {
|
||||
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]);
|
||||
}
|
||||
}
|
||||
DBA::close($items);
|
||||
|
||||
if (!empty($request['min_id'])) {
|
||||
$statuses = array_reverse($statuses);
|
||||
}
|
||||
|
||||
self::setLinkHeader($request['friendica_order'] != TimelineOrderByTypes::ID);
|
||||
$this->jsonExit($statuses);
|
||||
return Post::toArray($items);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,11 @@ class PublicTimeline extends BaseApi
|
|||
$condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
|
||||
}
|
||||
|
||||
$items = Post::selectTimelineForUser($uid, ['uri-id'], $condition, $params);
|
||||
if ($request['local']) {
|
||||
$items = Post::selectLocalTimelineForUser($uid, ['uri-id'], $condition, $params);
|
||||
} else {
|
||||
$items = Post::selectTimelineForUser($uid, ['uri-id'], $condition, $params);
|
||||
}
|
||||
|
||||
$display_quotes = self::appSupportsQuotes();
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ class Retweet extends BaseApi
|
|||
$item = Post::selectFirst($fields, ['uri-id' => $id, 'uid' => [0, $uid], 'private' => [Item::PUBLIC, Item::UNLISTED]], ['order' => ['uid' => true]]);
|
||||
|
||||
if (DBA::isResult($item) && !empty($item['body'])) {
|
||||
if (in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::TWITTER])) {
|
||||
if (in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::BLUESKY, Protocol::TUMBLR, Protocol::TWITTER])) {
|
||||
if (!Item::performActivity($id, 'announce', $uid)) {
|
||||
throw new InternalServerErrorException();
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ abstract class BaseAdmin extends BaseModule
|
|||
}
|
||||
}
|
||||
|
||||
if (!DI::app()->isSiteAdmin()) {
|
||||
if (!DI::userSession()->isSiteAdmin()) {
|
||||
throw new HTTPException\ForbiddenException(DI::l10n()->t('You don\'t have access to administration pages.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ class BaseProfile extends BaseModule
|
|||
];
|
||||
} else {
|
||||
$owner = User::getByNickname($nickname, ['uid']);
|
||||
if(DI::userSession()->isAuthenticated() || $owner && Feature::isEnabled($owner['uid'], 'public_calendar')) {
|
||||
if(DI::userSession()->isAuthenticated() || $owner && Feature::isEnabled($owner['uid'], Feature::PUBLIC_CALENDAR)) {
|
||||
$tabs[] = [
|
||||
'label' => DI::l10n()->t('Calendar'),
|
||||
'url' => DI::baseUrl() . '/calendar/show/' . $nickname,
|
||||
|
|
|
@ -42,7 +42,7 @@ class Bookmarklet extends BaseModule
|
|||
|
||||
if (!DI::userSession()->getLocalUserId()) {
|
||||
$output = '<h2>' . DI::l10n()->t('Login') . '</h2>';
|
||||
$output .= Login::form(DI::args()->getQueryString(), intval($config->get('config', 'register_policy')) === Register::CLOSED ? false : true);
|
||||
$output .= Login::form(DI::args()->getQueryString(), Register::getPolicy() !== Register::CLOSED);
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,14 +22,11 @@
|
|||
namespace Friendica\Module\Calendar\Event;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Content\Feature;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Model\Event;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
@ -46,17 +43,16 @@ class Get extends \Friendica\BaseModule
|
|||
/** @var IHandleUserSessions */
|
||||
protected $session;
|
||||
|
||||
public function __construct(App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, array $server, array $parameters = [])
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->session = $session;
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$nickname = $this->parameters['nickname'] ?? $this->app->getLoggedInUserNickname();
|
||||
$nickname = $this->parameters['nickname'] ?? $this->session->getLocalUserNickname();
|
||||
if (!$nickname) {
|
||||
throw new HTTPException\UnauthorizedException();
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ class Show extends BaseModule
|
|||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$nickname = $this->parameters['nickname'] ?? $this->app->getLoggedInUserNickname();
|
||||
$nickname = $this->parameters['nickname'] ?? $this->session->getLocalUserNickname();
|
||||
if (!$nickname) {
|
||||
throw new HTTPException\UnauthorizedException();
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ class Export extends BaseModule
|
|||
$this->baseUrl->redirect('profile/' . $nickname . '/restricted');
|
||||
}
|
||||
|
||||
if (!$this->session->isAuthenticated() && !Feature::isEnabled($owner['uid'], 'public_calendar')) {
|
||||
if (!$this->session->isAuthenticated() && !Feature::isEnabled($owner['uid'], Feature::PUBLIC_CALENDAR)) {
|
||||
$this->sysMessages->addNotice($this->t('Permission denied.'));
|
||||
$this->baseUrl->redirect('profile/' . $nickname);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ class Show extends BaseModule
|
|||
$this->baseUrl->redirect('profile/' . $nickname . '/restricted');
|
||||
}
|
||||
|
||||
if (!$this->session->isAuthenticated() && !Feature::isEnabled($owner['uid'], 'public_calendar')) {
|
||||
if (!$this->session->isAuthenticated() && !Feature::isEnabled($owner['uid'], Feature::PUBLIC_CALENDAR)) {
|
||||
$this->sysMessages->addNotice($this->t('Permission denied.'));
|
||||
return Login::form();
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ class Show extends BaseModule
|
|||
$this->page->registerFooterScript('view/asset/moment/min/moment-with-locales.min.js');
|
||||
$this->page->registerFooterScript('view/asset/fullcalendar/dist/fullcalendar.min.js');
|
||||
|
||||
$is_owner = $nickname == $this->app->getLoggedInUserNickname();
|
||||
$is_owner = $nickname == $this->session->getLocalUserNickname();
|
||||
|
||||
$htpl = Renderer::getMarkupTemplate('calendar/calendar_head.tpl');
|
||||
$this->page['htmlhead'] .= Renderer::replaceMacros($htpl, [
|
||||
|
|
|
@ -141,13 +141,15 @@ class Circle extends BaseModule
|
|||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
$change = false;
|
||||
$change = false;
|
||||
$relation = $request['rel'] ?? '';
|
||||
|
||||
if (!DI::userSession()->getLocalUserId()) {
|
||||
throw new \Friendica\Network\HTTPException\ForbiddenException();
|
||||
}
|
||||
|
||||
DI::page()['aside'] = Model\Circle::sidebarWidget('contact', 'circle', 'extended', ((DI::args()->getArgc() > 1) ? DI::args()->getArgv()[1] : 'everyone'));
|
||||
DI::page()['aside'] .= Widget::contactRels($this->server['REQUEST_URI'], $relation);
|
||||
|
||||
// With no circle number provided we jump to the unassigned contacts as a starting point
|
||||
// @TODO: Replace with parameter from router
|
||||
|
@ -298,6 +300,9 @@ class Circle extends BaseModule
|
|||
|
||||
// Format the data of the circle members
|
||||
foreach ($members as $member) {
|
||||
if (!self::matchRelation($relation, $member['rel'])) {
|
||||
continue;
|
||||
}
|
||||
if ($member['url']) {
|
||||
$entry = Contact::getContactTemplateVars($member);
|
||||
$entry['label'] = 'members';
|
||||
|
@ -332,6 +337,9 @@ class Circle extends BaseModule
|
|||
if (DBA::isResult($contacts)) {
|
||||
// Format the data of the contacts who aren't in the contact circle
|
||||
foreach ($contacts as $member) {
|
||||
if (!self::matchRelation($relation, $member['rel'])) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array($member['id'], $preselected)) {
|
||||
$entry = Contact::getContactTemplateVars($member);
|
||||
$entry['label'] = 'contacts';
|
||||
|
@ -366,4 +374,19 @@ class Circle extends BaseModule
|
|||
|
||||
return Renderer::replaceMacros($tpl, $context);
|
||||
}
|
||||
|
||||
private static function matchRelation(string $relation, int $rel)
|
||||
{
|
||||
switch ($relation) {
|
||||
case 'followers':
|
||||
return($rel == Model\Contact::FOLLOWER);
|
||||
case 'following':
|
||||
return($rel == Model\Contact::SHARING);
|
||||
case 'mutuals':
|
||||
return($rel == Model\Contact::FRIEND);
|
||||
case 'nothing':
|
||||
return($rel == Model\Contact::NOTHING);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ class Follow extends BaseModule
|
|||
$this->page['aside'] = '';
|
||||
|
||||
if (!in_array($protocol, [Protocol::PHANTOM, Protocol::MAIL])) {
|
||||
$this->page['aside'] = VCard::getHTML($contact);
|
||||
$this->page['aside'] = VCard::getHTML($contact, false, true);
|
||||
|
||||
$output .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'),
|
||||
['$title' => $this->t('Posts and Replies')]
|
||||
|
|
|
@ -37,6 +37,7 @@ use Friendica\Module\Contact as ModuleContact;
|
|||
use Friendica\Module\Response;
|
||||
use Friendica\Navigation\SystemMessages;
|
||||
use Friendica\Network\HTTPClient\Capability\ICanSendHttpRequests;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
@ -122,10 +123,10 @@ class MatchInterests extends BaseModule
|
|||
continue;
|
||||
}
|
||||
|
||||
$result = $this->httpClient->post($server . '/search/user/tags', $searchParameters);
|
||||
$result = $this->httpClient->post($server . '/search/user/tags', $searchParameters, [], 0, HttpClientRequest::CONTACTDISCOVER);
|
||||
if (!$result->isSuccess()) {
|
||||
// try legacy endpoint
|
||||
$result = $this->httpClient->post($server . '/msearch', $searchParameters);
|
||||
$result = $this->httpClient->post($server . '/msearch', $searchParameters, [], 0, HttpClientRequest::CONTACTDISCOVER);
|
||||
if (!$result->isSuccess()) {
|
||||
$this->logger->notice('Search-Endpoint not available for server.', ['server' => $server]);
|
||||
continue;
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Friendica\Module\Contact;
|
|||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Contact\LocalRelationship;
|
||||
use Friendica\Contact\LocalRelationship\Entity\LocalRelationship as LocalRelationshipEntity;
|
||||
use Friendica\Content\ContactSelector;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
|
@ -95,32 +96,32 @@ class Profile extends BaseModule
|
|||
return;
|
||||
}
|
||||
|
||||
Hook::callAll('contact_edit_post', $_POST);
|
||||
Hook::callAll('contact_edit_post', $request);
|
||||
|
||||
$fields = [];
|
||||
|
||||
if (isset($_POST['hidden'])) {
|
||||
$fields['hidden'] = !empty($_POST['hidden']);
|
||||
if (isset($request['hidden'])) {
|
||||
$fields['hidden'] = !empty($request['hidden']);
|
||||
}
|
||||
|
||||
if (isset($_POST['notify_new_posts'])) {
|
||||
$fields['notify_new_posts'] = !empty($_POST['notify_new_posts']);
|
||||
if (isset($request['notify_new_posts'])) {
|
||||
$fields['notify_new_posts'] = !empty($request['notify_new_posts']);
|
||||
}
|
||||
|
||||
if (isset($_POST['fetch_further_information'])) {
|
||||
$fields['fetch_further_information'] = intval($_POST['fetch_further_information']);
|
||||
if (isset($request['fetch_further_information'])) {
|
||||
$fields['fetch_further_information'] = intval($request['fetch_further_information']);
|
||||
}
|
||||
|
||||
if (isset($_POST['remote_self'])) {
|
||||
$fields['remote_self'] = intval($_POST['remote_self']);
|
||||
if (isset($request['remote_self'])) {
|
||||
$fields['remote_self'] = intval($request['remote_self']);
|
||||
}
|
||||
|
||||
if (isset($_POST['ffi_keyword_denylist'])) {
|
||||
$fields['ffi_keyword_denylist'] = $_POST['ffi_keyword_denylist'];
|
||||
if (isset($request['ffi_keyword_denylist'])) {
|
||||
$fields['ffi_keyword_denylist'] = $request['ffi_keyword_denylist'];
|
||||
}
|
||||
|
||||
if (isset($_POST['poll'])) {
|
||||
$priority = intval($_POST['poll']);
|
||||
if (isset($request['poll'])) {
|
||||
$priority = intval($request['poll']);
|
||||
if ($priority > 5 || $priority < 0) {
|
||||
$priority = 0;
|
||||
}
|
||||
|
@ -128,12 +129,16 @@ class Profile extends BaseModule
|
|||
$fields['priority'] = $priority;
|
||||
}
|
||||
|
||||
if (isset($_POST['info'])) {
|
||||
$fields['info'] = $_POST['info'];
|
||||
if (isset($request['info'])) {
|
||||
$fields['info'] = $request['info'];
|
||||
}
|
||||
|
||||
if (isset($_POST['channel_frequency'])) {
|
||||
Contact\User::setChannelFrequency($cdata['user'], $this->session->getLocalUserId(), $_POST['channel_frequency']);
|
||||
if (isset($request['channel_frequency'])) {
|
||||
Contact\User::setChannelFrequency($cdata['user'], $this->session->getLocalUserId(), $request['channel_frequency']);
|
||||
}
|
||||
|
||||
if (isset($request['channel_only'])) {
|
||||
Contact\User::setChannelOnly($cdata['user'], $this->session->getLocalUserId(), $request['channel_only']);
|
||||
}
|
||||
|
||||
if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => $this->session->getLocalUserId()])) {
|
||||
|
@ -319,28 +324,29 @@ class Profile extends BaseModule
|
|||
|
||||
if ($contact['network'] == Protocol::FEED) {
|
||||
$remote_self_options = [
|
||||
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting')
|
||||
LocalRelationshipEntity::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
LocalRelationshipEntity::MIRROR_OWN_POST => $this->t('Mirror as my own posting')
|
||||
];
|
||||
} elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
|
||||
$remote_self_options = [
|
||||
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
|
||||
LocalRelationshipEntity::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
LocalRelationshipEntity::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
|
||||
];
|
||||
} elseif ($contact['network'] == Protocol::DFRN) {
|
||||
$remote_self_options = [
|
||||
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting'),
|
||||
Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
|
||||
LocalRelationshipEntity::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
LocalRelationshipEntity::MIRROR_OWN_POST => $this->t('Mirror as my own posting'),
|
||||
LocalRelationshipEntity::MIRROR_NATIVE_RESHARE => $this->t('Native reshare')
|
||||
];
|
||||
} else {
|
||||
$remote_self_options = [
|
||||
Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting')
|
||||
LocalRelationshipEntity::MIRROR_DEACTIVATED => $this->t('No mirroring'),
|
||||
LocalRelationshipEntity::MIRROR_OWN_POST => $this->t('Mirror as my own posting')
|
||||
];
|
||||
}
|
||||
|
||||
$channel_frequency = Contact\User::getChannelFrequency($contact['id'], $this->session->getLocalUserId());
|
||||
$channel_frequency = Contact\User::getChannelFrequency($contact['id'], $this->session->getLocalUserId());
|
||||
$channel_only = Contact\User::getChannelOnly($contact['id'], $this->session->getLocalUserId());
|
||||
|
||||
$poll_interval = null;
|
||||
if ((($contact['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) {
|
||||
|
@ -432,6 +438,7 @@ class Profile extends BaseModule
|
|||
'$frequency_always' => ['channel_frequency', $this->t('Display all posts of this contact'), Contact\User::FREQUENCY_ALWAYS, $this->t('All posts from this contact will appear on the "for you" channel'), $channel_frequency == Contact\User::FREQUENCY_ALWAYS],
|
||||
'$frequency_reduced' => ['channel_frequency', $this->t('Display only few posts'), Contact\User::FREQUENCY_REDUCED, $this->t('When a contact creates a lot of posts in a short period, this setting reduces the number of displayed posts in every channel.'), $channel_frequency == Contact\User::FREQUENCY_REDUCED],
|
||||
'$frequency_never' => ['channel_frequency', $this->t('Never display posts'), Contact\User::FREQUENCY_NEVER, $this->t('Posts from this contact will never be displayed in any channel'), $channel_frequency == Contact\User::FREQUENCY_NEVER],
|
||||
'$channel_only' => ['channel_only', $this->t('Channel Only'), $channel_only, $this->t('If enabled, posts from this contact will only appear in channels, but not in the network stream.')],
|
||||
]);
|
||||
|
||||
$arr = ['contact' => $contact, 'output' => $o];
|
||||
|
|
|
@ -30,6 +30,7 @@ use Friendica\Module\Response;
|
|||
use Friendica\Network\HTTPClient\Capability\ICanSendHttpRequests;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Util\Profiler;
|
||||
use Friendica\Util\Strings;
|
||||
|
@ -107,7 +108,7 @@ class Redir extends \Friendica\BaseModule
|
|||
}
|
||||
|
||||
// Test for magic auth on the target system
|
||||
$response = $this->httpClient->head($basepath . '/magic', [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::HTML]);
|
||||
$response = $this->httpClient->head($basepath . '/magic', [HttpClientOptions::ACCEPT_CONTENT => HttpClientAccept::HTML, HttpClientOptions::REQUEST => HttpClientRequest::MAGICAUTH]);
|
||||
if ($response->isSuccess()) {
|
||||
$separator = strpos($target_url, '?') ? '&' : '?';
|
||||
$target_url .= $separator . 'zrl=' . urlencode($visitor) . '&addr=' . urlencode($contact_url);
|
||||
|
|
|
@ -133,7 +133,7 @@ class Unfollow extends \Friendica\BaseModule
|
|||
'$keywords_label' => ''
|
||||
]);
|
||||
|
||||
$this->page['aside'] = Widget\VCard::getHTML(Contact::getByURL($contact['url'], false));
|
||||
$this->page['aside'] = Widget\VCard::getHTML(Contact::getByURL($contact['url'], false), false, true);
|
||||
|
||||
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), ['$title' => $this->t('Posts and Replies')]);
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ class Channel extends Timeline
|
|||
$this->page['aside'] .= $this->getNoSharerWidget('channel');
|
||||
}
|
||||
|
||||
if (Feature::isEnabled($this->session->getLocalUserId(), 'trending_tags')) {
|
||||
if (Feature::isEnabled($this->session->getLocalUserId(), Feature::TRENDING_TAGS)) {
|
||||
$this->page['aside'] .= TrendingTags::getHTML($this->selectedTab);
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ class Channel extends Timeline
|
|||
}
|
||||
|
||||
if ($this->channel->isTimeline($this->selectedTab) || $this->userDefinedChannel->isTimeline($this->selectedTab, $this->session->getLocalUserId())) {
|
||||
$items = $this->getChannelItems($request);
|
||||
$items = $this->getChannelItems($request, $this->session->getLocalUserId());
|
||||
$order = 'created';
|
||||
} else {
|
||||
$items = $this->getCommunityItems();
|
||||
|
|