mirror of
https://github.com/friendica/friendica
synced 2024-12-22 13:20:15 +00:00
Merge branch 'stable' into develop
This commit is contained in:
commit
95229140f8
194 changed files with 11224 additions and 9691 deletions
87
CHANGELOG
87
CHANGELOG
|
@ -1,9 +1,86 @@
|
|||
Version 2024.06 (unreleased)
|
||||
Version 2024.08 (2024-08-17)
|
||||
Friendica Core
|
||||
Updates to the translations AR, CS, DE, ES, FR, GD, HU, IS, IT, JA, NL, PL, RU, SV
|
||||
Updates to the documentation [foss-, loma-one, mexon]
|
||||
Updates to the themes (frio) [haheute]
|
||||
General code cleanup [annando, haheute, mexon, MrPetovan]
|
||||
Improved the redirection for contact actions [annando]
|
||||
Improved the performance while fetching of replies [annando]
|
||||
Improved the performance when visiting remote profiles [annando]
|
||||
Improved OWA [annando]
|
||||
Improved the procession of worker tasks [annando]
|
||||
Improved performance in the probing process [annando]
|
||||
Improved INBOX performance [annando]
|
||||
Improved perfomance when expireing postings [annando]
|
||||
Improved mirroring settings for RSS contacts [annando]
|
||||
Improved supported image formats [annando]
|
||||
Improved handling of CC for comments [annando]
|
||||
Improved handling of "sensitive" flags for postings [annando]
|
||||
Improved display of log levels [annando, tobiasd]
|
||||
Improved handling of permissions for attachments [annando]
|
||||
Improved addon handling [MrPetovan]
|
||||
Improved API for channels and circles [annando]
|
||||
Improved performance while displaying local postings [annando]
|
||||
Improved federation with pixelfed, threads [annando]
|
||||
Improved integration with Bluesky [annando]
|
||||
Improved automatic cleanup of the database [annando]
|
||||
Fixed access to restricted timeline via API [annando]
|
||||
Fixed problem fetching from INBOXes [annando]
|
||||
Fixed display of contacts from unavailable networks [annando]
|
||||
Fixed profile display [annando]
|
||||
Fixed a problem with local un-/follows [annando]
|
||||
Fixed the uimport POST endpoint [annando]
|
||||
Fixed problem with 0Auth logins [annando]
|
||||
Fixed problem with @mentions in comments [annando]
|
||||
Fixed XSS in profile fields [annando, apexrabbit, Devilx86, MrPetovan, ponlayookm]
|
||||
Fixed bug in deleting unused cached avatar pictures [annando]
|
||||
Fixed paging bug on the media tab of remote profiles [annando]
|
||||
Fixed display of attached links [annando]
|
||||
Fixed a bug in circle only contacts [annando]
|
||||
Fixed display of moderation reports [MrPetovan, TheTomcat14]
|
||||
Fixed delivery problems to group postings [annando]
|
||||
Added monitoring service endpoint [annando]
|
||||
Added admin option display_link_length to set the length of displayed links [annando]
|
||||
Added the possibility to upload media files via API [annando]
|
||||
Added console command to clear avatar cache [annando]
|
||||
Added platform data to the API [annando]
|
||||
Added parsing support for Nodeinfo 2.1 and 2.2 [annando]
|
||||
Added node description to Nodeinfo [annando]
|
||||
Added owner information of relay accounts [annando]
|
||||
Added option for users about how to transmit postings with titles [annando]
|
||||
Added for non HTML content of feeds [annando]
|
||||
Added reshares for postings from Bluesky and tumbl [annando]
|
||||
Added public forums with manual request approval [annando]
|
||||
Added "next try" information for deferred worker jobs listing [annando]
|
||||
Added support of FEP-e232 [annando]
|
||||
Added automatic closure of registration if admin becomes inactive [annando]
|
||||
Added channel only option for contacts [annando]
|
||||
|
||||
Friendica Addons
|
||||
Friendica Addons
|
||||
Updates to the translations AR, CS, DE, FR, IT, PL, SV
|
||||
Blockbot
|
||||
Added Relatica to good client list [hankg]
|
||||
Improved agent identifier list [annando]
|
||||
Bluesky
|
||||
Added monitoring statistics [annando]
|
||||
Added support of sensitive postings [annando]
|
||||
Improved API handling [annando]
|
||||
Improved fetching of user DID [annando]
|
||||
Fixed conversion BS/Friendica handles [annando]
|
||||
jsuploader
|
||||
Improved detection of supported file types [annando]
|
||||
mailstream
|
||||
Improved image handling [mexon]
|
||||
tumblr
|
||||
Added monitoring statistics [annando]
|
||||
Improved quoted postings [annando]
|
||||
|
||||
Closed Issues
|
||||
Closed Issues
|
||||
11963, 13714, 13787, 13812, 13821, 13910, 14012, 14030, 14059,
|
||||
14077, 14079, 14045, 14052, 14055, 14081, 14084, 14102, 14110,
|
||||
14118, 14121, 14125, 14132, 14134, 14153, 14160, 14170, 14175,
|
||||
14186, 14197, 14220, 14228, 14231, 14240, 14249, 14250, 14285,
|
||||
14295, 14303, 14312, 14324, 14329, 14349, 14364
|
||||
|
||||
Version 2024.03 (2024-03-21)
|
||||
Friendica Core
|
||||
|
@ -292,7 +369,7 @@ Version 2023.04 (2023-04-23)
|
|||
twitter
|
||||
Improve remote-self handling [annando]
|
||||
impressum
|
||||
Avoide obfuscation on un-set email addresses [MrPestovan]
|
||||
Avoide obfuscation on un-set email addresses [MrPetovan]
|
||||
notifyall
|
||||
Fixed a bug selecting the email addresses [nupplaphil]
|
||||
tumblr
|
||||
|
@ -1741,7 +1818,7 @@ Version 2018.05 (2018-06-01)
|
|||
|
||||
Friendica Addons:
|
||||
Updates to the translations (DE, EN_GB, EN_US, ES, FI, FR, IS, IT, NL, PL, RU, ZH_CN) [translation teams]
|
||||
advancedcontentfilter: new addon with advanced filter capabilities [MrPetova]
|
||||
advancedcontentfilter: new addon with advanced filter capabilities [MrPetovan]
|
||||
catavatar: new addon for profile pictures based on David Revoy's cat-avatar generator [annando, fabrixxm, tobiasd]
|
||||
languagefilter: better help text [andyhee]
|
||||
mathjax: fixed the config form and adopted new CDN URL [tobiasd]
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
2024.06-dev
|
||||
2024.08
|
||||
|
|
|
@ -72,7 +72,7 @@ echo "Extract strings to $OUTFILE.."
|
|||
[ -f "$OUTFILE" ] && rm "$OUTFILE"; touch "$OUTFILE"
|
||||
|
||||
# shellcheck disable=SC2086 # $FINDOPTS is meant to be split
|
||||
find_result=$(find "$FINDSTARTDIR" $FINDOPTS -name "*.php" -type f | LC_ALL=C sort --stable)
|
||||
find_result=$(find "$FINDSTARTDIR" $FINDOPTS -name "*.php" -type f | LC_ALL=C sort -s)
|
||||
|
||||
total_files=$(wc -l <<< "${find_result}")
|
||||
|
||||
|
@ -86,7 +86,7 @@ do
|
|||
if [ ! -d "$file" ]
|
||||
then
|
||||
# shellcheck disable=SC2086 # $KEYWORDS is meant to be split
|
||||
xgettext $KEYWORDS -j -o "$OUTFILE" --from-code=UTF-8 "$file" || exit 1
|
||||
xgettext $KEYWORDS --no-wrap -j -o "$OUTFILE" --from-code=UTF-8 "$file" || exit 1
|
||||
sed -i.bkp "s/CHARSET/UTF-8/g" "$OUTFILE"
|
||||
fi
|
||||
(( count++ ))
|
||||
|
|
60
database.sql
60
database.sql
|
@ -1,6 +1,6 @@
|
|||
-- ------------------------------------------
|
||||
-- Friendica 2024.06-dev (Yellow Archangel)
|
||||
-- DB_UPDATE_VERSION 1565
|
||||
-- Friendica 2024.08 (Yellow Archangel)
|
||||
-- DB_UPDATE_VERSION 1571
|
||||
-- ------------------------------------------
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ CREATE TABLE IF NOT EXISTS `gserver` (
|
|||
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
|
||||
`url` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`nurl` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`version` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||
`version` varchar(255) NOT NULL DEFAULT '' COMMENT 'The version of this server software.',
|
||||
`site_name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||
`info` text COMMENT '',
|
||||
`register_policy` tinyint NOT NULL DEFAULT 0 COMMENT '',
|
||||
|
@ -28,7 +28,9 @@ CREATE TABLE IF NOT EXISTS `gserver` (
|
|||
`noscrape` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`network` char(4) NOT NULL DEFAULT '' COMMENT '',
|
||||
`protocol` tinyint unsigned COMMENT 'The protocol of the server',
|
||||
`platform` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||
`platform` varchar(255) NOT NULL DEFAULT '' COMMENT 'The canonical name of this server software.',
|
||||
`repository` varbinary(383) COMMENT 'The url of the source code repository of this server software.',
|
||||
`homepage` varbinary(383) COMMENT 'The url of the homepage of this server software.',
|
||||
`relay-subscribe` boolean NOT NULL DEFAULT '0' COMMENT 'Has the server subscribed to the relay system',
|
||||
`relay-scope` varchar(10) NOT NULL DEFAULT '' COMMENT 'The scope of messages that the server wants to get',
|
||||
`detection-method` tinyint unsigned COMMENT 'Method that had been used to detect that server',
|
||||
|
@ -815,6 +817,7 @@ CREATE TABLE IF NOT EXISTS `inbox-entry` (
|
|||
`activity-id` varbinary(383) COMMENT 'id of the incoming activity',
|
||||
`object-id` varbinary(383) COMMENT '',
|
||||
`in-reply-to-id` varbinary(383) COMMENT '',
|
||||
`context` varbinary(383) COMMENT '',
|
||||
`conversation` varbinary(383) COMMENT '',
|
||||
`type` varchar(64) COMMENT 'Type of the activity',
|
||||
`object-type` varchar(64) COMMENT 'Type of the object activity',
|
||||
|
@ -825,6 +828,7 @@ CREATE TABLE IF NOT EXISTS `inbox-entry` (
|
|||
`push` boolean COMMENT 'Is the entry pushed or have pulled it?',
|
||||
`trust` boolean COMMENT 'Do we trust this entry?',
|
||||
`wid` int unsigned COMMENT 'Workerqueue id',
|
||||
`retrial` tinyint unsigned DEFAULT 0 COMMENT 'Retrial counter',
|
||||
PRIMARY KEY(`id`),
|
||||
UNIQUE INDEX `activity-id` (`activity-id`),
|
||||
INDEX `object-id` (`object-id`),
|
||||
|
@ -1183,6 +1187,7 @@ CREATE TABLE IF NOT EXISTS `post` (
|
|||
`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',
|
||||
`external-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the external uri',
|
||||
`replies-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the endpoint for the replies collection',
|
||||
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation timestamp.',
|
||||
`edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last edit (default is created)',
|
||||
`received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime',
|
||||
|
@ -1201,6 +1206,7 @@ CREATE TABLE IF NOT EXISTS `post` (
|
|||
INDEX `parent-uri-id` (`parent-uri-id`),
|
||||
INDEX `thr-parent-id` (`thr-parent-id`),
|
||||
INDEX `external-id` (`external-id`),
|
||||
INDEX `replies-id` (`replies-id`),
|
||||
INDEX `owner-id` (`owner-id`),
|
||||
INDEX `author-id` (`author-id`),
|
||||
INDEX `causer-id` (`causer-id`),
|
||||
|
@ -1209,6 +1215,7 @@ CREATE TABLE IF NOT EXISTS `post` (
|
|||
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 (`external-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`replies-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`owner-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
FOREIGN KEY (`author-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
FOREIGN KEY (`causer-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
|
@ -1538,6 +1545,7 @@ CREATE TABLE IF NOT EXISTS `post-tag` (
|
|||
--
|
||||
CREATE TABLE IF NOT EXISTS `post-thread` (
|
||||
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
|
||||
`context-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the endpoint for the context collection',
|
||||
`conversation-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the conversation uri',
|
||||
`owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item owner',
|
||||
`author-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item author',
|
||||
|
@ -1548,6 +1556,7 @@ CREATE TABLE IF NOT EXISTS `post-thread` (
|
|||
`changed` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date that something in the conversation changed, indicating clients should fetch the conversation again',
|
||||
`commented` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
|
||||
PRIMARY KEY(`uri-id`),
|
||||
INDEX `context-id` (`context-id`),
|
||||
INDEX `conversation-id` (`conversation-id`),
|
||||
INDEX `owner-id` (`owner-id`),
|
||||
INDEX `author-id` (`author-id`),
|
||||
|
@ -1555,6 +1564,7 @@ CREATE TABLE IF NOT EXISTS `post-thread` (
|
|||
INDEX `received` (`received`),
|
||||
INDEX `commented` (`commented`),
|
||||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`context-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`conversation-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`owner-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
FOREIGN KEY (`author-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
|
@ -1570,6 +1580,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
|
|||
`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',
|
||||
`external-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the external uri',
|
||||
`replies-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the endpoint for the replies collection',
|
||||
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation timestamp.',
|
||||
`edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last edit (default is created)',
|
||||
`received` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime',
|
||||
|
@ -1602,6 +1613,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
|
|||
INDEX `parent-uri-id` (`parent-uri-id`),
|
||||
INDEX `thr-parent-id` (`thr-parent-id`),
|
||||
INDEX `external-id` (`external-id`),
|
||||
INDEX `replies-id` (`replies-id`),
|
||||
INDEX `owner-id` (`owner-id`),
|
||||
INDEX `author-id` (`author-id`),
|
||||
INDEX `causer-id` (`causer-id`),
|
||||
|
@ -1622,6 +1634,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
|
|||
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 (`external-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`replies-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`owner-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
FOREIGN KEY (`author-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
FOREIGN KEY (`causer-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
|
@ -1637,6 +1650,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
|
|||
--
|
||||
CREATE TABLE IF NOT EXISTS `post-thread-user` (
|
||||
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
|
||||
`context-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the endpoint for the context collection',
|
||||
`conversation-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the conversation uri',
|
||||
`owner-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item owner',
|
||||
`author-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item author',
|
||||
|
@ -1662,6 +1676,7 @@ CREATE TABLE IF NOT EXISTS `post-thread-user` (
|
|||
`post-user-id` int unsigned COMMENT 'Id of the post-user table',
|
||||
PRIMARY KEY(`uid`,`uri-id`),
|
||||
INDEX `uri-id` (`uri-id`),
|
||||
INDEX `context-id` (`context-id`),
|
||||
INDEX `conversation-id` (`conversation-id`),
|
||||
INDEX `owner-id` (`owner-id`),
|
||||
INDEX `author-id` (`author-id`),
|
||||
|
@ -1684,6 +1699,7 @@ CREATE TABLE IF NOT EXISTS `post-thread-user` (
|
|||
INDEX `contact-id_received` (`contact-id`,`received`),
|
||||
INDEX `contact-id_created` (`contact-id`,`created`),
|
||||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`context-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`conversation-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`owner-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
FOREIGN KEY (`author-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
|
@ -2271,6 +2287,8 @@ CREATE VIEW `post-origin-view` AS SELECT
|
|||
`post-origin`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread-user`.`conversation-id` AS `conversation-id`,
|
||||
`context-item-uri`.`uri` AS `context`,
|
||||
`post-thread-user`.`context-id` AS `context-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
|
@ -2278,6 +2296,8 @@ CREATE VIEW `post-origin-view` AS SELECT
|
|||
`post-origin`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post-user`.`external-id` AS `external-id`,
|
||||
`replies-item-uri`.`uri` AS `replies`,
|
||||
`post-user`.`replies-id` AS `replies-id`,
|
||||
`post-origin`.`created` AS `created`,
|
||||
`post-user`.`edited` AS `edited`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
|
@ -2431,7 +2451,9 @@ CREATE VIEW `post-origin-view` AS SELECT
|
|||
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 `context-item-uri` ON `context-item-uri`.`id` = `post-thread-user`.`context-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post-user`.`external-id`
|
||||
LEFT JOIN `item-uri` AS `replies-item-uri` ON `replies-item-uri`.`id` = `post-user`.`replies-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`
|
||||
|
@ -2459,6 +2481,8 @@ CREATE VIEW `post-thread-origin-view` AS SELECT
|
|||
`post-origin`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread-user`.`conversation-id` AS `conversation-id`,
|
||||
`context-item-uri`.`uri` AS `context`,
|
||||
`post-thread-user`.`context-id` AS `context-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
|
@ -2466,6 +2490,8 @@ CREATE VIEW `post-thread-origin-view` AS SELECT
|
|||
`post-origin`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post-user`.`external-id` AS `external-id`,
|
||||
`replies-item-uri`.`uri` AS `replies`,
|
||||
`post-user`.`replies-id` AS `replies-id`,
|
||||
`post-origin`.`created` AS `created`,
|
||||
`post-user`.`edited` AS `edited`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
|
@ -2618,7 +2644,9 @@ CREATE VIEW `post-thread-origin-view` AS SELECT
|
|||
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 `context-item-uri` ON `context-item-uri`.`id` = `post-thread-user`.`context-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post-user`.`external-id`
|
||||
LEFT JOIN `item-uri` AS `replies-item-uri` ON `replies-item-uri`.`id` = `post-user`.`replies-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`
|
||||
|
@ -2645,6 +2673,8 @@ CREATE VIEW `post-user-view` AS SELECT
|
|||
`post-user`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread-user`.`conversation-id` AS `conversation-id`,
|
||||
`context-item-uri`.`uri` AS `context`,
|
||||
`post-thread-user`.`context-id` AS `context-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
|
@ -2652,6 +2682,8 @@ CREATE VIEW `post-user-view` AS SELECT
|
|||
`post-user`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post-user`.`external-id` AS `external-id`,
|
||||
`replies-item-uri`.`uri` AS `replies`,
|
||||
`post-user`.`replies-id` AS `replies-id`,
|
||||
`post-user`.`created` AS `created`,
|
||||
`post-user`.`edited` AS `edited`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
|
@ -2804,7 +2836,9 @@ CREATE VIEW `post-user-view` AS SELECT
|
|||
LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-user`.`thr-parent-id`
|
||||
LEFT JOIN `item-uri` AS `parent-item-uri` ON `parent-item-uri`.`id` = `post-user`.`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 `context-item-uri` ON `context-item-uri`.`id` = `post-thread-user`.`context-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post-user`.`external-id`
|
||||
LEFT JOIN `item-uri` AS `replies-item-uri` ON `replies-item-uri`.`id` = `post-user`.`replies-id`
|
||||
LEFT JOIN `verb` ON `verb`.`id` = `post-user`.`vid`
|
||||
LEFT JOIN `event` ON `event`.`id` = `post-user`.`event-id`
|
||||
LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-user`.`uri-id`
|
||||
|
@ -2832,6 +2866,8 @@ CREATE VIEW `post-thread-user-view` AS SELECT
|
|||
`post-user`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread-user`.`conversation-id` AS `conversation-id`,
|
||||
`context-item-uri`.`uri` AS `context`,
|
||||
`post-thread-user`.`context-id` AS `context-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
|
@ -2839,6 +2875,8 @@ CREATE VIEW `post-thread-user-view` AS SELECT
|
|||
`post-user`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post-user`.`external-id` AS `external-id`,
|
||||
`replies-item-uri`.`uri` AS `replies`,
|
||||
`post-user`.`replies-id` AS `replies-id`,
|
||||
`post-thread-user`.`created` AS `created`,
|
||||
`post-user`.`edited` AS `edited`,
|
||||
`post-thread-user`.`commented` AS `commented`,
|
||||
|
@ -2990,7 +3028,9 @@ CREATE VIEW `post-thread-user-view` AS SELECT
|
|||
LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post-user`.`thr-parent-id`
|
||||
LEFT JOIN `item-uri` AS `parent-item-uri` ON `parent-item-uri`.`id` = `post-user`.`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 `context-item-uri` ON `context-item-uri`.`id` = `post-thread-user`.`context-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post-user`.`external-id`
|
||||
LEFT JOIN `item-uri` AS `replies-item-uri` ON `replies-item-uri`.`id` = `post-user`.`replies-id`
|
||||
LEFT JOIN `verb` ON `verb`.`id` = `post-user`.`vid`
|
||||
LEFT JOIN `event` ON `event`.`id` = `post-user`.`event-id`
|
||||
LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread-user`.`uri-id`
|
||||
|
@ -3013,12 +3053,16 @@ CREATE VIEW `post-view` AS SELECT
|
|||
`post`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread`.`conversation-id` AS `conversation-id`,
|
||||
`context-item-uri`.`uri` AS `context`,
|
||||
`post-thread`.`context-id` AS `context-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
`post`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post`.`external-id` AS `external-id`,
|
||||
`replies-item-uri`.`uri` AS `replies`,
|
||||
`post`.`replies-id` AS `replies-id`,
|
||||
`post`.`created` AS `created`,
|
||||
`post`.`edited` AS `edited`,
|
||||
`post-thread`.`commented` AS `commented`,
|
||||
|
@ -3139,7 +3183,9 @@ CREATE VIEW `post-view` AS SELECT
|
|||
LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post`.`thr-parent-id`
|
||||
LEFT JOIN `item-uri` AS `parent-item-uri` ON `parent-item-uri`.`id` = `post`.`parent-uri-id`
|
||||
LEFT JOIN `item-uri` AS `conversation-item-uri` ON `conversation-item-uri`.`id` = `post-thread`.`conversation-id`
|
||||
LEFT JOIN `item-uri` AS `context-item-uri` ON `context-item-uri`.`id` = `post-thread`.`context-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post`.`external-id`
|
||||
LEFT JOIN `item-uri` AS `replies-item-uri` ON `replies-item-uri`.`id` = `post`.`replies-id`
|
||||
LEFT JOIN `verb` ON `verb`.`id` = `post`.`vid`
|
||||
LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post`.`uri-id`
|
||||
LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post`.`uri-id`
|
||||
|
@ -3160,12 +3206,16 @@ CREATE VIEW `post-thread-view` AS SELECT
|
|||
`post`.`thr-parent-id` AS `thr-parent-id`,
|
||||
`conversation-item-uri`.`uri` AS `conversation`,
|
||||
`post-thread`.`conversation-id` AS `conversation-id`,
|
||||
`context-item-uri`.`uri` AS `context`,
|
||||
`post-thread`.`context-id` AS `context-id`,
|
||||
`quote-item-uri`.`uri` AS `quote-uri`,
|
||||
`post-content`.`quote-uri-id` AS `quote-uri-id`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
`post`.`gravity` AS `gravity`,
|
||||
`external-item-uri`.`uri` AS `extid`,
|
||||
`post`.`external-id` AS `external-id`,
|
||||
`replies-item-uri`.`uri` AS `replies`,
|
||||
`post`.`replies-id` AS `replies-id`,
|
||||
`post-thread`.`created` AS `created`,
|
||||
`post`.`edited` AS `edited`,
|
||||
`post-thread`.`commented` AS `commented`,
|
||||
|
@ -3288,7 +3338,9 @@ CREATE VIEW `post-thread-view` AS SELECT
|
|||
LEFT JOIN `item-uri` AS `thr-parent-item-uri` ON `thr-parent-item-uri`.`id` = `post`.`thr-parent-id`
|
||||
LEFT JOIN `item-uri` AS `parent-item-uri` ON `parent-item-uri`.`id` = `post`.`parent-uri-id`
|
||||
LEFT JOIN `item-uri` AS `conversation-item-uri` ON `conversation-item-uri`.`id` = `post-thread`.`conversation-id`
|
||||
LEFT JOIN `item-uri` AS `context-item-uri` ON `context-item-uri`.`id` = `post-thread`.`context-id`
|
||||
LEFT JOIN `item-uri` AS `external-item-uri` ON `external-item-uri`.`id` = `post`.`external-id`
|
||||
LEFT JOIN `item-uri` AS `replies-item-uri` ON `replies-item-uri`.`id` = `post`.`replies-id`
|
||||
LEFT JOIN `verb` ON `verb`.`id` = `post`.`vid`
|
||||
LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread`.`uri-id`
|
||||
LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-thread`.`uri-id`
|
||||
|
|
|
@ -78,4 +78,5 @@ Help
|
|||
**About**
|
||||
|
||||
* [Server Information](friendica)
|
||||
* [Terms of Service](tos)
|
||||
* [Credits](credits)
|
||||
|
|
|
@ -6,39 +6,41 @@ Global servers
|
|||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| --------------------- | -------------------------------------------------- | ---------------- | ---- | --- | ------------------- | -------------- |
|
||||
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
|
||||
| url | | varbinary(383) | NO | | | |
|
||||
| nurl | | varbinary(383) | NO | | | |
|
||||
| version | | varchar(255) | NO | | | |
|
||||
| site_name | | varchar(255) | NO | | | |
|
||||
| info | | text | YES | | NULL | |
|
||||
| register_policy | | tinyint | NO | | 0 | |
|
||||
| registered-users | Number of registered users | int unsigned | NO | | 0 | |
|
||||
| active-week-users | Number of active users in the last week | int unsigned | YES | | NULL | |
|
||||
| active-month-users | Number of active users in the last month | int unsigned | YES | | NULL | |
|
||||
| active-halfyear-users | Number of active users in the last six month | int unsigned | YES | | NULL | |
|
||||
| local-posts | Number of local posts | int unsigned | YES | | NULL | |
|
||||
| local-comments | Number of local comments | int unsigned | YES | | NULL | |
|
||||
| directory-type | Type of directory service (Poco, Mastodon) | tinyint | YES | | 0 | |
|
||||
| poco | | varbinary(383) | NO | | | |
|
||||
| openwebauth | Path to the OpenWebAuth endpoint | varbinary(383) | YES | | NULL | |
|
||||
| authredirect | Path to the authRedirect endpoint | varbinary(383) | YES | | NULL | |
|
||||
| noscrape | | varbinary(383) | NO | | | |
|
||||
| network | | char(4) | NO | | | |
|
||||
| protocol | The protocol of the server | tinyint unsigned | YES | | NULL | |
|
||||
| platform | | varchar(255) | NO | | | |
|
||||
| relay-subscribe | Has the server subscribed to the relay system | boolean | NO | | 0 | |
|
||||
| relay-scope | The scope of messages that the server wants to get | varchar(10) | NO | | | |
|
||||
| detection-method | Method that had been used to detect that server | tinyint unsigned | YES | | NULL | |
|
||||
| created | | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| last_poco_query | | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| last_contact | Last successful connection request | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| last_failure | Last failed connection request | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| blocked | Server is blocked | boolean | YES | | NULL | |
|
||||
| failed | Connection failed | boolean | YES | | NULL | |
|
||||
| next_contact | Next connection request | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| --------------------- | -------------------------------------------------------------- | ---------------- | ---- | --- | ------------------- | -------------- |
|
||||
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
|
||||
| url | | varbinary(383) | NO | | | |
|
||||
| nurl | | varbinary(383) | NO | | | |
|
||||
| version | The version of this server software. | varchar(255) | NO | | | |
|
||||
| site_name | | varchar(255) | NO | | | |
|
||||
| info | | text | YES | | NULL | |
|
||||
| register_policy | | tinyint | NO | | 0 | |
|
||||
| registered-users | Number of registered users | int unsigned | NO | | 0 | |
|
||||
| active-week-users | Number of active users in the last week | int unsigned | YES | | NULL | |
|
||||
| active-month-users | Number of active users in the last month | int unsigned | YES | | NULL | |
|
||||
| active-halfyear-users | Number of active users in the last six month | int unsigned | YES | | NULL | |
|
||||
| local-posts | Number of local posts | int unsigned | YES | | NULL | |
|
||||
| local-comments | Number of local comments | int unsigned | YES | | NULL | |
|
||||
| directory-type | Type of directory service (Poco, Mastodon) | tinyint | YES | | 0 | |
|
||||
| poco | | varbinary(383) | NO | | | |
|
||||
| openwebauth | Path to the OpenWebAuth endpoint | varbinary(383) | YES | | NULL | |
|
||||
| authredirect | Path to the authRedirect endpoint | varbinary(383) | YES | | NULL | |
|
||||
| noscrape | | varbinary(383) | NO | | | |
|
||||
| network | | char(4) | NO | | | |
|
||||
| protocol | The protocol of the server | tinyint unsigned | YES | | NULL | |
|
||||
| platform | The canonical name of this server software. | varchar(255) | NO | | | |
|
||||
| repository | The url of the source code repository of this server software. | varbinary(383) | YES | | NULL | |
|
||||
| homepage | The url of the homepage of this server software. | varbinary(383) | YES | | NULL | |
|
||||
| relay-subscribe | Has the server subscribed to the relay system | boolean | NO | | 0 | |
|
||||
| relay-scope | The scope of messages that the server wants to get | varchar(10) | NO | | | |
|
||||
| detection-method | Method that had been used to detect that server | tinyint unsigned | YES | | NULL | |
|
||||
| created | | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| last_poco_query | | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| last_contact | Last successful connection request | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| last_failure | Last failed connection request | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
| blocked | Server is blocked | boolean | YES | | NULL | |
|
||||
| failed | Connection failed | boolean | YES | | NULL | |
|
||||
| next_contact | Next connection request | datetime | YES | | 0001-01-01 00:00:00 | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
|
|
@ -6,22 +6,24 @@ Incoming activity
|
|||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------------------ | -------------------------------------- | -------------- | ---- | --- | ------- | -------------- |
|
||||
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
|
||||
| activity-id | id of the incoming activity | varbinary(383) | YES | | NULL | |
|
||||
| object-id | | varbinary(383) | YES | | NULL | |
|
||||
| in-reply-to-id | | varbinary(383) | YES | | NULL | |
|
||||
| conversation | | varbinary(383) | YES | | NULL | |
|
||||
| type | Type of the activity | varchar(64) | YES | | NULL | |
|
||||
| object-type | Type of the object activity | varchar(64) | YES | | NULL | |
|
||||
| object-object-type | Type of the object's object activity | varchar(64) | YES | | NULL | |
|
||||
| received | Receiving date | datetime | YES | | NULL | |
|
||||
| activity | The JSON activity | mediumtext | YES | | NULL | |
|
||||
| signer | | varchar(255) | YES | | NULL | |
|
||||
| push | Is the entry pushed or have pulled it? | boolean | YES | | NULL | |
|
||||
| trust | Do we trust this entry? | boolean | YES | | NULL | |
|
||||
| wid | Workerqueue id | int unsigned | YES | | NULL | |
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------------------ | -------------------------------------- | ---------------- | ---- | --- | ------- | -------------- |
|
||||
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
|
||||
| activity-id | id of the incoming activity | varbinary(383) | YES | | NULL | |
|
||||
| object-id | | varbinary(383) | YES | | NULL | |
|
||||
| in-reply-to-id | | varbinary(383) | YES | | NULL | |
|
||||
| context | | varbinary(383) | YES | | NULL | |
|
||||
| conversation | | varbinary(383) | YES | | NULL | |
|
||||
| type | Type of the activity | varchar(64) | YES | | NULL | |
|
||||
| object-type | Type of the object activity | varchar(64) | YES | | NULL | |
|
||||
| object-object-type | Type of the object's object activity | varchar(64) | YES | | NULL | |
|
||||
| received | Receiving date | datetime | YES | | NULL | |
|
||||
| activity | The JSON activity | mediumtext | YES | | NULL | |
|
||||
| signer | | varchar(255) | YES | | NULL | |
|
||||
| push | Is the entry pushed or have pulled it? | boolean | YES | | NULL | |
|
||||
| trust | Do we trust this entry? | boolean | YES | | NULL | |
|
||||
| wid | Workerqueue id | int unsigned | YES | | NULL | |
|
||||
| retrial | Retrial counter | tinyint unsigned | YES | | 0 | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
|
|
@ -9,6 +9,7 @@ Fields
|
|||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------- | ------------------ | ---- | --- | ------------------- | ----- |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | PRI | NULL | |
|
||||
| context-id | Id of the item-uri table entry that contains the endpoint for the context collection | int unsigned | YES | | NULL | |
|
||||
| conversation-id | Id of the item-uri table entry that contains the conversation uri | int unsigned | YES | | NULL | |
|
||||
| owner-id | Item owner | int unsigned | NO | | 0 | |
|
||||
| author-id | Item author | int unsigned | NO | | 0 | |
|
||||
|
@ -40,6 +41,7 @@ Indexes
|
|||
| -------------------- | --------------------- |
|
||||
| PRIMARY | uid, uri-id |
|
||||
| uri-id | uri-id |
|
||||
| context-id | context-id |
|
||||
| conversation-id | conversation-id |
|
||||
| owner-id | owner-id |
|
||||
| author-id | author-id |
|
||||
|
@ -68,6 +70,7 @@ Foreign Keys
|
|||
| Field | Target Table | Target Field |
|
||||
|-------|--------------|--------------|
|
||||
| uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| context-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| conversation-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| owner-id | [contact](help/database/db_contact) | id |
|
||||
| author-id | [contact](help/database/db_contact) | id |
|
||||
|
|
|
@ -9,6 +9,7 @@ Fields
|
|||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------- | ------------ | ---- | --- | ------------------- | ----- |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | PRI | NULL | |
|
||||
| context-id | Id of the item-uri table entry that contains the endpoint for the context collection | int unsigned | YES | | NULL | |
|
||||
| conversation-id | Id of the item-uri table entry that contains the conversation uri | int unsigned | YES | | NULL | |
|
||||
| owner-id | Item owner | int unsigned | NO | | 0 | |
|
||||
| author-id | Item author | int unsigned | NO | | 0 | |
|
||||
|
@ -25,6 +26,7 @@ Indexes
|
|||
| Name | Fields |
|
||||
| --------------- | --------------- |
|
||||
| PRIMARY | uri-id |
|
||||
| context-id | context-id |
|
||||
| conversation-id | conversation-id |
|
||||
| owner-id | owner-id |
|
||||
| author-id | author-id |
|
||||
|
@ -38,6 +40,7 @@ Foreign Keys
|
|||
| Field | Target Table | Target Field |
|
||||
|-------|--------------|--------------|
|
||||
| uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| context-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| conversation-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| owner-id | [contact](help/database/db_contact) | id |
|
||||
| author-id | [contact](help/database/db_contact) | id |
|
||||
|
|
|
@ -6,39 +6,40 @@ User specific post data
|
|||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ----------------- | --------------------------------------------------------------------------------- | ------------------ | ---- | --- | ------------------- | -------------- |
|
||||
| id | | int unsigned | NO | PRI | NULL | auto_increment |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | | NULL | |
|
||||
| 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 | |
|
||||
| external-id | Id of the item-uri table entry that contains the external uri | int unsigned | YES | | NULL | |
|
||||
| created | Creation timestamp. | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| edited | Date of last edit (default is created) | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| received | datetime | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| gravity | | tinyint unsigned | NO | | 0 | |
|
||||
| network | Network from where the item comes from | char(4) | NO | | | |
|
||||
| owner-id | Link to the contact table with uid=0 of the owner of this item | int unsigned | NO | | 0 | |
|
||||
| author-id | Link to the contact table with uid=0 of the author of this item | int unsigned | NO | | 0 | |
|
||||
| causer-id | Link to the contact table with uid=0 of the contact that caused the item creation | int unsigned | YES | | NULL | |
|
||||
| post-type | Post type (personal note, image, article, ...) | tinyint unsigned | NO | | 0 | |
|
||||
| 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 | |
|
||||
| uid | Owner id which owns this copy of the item | mediumint unsigned | NO | | NULL | |
|
||||
| protocol | Protocol used to deliver the item for this user | tinyint unsigned | YES | | NULL | |
|
||||
| contact-id | contact.id | int unsigned | NO | | 0 | |
|
||||
| event-id | Used to link to the event.id | int unsigned | YES | | NULL | |
|
||||
| unseen | post has not been seen | boolean | NO | | 1 | |
|
||||
| hidden | Marker to hide the post from the user | boolean | NO | | 0 | |
|
||||
| notification-type | | smallint unsigned | NO | | 0 | |
|
||||
| wall | This item was posted to the wall of uid | boolean | NO | | 0 | |
|
||||
| origin | item originated at this site | boolean | NO | | 0 | |
|
||||
| psid | ID of the permission set of this post | int unsigned | YES | | NULL | |
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ----------------- | ------------------------------------------------------------------------------------ | ------------------ | ---- | --- | ------------------- | -------------- |
|
||||
| id | | int unsigned | NO | PRI | NULL | auto_increment |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | | NULL | |
|
||||
| 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 | |
|
||||
| external-id | Id of the item-uri table entry that contains the external uri | int unsigned | YES | | NULL | |
|
||||
| replies-id | Id of the item-uri table entry that contains the endpoint for the replies collection | int unsigned | YES | | NULL | |
|
||||
| created | Creation timestamp. | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| edited | Date of last edit (default is created) | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| received | datetime | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| gravity | | tinyint unsigned | NO | | 0 | |
|
||||
| network | Network from where the item comes from | char(4) | NO | | | |
|
||||
| owner-id | Link to the contact table with uid=0 of the owner of this item | int unsigned | NO | | 0 | |
|
||||
| author-id | Link to the contact table with uid=0 of the author of this item | int unsigned | NO | | 0 | |
|
||||
| causer-id | Link to the contact table with uid=0 of the contact that caused the item creation | int unsigned | YES | | NULL | |
|
||||
| post-type | Post type (personal note, image, article, ...) | tinyint unsigned | NO | | 0 | |
|
||||
| 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 | |
|
||||
| uid | Owner id which owns this copy of the item | mediumint unsigned | NO | | NULL | |
|
||||
| protocol | Protocol used to deliver the item for this user | tinyint unsigned | YES | | NULL | |
|
||||
| contact-id | contact.id | int unsigned | NO | | 0 | |
|
||||
| event-id | Used to link to the event.id | int unsigned | YES | | NULL | |
|
||||
| unseen | post has not been seen | boolean | NO | | 1 | |
|
||||
| hidden | Marker to hide the post from the user | boolean | NO | | 0 | |
|
||||
| notification-type | | smallint unsigned | NO | | 0 | |
|
||||
| wall | This item was posted to the wall of uid | boolean | NO | | 0 | |
|
||||
| origin | item originated at this site | boolean | NO | | 0 | |
|
||||
| psid | ID of the permission set of this post | int unsigned | YES | | NULL | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
@ -51,6 +52,7 @@ Indexes
|
|||
| parent-uri-id | parent-uri-id |
|
||||
| thr-parent-id | thr-parent-id |
|
||||
| external-id | external-id |
|
||||
| replies-id | replies-id |
|
||||
| owner-id | owner-id |
|
||||
| author-id | author-id |
|
||||
| causer-id | causer-id |
|
||||
|
@ -77,6 +79,7 @@ Foreign Keys
|
|||
| parent-uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| thr-parent-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| external-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| replies-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| owner-id | [contact](help/database/db_contact) | id |
|
||||
| author-id | [contact](help/database/db_contact) | id |
|
||||
| causer-id | [contact](help/database/db_contact) | id |
|
||||
|
|
|
@ -6,26 +6,27 @@ Structure for all posts
|
|||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------------- | --------------------------------------------------------------------------------- | ----------------- | ---- | --- | ------------------- | ----- |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | PRI | 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 | |
|
||||
| external-id | Id of the item-uri table entry that contains the external uri | int unsigned | YES | | NULL | |
|
||||
| created | Creation timestamp. | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| edited | Date of last edit (default is created) | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| received | datetime | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| gravity | | tinyint unsigned | NO | | 0 | |
|
||||
| network | Network from where the item comes from | char(4) | NO | | | |
|
||||
| owner-id | Link to the contact table with uid=0 of the owner of this item | int unsigned | NO | | 0 | |
|
||||
| author-id | Link to the contact table with uid=0 of the author of this item | int unsigned | NO | | 0 | |
|
||||
| causer-id | Link to the contact table with uid=0 of the contact that caused the item creation | int unsigned | YES | | NULL | |
|
||||
| post-type | Post type (personal note, image, article, ...) | 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 | |
|
||||
| global | | boolean | NO | | 0 | |
|
||||
| visible | | boolean | NO | | 0 | |
|
||||
| deleted | item has been marked for deletion | boolean | NO | | 0 | |
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ------------- | ------------------------------------------------------------------------------------ | ----------------- | ---- | --- | ------------------- | ----- |
|
||||
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | PRI | 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 | |
|
||||
| external-id | Id of the item-uri table entry that contains the external uri | int unsigned | YES | | NULL | |
|
||||
| replies-id | Id of the item-uri table entry that contains the endpoint for the replies collection | int unsigned | YES | | NULL | |
|
||||
| created | Creation timestamp. | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| edited | Date of last edit (default is created) | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| received | datetime | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| gravity | | tinyint unsigned | NO | | 0 | |
|
||||
| network | Network from where the item comes from | char(4) | NO | | | |
|
||||
| owner-id | Link to the contact table with uid=0 of the owner of this item | int unsigned | NO | | 0 | |
|
||||
| author-id | Link to the contact table with uid=0 of the author of this item | int unsigned | NO | | 0 | |
|
||||
| causer-id | Link to the contact table with uid=0 of the contact that caused the item creation | int unsigned | YES | | NULL | |
|
||||
| post-type | Post type (personal note, image, article, ...) | 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 | |
|
||||
| global | | boolean | NO | | 0 | |
|
||||
| visible | | boolean | NO | | 0 | |
|
||||
| deleted | item has been marked for deletion | boolean | NO | | 0 | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
@ -36,6 +37,7 @@ Indexes
|
|||
| parent-uri-id | parent-uri-id |
|
||||
| thr-parent-id | thr-parent-id |
|
||||
| external-id | external-id |
|
||||
| replies-id | replies-id |
|
||||
| owner-id | owner-id |
|
||||
| author-id | author-id |
|
||||
| causer-id | causer-id |
|
||||
|
@ -50,6 +52,7 @@ Foreign Keys
|
|||
| parent-uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| thr-parent-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| external-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| replies-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| owner-id | [contact](help/database/db_contact) | id |
|
||||
| author-id | [contact](help/database/db_contact) | id |
|
||||
| causer-id | [contact](help/database/db_contact) | id |
|
||||
|
|
|
@ -72,4 +72,5 @@ Hilfe
|
|||
**Über**
|
||||
|
||||
* [Server Information](friendica)
|
||||
* [Nutzungsbedingungen](tos)
|
||||
* [Mitwirkende](credits)
|
||||
|
|
|
@ -78,3 +78,9 @@ The following will compress */var/log/friendica* (assuming this is the location
|
|||
daily
|
||||
rotate 2
|
||||
}
|
||||
|
||||
### Zabbix
|
||||
|
||||
To monitor the health status of your Friendica installation, you can use for example a tool like Zabbix. Please define 'stats_key' in your local.config.php in the 'system' section to be able to access the statistics page at /stats?key=your-defined-stats_key
|
||||
|
||||
The statistics contain data about the worker performance, the last cron call, number of reports, inbound and outbound packets, posts and comments.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Contact: mailto:info@friendi.ca
|
||||
|
||||
Expires: 2025-01-30T23:59:59Z
|
||||
Expires: 2025-06-30T23:59:59Z
|
||||
|
||||
Preferred-Languages: en
|
||||
|
||||
|
|
37
src/App.php
37
src/App.php
|
@ -24,6 +24,7 @@ namespace Friendica;
|
|||
use Exception;
|
||||
use Friendica\App\Arguments;
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\App\Request;
|
||||
use Friendica\Capabilities\ICanCreateResponses;
|
||||
use Friendica\Content\Nav;
|
||||
use Friendica\Core\Config\Factory\Config;
|
||||
|
@ -64,7 +65,7 @@ class App
|
|||
{
|
||||
const PLATFORM = 'Friendica';
|
||||
const CODENAME = 'Yellow Archangel';
|
||||
const VERSION = '2024.06-dev';
|
||||
const VERSION = '2024.08';
|
||||
|
||||
// Allow themes to control internal parameters
|
||||
// by changing App values in theme.php
|
||||
|
@ -93,6 +94,9 @@ class App
|
|||
/** @var string The name of the current mobile theme */
|
||||
private $currentMobileTheme;
|
||||
|
||||
/** @var string */
|
||||
private $requestId;
|
||||
|
||||
/** @var Authentication */
|
||||
private $auth;
|
||||
|
||||
|
@ -281,8 +285,9 @@ class App
|
|||
* @param DbaDefinition $dbaDefinition
|
||||
* @param ViewDefinition $viewDefinition
|
||||
*/
|
||||
public function __construct(Authentication $auth, Database $database, IManageConfigValues $config, App\Mode $mode, BaseURL $baseURL, LoggerInterface $logger, Profiler $profiler, L10n $l10n, Arguments $args, IManagePersonalConfigValues $pConfig, IHandleUserSessions $session, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition)
|
||||
public function __construct(Request $request, Authentication $auth, Database $database, IManageConfigValues $config, App\Mode $mode, BaseURL $baseURL, LoggerInterface $logger, Profiler $profiler, L10n $l10n, Arguments $args, IManagePersonalConfigValues $pConfig, IHandleUserSessions $session, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition)
|
||||
{
|
||||
$this->requestId = $request->getRequestId();
|
||||
$this->auth = $auth;
|
||||
$this->database = $database;
|
||||
$this->config = $config;
|
||||
|
@ -683,9 +688,11 @@ class App
|
|||
}
|
||||
|
||||
$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->logSlowCalls(microtime(true) - $request_start, $response->getStatusCode(), $requeststring, $server['HTTP_USER_AGENT'] ?? '');
|
||||
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->logSlowCalls(microtime(true) - $request_start, $e->getCode(), $requeststring, $server['HTTP_USER_AGENT'] ?? '');
|
||||
$httpException->rawContent($e);
|
||||
}
|
||||
$page->logRuntime($this->config, 'runFrontend');
|
||||
|
@ -707,4 +714,30 @@ class App
|
|||
$this->baseURL->redirect($toUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log slow page executions
|
||||
*
|
||||
* @param float $duration
|
||||
* @param integer $code
|
||||
* @param string $request
|
||||
* @param string $agent
|
||||
* @return void
|
||||
*/
|
||||
private function logSlowCalls(float $duration, int $code, string $request, string $agent)
|
||||
{
|
||||
$logfile = $this->config->get('system', 'page_execution_logfile');
|
||||
$loglimit = $this->config->get('system', 'page_execution_log_limit');
|
||||
if (empty($logfile) || empty($loglimit) || ($duration < $loglimit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@file_put_contents(
|
||||
$logfile,
|
||||
DateTimeFormat::utcNow() . "\t" . round($duration, 3) . "\t" .
|
||||
$this->requestId . "\t" . $code . "\t" .
|
||||
$request . "\t" . $agent . "\n",
|
||||
FILE_APPEND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,17 +224,17 @@ abstract class BaseModule implements ICanHandleRequests
|
|||
switch ($this->args->getMethod()) {
|
||||
case Router::DELETE:
|
||||
$this->delete($request);
|
||||
break;
|
||||
return $this->response->generate();
|
||||
case Router::PATCH:
|
||||
$this->patch($request);
|
||||
break;
|
||||
return $this->response->generate();
|
||||
case Router::POST:
|
||||
Core\Hook::callAll($this->args->getModuleName() . '_mod_post', $request);
|
||||
$this->post($request);
|
||||
break;
|
||||
return $this->response->generate();
|
||||
case Router::PUT:
|
||||
$this->put($request);
|
||||
break;
|
||||
return $this->response->generate();
|
||||
}
|
||||
|
||||
$timestamp = microtime(true);
|
||||
|
|
119
src/Console/ClearAvatarCache.php
Normal file
119
src/Console/ClearAvatarCache.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?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\Console;
|
||||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\Contact\Avatar;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
|
||||
/**
|
||||
* tool to clear the avatar file cache.
|
||||
*/
|
||||
class ClearAvatarCache extends \Asika\SimpleConsole\Console
|
||||
{
|
||||
protected $helpOptions = ['h', 'help', '?'];
|
||||
|
||||
/**
|
||||
* @var $dba Friendica\Database\Database
|
||||
*/
|
||||
private $dba;
|
||||
|
||||
/**
|
||||
* @var $baseurl Friendica\App\BaseURL
|
||||
*/
|
||||
private $baseUrl;
|
||||
|
||||
/**
|
||||
* @var L10n
|
||||
*/
|
||||
private $l10n;
|
||||
|
||||
/**
|
||||
* @var IManageConfigValues
|
||||
*/
|
||||
private $config;
|
||||
|
||||
protected function getHelp()
|
||||
{
|
||||
$help = <<<HELP
|
||||
console clearavatarcache - Clear the file based avatar cache
|
||||
Synopsis
|
||||
bin/console clearavatarcache
|
||||
|
||||
Description
|
||||
bin/console clearavatarcache
|
||||
Clear the file based avatar cache
|
||||
|
||||
Options
|
||||
-h|--help|-? Show help information
|
||||
HELP;
|
||||
return $help;
|
||||
}
|
||||
|
||||
public function __construct(\Friendica\Database\Database $dba, BaseURL $baseUrl, L10n $l10n, IManageConfigValues $config, array $argv = null)
|
||||
{
|
||||
parent::__construct($argv);
|
||||
|
||||
$this->dba = $dba;
|
||||
$this->baseUrl = $baseUrl;
|
||||
$this->l10n = $l10n;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function doExecute(): int
|
||||
{
|
||||
if ($this->config->get('system', 'avatar_cache')) {
|
||||
$this->err($this->l10n->t('The avatar cache needs to be disabled in local.config.php to use this command.'));
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Contacts (but not self contacts) with cached avatars.
|
||||
$condition = ["NOT `self` AND (`photo` != ? OR `thumb` != ? OR `micro` != ?)", '', '', ''];
|
||||
$total = $this->dba->count('contact', $condition);
|
||||
$count = 0;
|
||||
$contacts = $this->dba->select('contact', ['id', 'uri-id', 'url', 'uid', 'photo', 'thumb', 'micro'], $condition);
|
||||
while ($contact = $this->dba->fetch($contacts)) {
|
||||
if (Avatar::deleteCache($contact) || $this->isAvatarCache($contact)) {
|
||||
Contact::update(['photo' => '', 'thumb' => '', 'micro' => ''], ['id' => $contact['id']]);
|
||||
}
|
||||
$this->out(++$count . '/' . $total . "\t" . $contact['id'] . "\t" . $contact['url'] . "\t" . $contact['photo']);
|
||||
}
|
||||
$this->dba->close($contacts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function isAvatarCache(array $contact): bool
|
||||
{
|
||||
if (!empty($contact['photo']) && strpos($contact['photo'], Avatar::baseUrl()) === 0) {
|
||||
return true;
|
||||
}
|
||||
if (!empty($contact['thumb']) && strpos($contact['thumb'], Avatar::baseUrl()) === 0) {
|
||||
return true;
|
||||
}
|
||||
if (!empty($contact['micro']) && strpos($contact['micro'], Avatar::baseUrl()) === 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -25,6 +25,9 @@ use Asika\SimpleConsole\CommandArgsException;
|
|||
use Friendica\Core\Storage\Repository\StorageManager;
|
||||
use Friendica\Core\Storage\Exception\ReferenceStorageException;
|
||||
use Friendica\Core\Storage\Exception\StorageException;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Photo;
|
||||
|
||||
/**
|
||||
* tool to manage storage backend and stored data from CLI
|
||||
|
@ -57,6 +60,9 @@ Synopsis
|
|||
bin/console storage list
|
||||
List available storage backends
|
||||
|
||||
bin/console storage clear
|
||||
Remove the contact avatar cache data
|
||||
|
||||
bin/console storage set <name>
|
||||
Set current storage backend
|
||||
name storage backend to use. see "list".
|
||||
|
@ -87,6 +93,9 @@ HELP;
|
|||
case 'list':
|
||||
return $this->doList();
|
||||
break;
|
||||
case 'clear':
|
||||
return $this->clear();
|
||||
break;
|
||||
case 'set':
|
||||
return $this->doSet();
|
||||
break;
|
||||
|
@ -126,6 +135,22 @@ HELP;
|
|||
return 0;
|
||||
}
|
||||
|
||||
protected function clear()
|
||||
{
|
||||
$fields = ['photo' => '', 'thumb' => '', 'micro' => ''];
|
||||
$photos = DBA::select('photo', ['id', 'contact-id'], ['uid' => 0, 'photo-type' => [Photo::CONTACT_AVATAR, Photo::CONTACT_BANNER]]);
|
||||
while ($photo = DBA::fetch($photos)) {
|
||||
if (Photo::delete(['id' => $photo['id']])) {
|
||||
Contact::update($fields, ['id' => $photo['contact-id']]);
|
||||
$this->out('Cleared photo id ' . $photo['id'] . ' - contact id ' . $photo['contact-id']);
|
||||
} else {
|
||||
$this->out('Photo id ' . $photo['id'] . ' was not deleted.');
|
||||
}
|
||||
}
|
||||
DBA::close($photos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function doSet()
|
||||
{
|
||||
if (count($this->args) !== 2 || empty($this->args[1])) {
|
||||
|
|
|
@ -23,14 +23,11 @@ namespace Friendica\Contact;
|
|||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||
use Friendica\Object\Image;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\HTTPSignature;
|
||||
use Friendica\Util\Images;
|
||||
use Friendica\Util\Network;
|
||||
use Friendica\Util\Proxy;
|
||||
|
||||
/**
|
||||
|
@ -97,7 +94,7 @@ class Avatar
|
|||
return $fields;
|
||||
}
|
||||
|
||||
$filename = self::getFilename($contact['url'], $avatar);
|
||||
$filename = self::getFilename($contact['url']);
|
||||
$timestamp = time();
|
||||
|
||||
$fields['blurhash'] = $image->getBlurHash();
|
||||
|
@ -125,7 +122,7 @@ class Avatar
|
|||
return $fields;
|
||||
}
|
||||
|
||||
$filename = self::getFilename($contact['url'], $contact['avatar']);
|
||||
$filename = self::getFilename($contact['url']);
|
||||
$timestamp = time();
|
||||
|
||||
$fields['photo'] = self::storeAvatarCache($image, $filename, Proxy::PIXEL_SMALL, $timestamp);
|
||||
|
@ -135,12 +132,10 @@ class Avatar
|
|||
return $fields;
|
||||
}
|
||||
|
||||
private static function getFilename(string $url, string $host): string
|
||||
private static function getFilename(string $url): string
|
||||
{
|
||||
$guid = Item::guidFromUri($url, $host);
|
||||
|
||||
return substr($guid, 0, 2) . '/' . substr($guid, 3, 2) . '/' . substr($guid, 5, 3) . '/' .
|
||||
substr($guid, 9, 2) .'/' . substr($guid, 11, 2) . '/' . substr($guid, 13, 4). '/' . substr($guid, 18) . '-';
|
||||
$guid = hash('ripemd128', $url);
|
||||
return substr($guid, 0, 3) . '/' . substr($guid, 4) . '-';
|
||||
}
|
||||
|
||||
private static function storeAvatarCache(Image $image, string $filename, int $size, int $timestamp): string
|
||||
|
@ -279,7 +274,7 @@ class Avatar
|
|||
$localFile = self::getCacheFile($avatar);
|
||||
if (!empty($localFile)) {
|
||||
@unlink($localFile);
|
||||
Logger::debug('Unlink avatar', ['avatar' => $avatar]);
|
||||
Logger::debug('Unlink avatar', ['avatar' => $avatar, 'local' => $localFile]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,7 +311,7 @@ class Avatar
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function baseUrl(): string
|
||||
public static function baseUrl(): string
|
||||
{
|
||||
$baseurl = DI::config()->get('system', 'avatar_cache_url');
|
||||
if (!empty($baseurl)) {
|
||||
|
|
|
@ -66,7 +66,7 @@ class GroupManager
|
|||
'archive' => false,
|
||||
];
|
||||
|
||||
$condition = DBA::mergeConditions($condition, ["`platform` != ?", 'peertube']);
|
||||
$condition = DBA::mergeConditions($condition, ["`platform` NOT IN (?, ?)", 'peertube', 'wordpress']);
|
||||
|
||||
if (!$showprivate) {
|
||||
$condition = DBA::mergeConditions($condition, ['manually-approve' => false]);
|
||||
|
|
|
@ -547,9 +547,9 @@ class Item
|
|||
$item['private'] = $private_group ? ItemModel::PRIVATE : ItemModel::UNLISTED;
|
||||
|
||||
if ($only_to_group) {
|
||||
$cdata = Contact::getPublicAndUserContactID($group_contact['id'], $item['uid']);
|
||||
if (!empty($cdata['user'])) {
|
||||
$item['owner-id'] = $cdata['user'];
|
||||
$pcid = Contact::getPublicContactId($group_contact['id'], $item['uid']);
|
||||
if ($pcid) {
|
||||
$item['owner-id'] = $pcid;
|
||||
unset($item['owner-link']);
|
||||
unset($item['owner-name']);
|
||||
unset($item['owner-avatar']);
|
||||
|
@ -1032,7 +1032,7 @@ class Item
|
|||
}
|
||||
|
||||
$this->emailer->send(new ItemCCEMail(
|
||||
$this->app,
|
||||
$this->userSession,
|
||||
$this->l10n,
|
||||
$this->baseURL,
|
||||
$post,
|
||||
|
|
|
@ -1364,7 +1364,7 @@ class BBCode
|
|||
// At a later stage we won't be able to exclude certain parts of the code.
|
||||
$text = self::performWithEscapedTags($text, ['url', 'img', 'audio', 'video', 'youtube', 'vimeo', 'share', 'attachment', 'iframe', 'bookmark', 'map', 'oembed'], function ($text) use ($simple_html, $for_plaintext) {
|
||||
if (!$for_plaintext) {
|
||||
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
|
||||
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text) ?? '';
|
||||
}
|
||||
return self::convertSmileysToHtml($text, $simple_html, $for_plaintext);
|
||||
});
|
||||
|
@ -2090,7 +2090,7 @@ class BBCode
|
|||
$text = preg_replace("/\[zrl\=(.*?)\](.*?)\[\/zrl\]/ism", '[url=$1]$2[/url]', $text);
|
||||
|
||||
if (in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::DIASPORA, self::OSTATUS, self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) {
|
||||
$text = self::shortenLinkDescription($text);
|
||||
$text = self::shortenLinkDescription($text, $simple_html);
|
||||
} else {
|
||||
$text = self::unifyLinks($text);
|
||||
}
|
||||
|
@ -2124,7 +2124,12 @@ class BBCode
|
|||
}
|
||||
|
||||
$parts['host'] = idn_to_ascii(urldecode($parts['host']));
|
||||
return (string)Uri::fromParts($parts);
|
||||
try {
|
||||
return (string)Uri::fromParts($parts);
|
||||
} catch (\Throwable $th) {
|
||||
Logger::notice('Exception on unparsing url', ['url' => $url, 'parts' => $parts, 'code' => $th->getCode(), 'message' => $th->getMessage()]);
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
private static function unifyLinks(string $text): string
|
||||
|
@ -2138,20 +2143,26 @@ class BBCode
|
|||
);
|
||||
}
|
||||
|
||||
private static function shortenLinkDescription(string $text): string
|
||||
private static function shortenLinkDescription(string $text, int $simple_html): string
|
||||
{
|
||||
if ($simple_html == self::INTERNAL) {
|
||||
$max_length = DI::config()->get('system', 'display_link_length');
|
||||
} else {
|
||||
$max_length = 30;
|
||||
}
|
||||
|
||||
$text = preg_replace_callback(
|
||||
"/\[url\](.*?)\[\/url\]/ism",
|
||||
function ($match) {
|
||||
return "[url=" . self::escapeUrl($match[1]) . "]" . Strings::getStyledURL($match[1]) . "[/url]";
|
||||
function ($match) use ($max_length) {
|
||||
return "[url=" . self::escapeUrl($match[1]) . "]" . Strings::getStyledURL($match[1], $max_length) . "[/url]";
|
||||
},
|
||||
$text
|
||||
);
|
||||
$text = preg_replace_callback(
|
||||
"/\[url\=(.*?)\](.*?)\[\/url\]/ism",
|
||||
function ($match) {
|
||||
function ($match) use ($max_length) {
|
||||
if ($match[1] == $match[2]) {
|
||||
return "[url=" . self::escapeUrl($match[1]) . "]" . Strings::getStyledURL($match[2]) . "[/url]";
|
||||
return "[url=" . self::escapeUrl($match[1]) . "]" . Strings::getStyledURL($match[2], $max_length) . "[/url]";
|
||||
} else {
|
||||
return "[url=" . self::escapeUrl($match[1]) . "]" . $match[2] . "[/url]";
|
||||
}
|
||||
|
@ -2641,7 +2652,7 @@ class BBCode
|
|||
$bbcode = "\n" . '[audio]' . $url . '[/audio]' . "\n";
|
||||
break;
|
||||
default:
|
||||
$bbcode = "\n" . '[img]' . $url . '[/img]' . "\n";
|
||||
$bbcode = "\n" . '[img=' . $url . '][/img]' . "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -868,7 +868,7 @@ class HTML
|
|||
'$save_label' => $save_label,
|
||||
'$search_hint' => DI::l10n()->t('@name, !group, #tags, content'),
|
||||
'$mode' => $mode,
|
||||
'$return_url' => urlencode(Search::getSearchPath($s)),
|
||||
'$return_url' => bin2hex(Search::getSearchPath($s)),
|
||||
];
|
||||
|
||||
if (!$aside) {
|
||||
|
|
|
@ -398,7 +398,7 @@ class Widget
|
|||
$entries[] = [
|
||||
'url' => Contact::magicLinkByContact($contact),
|
||||
'name' => $contact['name'],
|
||||
'photo' => Contact::getThumb($contact),
|
||||
'photo' => Contact::getThumb($contact, true),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class SavedSearches
|
|||
'$add' => '',
|
||||
'$searchbox' => '',
|
||||
'$saved' => $saved,
|
||||
'$return_url' => urlencode($return_url),
|
||||
'$return_url' => bin2hex($return_url),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ Usage: bin/console [--version] [-h|--help|-?] <command> [<args>] [-v]
|
|||
Commands:
|
||||
addon Addon management
|
||||
cache Manage node cache
|
||||
clearavatarcache Clear the file based avatar cache
|
||||
config Edit site config
|
||||
contact Contact management
|
||||
createdoxygen Generate Doxygen headers
|
||||
|
@ -84,6 +85,7 @@ HELP;
|
|||
'archivecontact' => Friendica\Console\ArchiveContact::class,
|
||||
'autoinstall' => Friendica\Console\AutomaticInstallation::class,
|
||||
'cache' => Friendica\Console\Cache::class,
|
||||
'clearavatarcache' => Friendica\Console\ClearAvatarCache::class,
|
||||
'config' => Friendica\Console\Config::class,
|
||||
'contact' => Friendica\Console\Contact::class,
|
||||
'createdoxygen' => Friendica\Console\CreateDoxygen::class,
|
||||
|
|
|
@ -235,7 +235,7 @@ class Worker
|
|||
* @return integer Number of deferred entries in the worker queue
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function deferredEntries(): int
|
||||
public static function deferredEntries(): int
|
||||
{
|
||||
$stamp = (float)microtime(true);
|
||||
$count = DBA::count('workerqueue', ["NOT `done` AND `pid` = 0 AND `retrial` > ?", 0]);
|
||||
|
@ -250,7 +250,7 @@ class Worker
|
|||
* @return integer Number of non executed entries in the worker queue
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function totalEntries(): int
|
||||
public static function totalEntries(): int
|
||||
{
|
||||
$stamp = (float)microtime(true);
|
||||
$count = DBA::count('workerqueue', ['done' => false, 'pid' => 0]);
|
||||
|
@ -862,7 +862,7 @@ class Worker
|
|||
* @return integer Number of active worker processes
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function activeWorkers(): int
|
||||
public static function activeWorkers(): int
|
||||
{
|
||||
$stamp = (float)microtime(true);
|
||||
$count = DI::process()->countCommand('Worker.php');
|
||||
|
|
|
@ -66,7 +66,7 @@ abstract class DI
|
|||
public static function setCompositeRootDependencyByHand()
|
||||
{
|
||||
$database = static::dba();
|
||||
$database->setDependency(static::config(), static::profiler(), static::logger());
|
||||
$database->setDependency(static::config(), static::profiler(), static::logger(), static::lock());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace Friendica\Database;
|
||||
|
||||
use Friendica\Core\Lock\Exception\LockPersistenceException;
|
||||
use Friendica\DI;
|
||||
use mysqli;
|
||||
use mysqli_result;
|
||||
|
@ -823,6 +824,27 @@ class DBA
|
|||
return DI::dba()->optimizeTable($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire a lock to prevent a table optimization
|
||||
*
|
||||
* @return bool
|
||||
* @throws LockPersistenceException
|
||||
*/
|
||||
public static function acquireOptimizeLock(): bool
|
||||
{
|
||||
return DI::dba()->acquireOptimizeLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the table optimization lock
|
||||
* @return bool
|
||||
* @throws LockPersistenceException
|
||||
*/
|
||||
public static function releaseOptimizeLock(): bool
|
||||
{
|
||||
return DI::dba()->releaseOptimizeLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill sleeping database processes
|
||||
*/
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
namespace Friendica\Database;
|
||||
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\Lock\Capability\ICanLock;
|
||||
use Friendica\Core\Lock\Exception\LockPersistenceException;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\Definition\DbaDefinition;
|
||||
use Friendica\Database\Definition\ViewDefinition;
|
||||
|
@ -50,6 +52,8 @@ class Database
|
|||
const INSERT_UPDATE = 1;
|
||||
const INSERT_IGNORE = 2;
|
||||
|
||||
const LOCK_OPTIMIZE = 'database::optimize_tables';
|
||||
|
||||
protected $connected = false;
|
||||
|
||||
/**
|
||||
|
@ -64,6 +68,11 @@ class Database
|
|||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger = null;
|
||||
/**
|
||||
* @var ICanLock
|
||||
*/
|
||||
protected $syslock = null;
|
||||
|
||||
protected $server_info = '';
|
||||
/** @var PDO|mysqli */
|
||||
protected $connection;
|
||||
|
@ -106,11 +115,12 @@ class Database
|
|||
*
|
||||
* @todo Make this method obsolete - use a clean pattern instead ...
|
||||
*/
|
||||
public function setDependency(IManageConfigValues $config, Profiler $profiler, LoggerInterface $logger)
|
||||
public function setDependency(IManageConfigValues $config, Profiler $profiler, LoggerInterface $logger, ICanLock $lock)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->profiler = $profiler;
|
||||
$this->config = $config;
|
||||
$this->syslock = $lock;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1755,7 +1765,42 @@ class Database
|
|||
*/
|
||||
public function optimizeTable(string $table): bool
|
||||
{
|
||||
return $this->e("OPTIMIZE TABLE " . DBA::buildTableString([$table])) !== false;
|
||||
if ($this->syslock->isLocked(self::LOCK_OPTIMIZE)) {
|
||||
$this->logger->info('Optimization is locked');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->acquireOptimizeLock()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $this->e("OPTIMIZE TABLE " . DBA::buildTableString([$table])) !== false;
|
||||
|
||||
$this->releaseOptimizeLock();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire a lock to prevent a table optimization
|
||||
*
|
||||
* @return bool
|
||||
* @throws LockPersistenceException
|
||||
*/
|
||||
public function acquireOptimizeLock(): bool
|
||||
{
|
||||
return $this->syslock->acquire(self::LOCK_OPTIMIZE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the table optimization lock
|
||||
*
|
||||
* @return bool
|
||||
* @throws LockPersistenceException
|
||||
*/
|
||||
public function releaseOptimizeLock(): bool
|
||||
{
|
||||
return $this->syslock->release(self::LOCK_OPTIMIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace Friendica\Factory\Api\Mastodon;
|
|||
|
||||
use Friendica\App\BaseURL;
|
||||
use Friendica\BaseFactory;
|
||||
use Friendica\Model\Attach;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Model\Post;
|
||||
|
@ -144,4 +145,37 @@ class Attachment extends BaseFactory
|
|||
$object = new \Friendica\Object\Api\Mastodon\Attachment($attachment, 'image', $url, $preview_url, '');
|
||||
return $object->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id id of the attachment
|
||||
*
|
||||
* @return array
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public function createFromAttach(int $id): array
|
||||
{
|
||||
$media = Attach::selectFirst(['id', 'filetype'], ['id' => $id]);
|
||||
if (empty($media)) {
|
||||
return [];
|
||||
}
|
||||
$attachment = [
|
||||
'id' => 'attach:' . $media['id'],
|
||||
'description' => null,
|
||||
'blurhash' => null,
|
||||
];
|
||||
|
||||
$types = [Post\Media::AUDIO => 'audio', Post\Media::VIDEO => 'video', Post\Media::IMAGE => 'image'];
|
||||
|
||||
$type = Post\Media::getType($media['filetype']);
|
||||
|
||||
$url = $this->baseUrl . '/attach/' . $id;
|
||||
|
||||
$object = new \Friendica\Object\Api\Mastodon\Attachment($attachment, $types[$type] ?? 'unknown', $url, '', '');
|
||||
return $object->toArray();
|
||||
}
|
||||
|
||||
public function isAttach(string $id): bool
|
||||
{
|
||||
return substr($id, 0, 7) == 'attach:';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ use Friendica\Content\Item as ContentItem;
|
|||
use Friendica\Content\Smilies;
|
||||
use Friendica\Content\Text\BBCode;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
|
@ -105,7 +106,7 @@ class Status extends BaseFactory
|
|||
*/
|
||||
public function createFromUriId(int $uriId, int $uid = 0, bool $display_quote = false, bool $reblog = true, bool $in_reply_status = true): \Friendica\Object\Api\Mastodon\Status
|
||||
{
|
||||
$fields = ['uri-id', 'uid', 'author-id', 'causer-id', 'author-uri-id', 'author-link', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
|
||||
$fields = ['uri-id', 'uid', 'author-id', 'causer-id', 'author-uri-id', 'author-link', 'author-gsid', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
|
||||
'created', 'edited', 'commented', 'received', 'changed', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id',
|
||||
'delivery_queue_count', 'delivery_queue_done','delivery_queue_failed', 'allow_cid', 'deny_cid', 'allow_gid', 'deny_gid', 'sensitive'];
|
||||
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
|
||||
|
@ -212,8 +213,27 @@ class Status extends BaseFactory
|
|||
$item['featured']
|
||||
);
|
||||
|
||||
$sensitive = (bool)$item['sensitive'];
|
||||
$application = new \Friendica\Object\Api\Mastodon\Application($item['app'] ?: ContactSelector::networkToName($item['network'], $item['author-link']));
|
||||
$sensitive = (bool)$item['sensitive'];
|
||||
|
||||
$network = ContactSelector::networkToName($item['network']);
|
||||
$sitename = '';
|
||||
$platform = '';
|
||||
$version = '';
|
||||
|
||||
if (in_array($item['network'], Protocol::FEDERATED)) {
|
||||
$gserver = $this->dba->selectFirst('gserver', ['site_name', 'platform', 'version'], ['id' => $item['author-gsid']]);
|
||||
if (!empty($gserver)) {
|
||||
$platform = ucfirst($gserver['platform']);
|
||||
$version = $gserver['version'];
|
||||
$sitename = $gserver['site_name'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($platform == '') {
|
||||
$platform = ContactSelector::networkToName($item['network'], $item['author-link'], $item['network'], $item['author-gsid']);
|
||||
}
|
||||
|
||||
$application = new \Friendica\Object\Api\Mastodon\Application($item['app'] ?: $platform);
|
||||
|
||||
$mentions = $this->mstdnMentionFactory->createFromUriId($uriId)->getArrayCopy();
|
||||
$tags = $this->mstdnTagFactory->createFromUriId($uriId);
|
||||
|
@ -322,7 +342,7 @@ class Status extends BaseFactory
|
|||
|
||||
$delivery_data = $uid != $item['uid'] ? null : new FriendicaDeliveryData($item['delivery_queue_count'], $item['delivery_queue_done'], $item['delivery_queue_failed']);
|
||||
$visibility_data = $uid != $item['uid'] ? null : new FriendicaVisibility($this->aclFormatter->expand($item['allow_cid']), $this->aclFormatter->expand($item['deny_cid']), $this->aclFormatter->expand($item['allow_gid']), $this->aclFormatter->expand($item['deny_gid']));
|
||||
$friendica = new FriendicaExtension($item['title'] ?? '', $item['changed'], $item['commented'], $item['received'], $counts->dislikes, $origin_dislike, $delivery_data, $visibility_data);
|
||||
$friendica = new FriendicaExtension($item['title'] ?? '', $item['changed'], $item['commented'], $item['received'], $counts->dislikes, $origin_dislike, $network, $platform, $version, $sitename, $delivery_data, $visibility_data);
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $friendica, $quote, $poll, $emojis);
|
||||
}
|
||||
|
@ -393,7 +413,7 @@ class Status extends BaseFactory
|
|||
$attachments = [];
|
||||
$in_reply = [];
|
||||
$reshare = [];
|
||||
$friendica = new FriendicaExtension('', null, null, null, 0, false, null, null);
|
||||
$friendica = new FriendicaExtension('', null, null, null, 0, false, null, null, null, null, null, null);
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $in_reply, $reshare, $friendica);
|
||||
}
|
||||
|
|
|
@ -287,6 +287,7 @@ class APContact
|
|||
} elseif ($apcontact['type'] == 'Tombstone') {
|
||||
// The "inbox" field must have a content
|
||||
$apcontact['inbox'] = '';
|
||||
$apcontact['addr'] = '';
|
||||
}
|
||||
|
||||
// Quit if this doesn't seem to be an account at all
|
||||
|
@ -294,7 +295,7 @@ class APContact
|
|||
return $fetched_contact;
|
||||
}
|
||||
|
||||
if (empty($apcontact['addr'])) {
|
||||
if (empty($apcontact['addr']) && ($apcontact['type'] != 'Tombstone')) {
|
||||
try {
|
||||
$apcontact['addr'] = $apcontact['nick'] . '@' . (new Uri($apcontact['url']))->getAuthority();
|
||||
} catch (\Throwable $e) {
|
||||
|
|
|
@ -245,6 +245,7 @@ class Attach
|
|||
* @param string $src Source file name
|
||||
* @param int $uid User id
|
||||
* @param string $filename Optional file name
|
||||
* @param string $filetype Optional file type
|
||||
* @param string $allow_cid
|
||||
* @param string $allow_gid
|
||||
* @param string $deny_cid
|
||||
|
@ -252,7 +253,7 @@ class Attach
|
|||
* @return boolean|int Insert id or false on failure
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function storeFile(string $src, int $uid, string $filename = '', string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '')
|
||||
public static function storeFile(string $src, int $uid, string $filename = '', string $filetype = '', string $allow_cid = '', string $allow_gid = '', string $deny_cid = '', string $deny_gid = '')
|
||||
{
|
||||
if ($filename === '') {
|
||||
$filename = basename($src);
|
||||
|
@ -260,7 +261,7 @@ class Attach
|
|||
|
||||
$data = @file_get_contents($src);
|
||||
|
||||
return self::store($data, $uid, $filename, '', null, $allow_cid, $allow_gid, $deny_cid, $deny_gid);
|
||||
return self::store($data, $uid, $filename, $filetype, null, $allow_cid, $allow_gid, $deny_cid, $deny_gid);
|
||||
}
|
||||
|
||||
|
||||
|
@ -345,6 +346,16 @@ class Attach
|
|||
}
|
||||
}
|
||||
|
||||
public static function setPermissionForId(int $id, 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,
|
||||
];
|
||||
|
||||
self::update($fields, ['id' => $id, 'uid' => $uid]);
|
||||
}
|
||||
|
||||
public static function addAttachmentToBody(string $body, int $uid): string
|
||||
{
|
||||
preg_match_all("/\[attachment\](.*?)\[\/attachment\]/ism", $body, $matches, PREG_SET_ORDER);
|
||||
|
|
|
@ -290,12 +290,12 @@ class Circle
|
|||
throw new HTTPException\NotFoundException('Circle not found.');
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
return DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $cdata['user']], Database::INSERT_IGNORE);
|
||||
return DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $ucid], Database::INSERT_IGNORE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -318,12 +318,12 @@ class Circle
|
|||
throw new HTTPException\NotFoundException('Circle not found.');
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
return DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $cid]);
|
||||
return DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $ucid]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,12 +347,12 @@ class Circle
|
|||
}
|
||||
|
||||
foreach ($contacts as $cid) {
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $cdata['user']], Database::INSERT_IGNORE);
|
||||
DBA::insert('group_member', ['gid' => $gid, 'contact-id' => $ucid], Database::INSERT_IGNORE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,12 +379,12 @@ class Circle
|
|||
$contactIds = [];
|
||||
|
||||
foreach ($contacts as $cid) {
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($cid, $circle['uid']);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Invalid contact.');
|
||||
}
|
||||
|
||||
$contactIds[] = $cdata['user'];
|
||||
$contactIds[] = $ucid;
|
||||
}
|
||||
|
||||
// Return status of deletion
|
||||
|
|
|
@ -444,12 +444,12 @@ class Contact
|
|||
return false;
|
||||
}
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = self::getUserContactId($cid, $uid);
|
||||
if (!$ucid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$condition = ['id' => $cdata['user'], 'rel' => [self::FOLLOWER, self::FRIEND]];
|
||||
$condition = ['id' => $ucid, 'rel' => [self::FOLLOWER, self::FRIEND]];
|
||||
if ($strict) {
|
||||
$condition = array_merge($condition, ['pending' => false, 'readonly' => false, 'blocked' => false]);
|
||||
}
|
||||
|
@ -495,12 +495,12 @@ class Contact
|
|||
return false;
|
||||
}
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = self::getUserContactId($cid, $uid);
|
||||
if (!$ucid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$condition = ['id' => $cdata['user'], 'rel' => [self::SHARING, self::FRIEND]];
|
||||
$condition = ['id' => $ucid, 'rel' => [self::SHARING, self::FRIEND]];
|
||||
if ($strict) {
|
||||
$condition = array_merge($condition, ['pending' => false, 'readonly' => false, 'blocked' => false]);
|
||||
}
|
||||
|
@ -671,6 +671,32 @@ class Contact
|
|||
return ['public' => $pcid, 'user' => $ucid];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public contact id of a provided contact id
|
||||
*
|
||||
* @param integer $cid
|
||||
* @param integer $uid
|
||||
* @return integer
|
||||
*/
|
||||
public static function getPublicContactId(int $cid, int $uid): int
|
||||
{
|
||||
$contact = DBA::selectFirst('account-user-view', ['pid'], ['id' => $cid, 'uid' => [0, $uid]]);
|
||||
return $contact['pid'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user contact id of a provided contact id
|
||||
*
|
||||
* @param integer $cid
|
||||
* @param integer $uid
|
||||
* @return integer
|
||||
*/
|
||||
public static function getUserContactId(int $cid, int $uid): int
|
||||
{
|
||||
$data = self::getPublicAndUserContactID($cid, $uid);
|
||||
return $data['user'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for "getPublicAndUserContactID"
|
||||
*
|
||||
|
@ -968,13 +994,13 @@ class Contact
|
|||
}
|
||||
|
||||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
if ($pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $pcid, $contact['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
self::removeSharer($contact);
|
||||
self::removeSharer($contact, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -998,13 +1024,13 @@ class Contact
|
|||
}
|
||||
|
||||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND])) {
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
if ($pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $pcid, $contact['uid']);
|
||||
}
|
||||
}
|
||||
|
||||
self::removeFollower($contact);
|
||||
self::removeFollower($contact, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1025,14 +1051,14 @@ class Contact
|
|||
throw new \InvalidArgumentException('Unexpected public contact record');
|
||||
}
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
|
||||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND]) && !empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']);
|
||||
if (in_array($contact['rel'], [self::SHARING, self::FRIEND]) && $pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\Unfollow', $pcid, $contact['uid']);
|
||||
}
|
||||
|
||||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND]) && !empty($cdata['public'])) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
|
||||
if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND]) && $pcid) {
|
||||
Worker::add(Worker::PRIORITY_HIGH, 'Contact\RevokeFollow', $pcid, $contact['uid']);
|
||||
}
|
||||
|
||||
self::remove($contact['id']);
|
||||
|
@ -1547,24 +1573,25 @@ class Contact
|
|||
/**
|
||||
* Returns posts from a given contact url
|
||||
*
|
||||
* @param string $contact_url Contact URL
|
||||
* @param bool $thread_mode
|
||||
* @param int $update Update mode
|
||||
* @param int $parent Item parent ID for the update mode
|
||||
* @param bool $only_media Only display media content
|
||||
* @param string $contact_url Contact URL
|
||||
* @param int $uid User ID
|
||||
* @param bool $only_media Only display media content
|
||||
* @param string $last_created Newest creation date, used for paging
|
||||
* @return string posts in HTML
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getPostsFromUrl(string $contact_url, int $uid, bool $only_media = false): string
|
||||
public static function getPostsFromUrl(string $contact_url, int $uid, bool $only_media = false, string $last_created = null): string
|
||||
{
|
||||
return self::getPostsFromId(self::getIdForURL($contact_url), $uid, $only_media);
|
||||
return self::getPostsFromId(self::getIdForURL($contact_url), $uid, $only_media, $last_created);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns posts from a given contact id
|
||||
*
|
||||
* @param int $cid Contact ID
|
||||
* @param bool $only_media Only display media content
|
||||
* @param int $cid Contact ID
|
||||
* @param int $uid User ID
|
||||
* @param bool $only_media Only display media content
|
||||
* @param string $last_created Newest creation date, used for paging
|
||||
* @return string posts in HTML
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
@ -2666,6 +2693,14 @@ class Contact
|
|||
|
||||
$data = Probe::uri($contact['url'], $network, $contact['uid']);
|
||||
|
||||
if (in_array($data['network'], Protocol::FEDERATED) && (parse_url($data['url'], PHP_URL_SCHEME) == 'http')) {
|
||||
$ssl_url = str_replace('http://', 'https://', $contact['url']);
|
||||
$ssl_data = Probe::uri($ssl_url, $network, $contact['uid']);
|
||||
if (($ssl_data['network'] == $data['network']) && (parse_url($ssl_data['url'], PHP_URL_SCHEME) != 'http')) {
|
||||
$data = $ssl_data;
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['network'] == Protocol::DIASPORA) {
|
||||
try {
|
||||
DI::dsprContact()->updateFromProbeArray($data);
|
||||
|
@ -2824,7 +2859,7 @@ class Contact
|
|||
// We must not try to update relay contacts via probe. They are no real contacts.
|
||||
// See Relay::updateContact() for more details.
|
||||
// We check after the probing to be able to correct falsely detected contact types.
|
||||
if (($contact['contact-type'] == self::TYPE_RELAY) && Strings::compareLink($contact['url'], $contact['baseurl']) &&
|
||||
if (($contact['contact-type'] == self::TYPE_RELAY) && Strings::compareLink($contact['url'], $contact['baseurl'] ?? '') &&
|
||||
(!Strings::compareLink($ret['url'], $contact['url']) || in_array($ret['network'], [Protocol::FEED, Protocol::PHANTOM]))
|
||||
) {
|
||||
if (GServer::reachable($contact)) {
|
||||
|
@ -3013,6 +3048,10 @@ class Contact
|
|||
*/
|
||||
public static function getProtocol(string $url, string $network): string
|
||||
{
|
||||
if (self::isLocal($url)) {
|
||||
return Protocol::ACTIVITYPUB;
|
||||
}
|
||||
|
||||
if ($network != Protocol::DFRN) {
|
||||
return $network;
|
||||
}
|
||||
|
@ -3404,16 +3443,21 @@ class Contact
|
|||
* Update the local relationship when a local user loses a follower
|
||||
*
|
||||
* @param array $contact User-specific contact (uid != 0) array
|
||||
* @param bool $delete Delete if set, otherwise set relation to "nothing" when contact had been a follower
|
||||
* @return void
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function removeFollower(array $contact)
|
||||
public static function removeFollower(array $contact, bool $delete = true)
|
||||
{
|
||||
if (in_array($contact['rel'] ?? [], [self::FRIEND, self::SHARING])) {
|
||||
self::update(['rel' => self::SHARING], ['id' => $contact['id']]);
|
||||
} elseif (!empty($contact['id'])) {
|
||||
self::remove($contact['id']);
|
||||
if ($delete) {
|
||||
self::remove($contact['id']);
|
||||
} else {
|
||||
self::update(['rel' => self::NOTHING, 'pending' => false], ['id' => $contact['id']]);
|
||||
}
|
||||
} else {
|
||||
DI::logger()->info('Couldn\'t remove follower because of invalid contact array', ['contact' => $contact]);
|
||||
return;
|
||||
|
@ -3423,9 +3467,9 @@ class Contact
|
|||
|
||||
self::clearFollowerFollowingEndpointCache($contact['uid']);
|
||||
|
||||
$cdata = self::getPublicAndUserContactID($contact['id'], $contact['uid']);
|
||||
if (!empty($cdata['public'])) {
|
||||
DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $cdata['public']]);
|
||||
$pcid = self::getPublicContactId($contact['id'], $contact['uid']);
|
||||
if ($pcid) {
|
||||
DI::notification()->deleteForUserByVerb($contact['uid'], Activity::FOLLOW, ['actor-id' => $pcid]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3434,14 +3478,19 @@ class Contact
|
|||
* Removes the contact for sharing-only protocols (feed and mail).
|
||||
*
|
||||
* @param array $contact User-specific contact (uid != 0) array
|
||||
* @param bool $delete Delete if set, otherwise set relation to "nothing" when contact had been a sharer
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
public static function removeSharer(array $contact)
|
||||
public static function removeSharer(array $contact, bool $delete = true)
|
||||
{
|
||||
self::clearFollowerFollowingEndpointCache($contact['uid']);
|
||||
|
||||
if ($contact['rel'] == self::SHARING || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) {
|
||||
self::remove($contact['id']);
|
||||
if (in_array($contact['rel'], [self::SHARING, self::NOTHING]) || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) {
|
||||
if ($delete) {
|
||||
self::remove($contact['id']);
|
||||
} else {
|
||||
self::update(['rel' => self::NOTHING, 'pending' => false], ['id' => $contact['id']]);
|
||||
}
|
||||
} else {
|
||||
self::update(['rel' => self::FOLLOWER, 'pending' => false], ['id' => $contact['id']]);
|
||||
}
|
||||
|
@ -3572,6 +3621,9 @@ class Contact
|
|||
}
|
||||
|
||||
$contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'alias', 'uid'], ['id' => $cid]);
|
||||
if (empty($contact)) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return self::magicLinkByContact($contact, $url);
|
||||
}
|
||||
|
|
|
@ -281,12 +281,12 @@ class User
|
|||
*/
|
||||
public static function setCollapsed(int $cid, int $uid, bool $collapsed)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['collapsed' => $collapsed], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['collapsed' => $collapsed], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,21 +300,13 @@ class User
|
|||
*/
|
||||
public static function isCollapsed(int $cid, int $uid): bool
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$collapsed = false;
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
$collapsed = (bool) $public_contact['collapsed'];
|
||||
}
|
||||
}
|
||||
|
||||
return $collapsed;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['collapsed'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,12 +320,12 @@ class User
|
|||
*/
|
||||
public static function setChannelFrequency(int $cid, int $uid, int $frequency)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['channel-frequency' => $frequency], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['channel-frequency' => $frequency], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,21 +339,13 @@ class User
|
|||
*/
|
||||
public static function getChannelFrequency(int $cid, int $uid): int
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$frequency = self::FREQUENCY_DEFAULT;
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-frequency'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
$frequency = $public_contact['channel-frequency'] ?? self::FREQUENCY_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
return $frequency;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-frequency'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['channel-frequency'] ?? self::FREQUENCY_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -375,12 +359,12 @@ class User
|
|||
*/
|
||||
public static function setChannelOnly(int $cid, int $uid, bool $isChannelOnly)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['channel-only' => $isChannelOnly], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['channel-only' => $isChannelOnly], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,21 +378,13 @@ class User
|
|||
*/
|
||||
public static function getChannelOnly(int $cid, int $uid): bool
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
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;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['channel-only'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['channel-only'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -422,12 +398,12 @@ class User
|
|||
*/
|
||||
public static function setIsBlocked(int $cid, int $uid, bool $blocked)
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBA::update('user-contact', ['is-blocked' => $blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
|
||||
DBA::update('user-contact', ['is-blocked' => $blocked], ['cid' => $pcid, 'uid' => $uid], true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -440,18 +416,12 @@ class User
|
|||
*/
|
||||
public static function isIsBlocked(int $cid, int $uid): bool
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (empty($cdata)) {
|
||||
$pcid = Contact::getPublicContactId($cid, $uid);
|
||||
if (!$pcid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($cdata['public'])) {
|
||||
$public_contact = DBA::selectFirst('user-contact', ['is-blocked'], ['cid' => $cdata['public'], 'uid' => $uid]);
|
||||
if (DBA::isResult($public_contact)) {
|
||||
return $public_contact['is-blocked'];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
$public_contact = DBA::selectFirst('user-contact', ['is-blocked'], ['cid' => $pcid, 'uid' => $uid]);
|
||||
return $public_contact['is-blocked'] ?? false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,9 +87,11 @@ class GServer
|
|||
|
||||
// Standardized endpoints
|
||||
const DETECT_STATISTICS_JSON = 100;
|
||||
const DETECT_NODEINFO_1 = 101;
|
||||
const DETECT_NODEINFO_2 = 102;
|
||||
const DETECT_NODEINFO_210 = 103;
|
||||
const DETECT_NODEINFO_10 = 101; // Nodeinfo Version 1.0
|
||||
const DETECT_NODEINFO_20 = 102; // Nodeinfo Version 2.0
|
||||
const DETECT_NODEINFO2_10 = 103; // Nodeinfo2 Version 1.0
|
||||
const DETECT_NODEINFO_21 = 104; // Nodeinfo Version 2.1
|
||||
const DETECT_NODEINFO_22 = 105; // Nodeinfo Version 2.2
|
||||
|
||||
/**
|
||||
* Check for the existence of a server and adds it in the background if not existant
|
||||
|
@ -612,7 +614,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, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/nodeinfo', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if ($curlResult->isTimeout()) {
|
||||
self::setFailureByUrl($url);
|
||||
return false;
|
||||
|
@ -621,10 +623,11 @@ class GServer
|
|||
if (!empty($network) && !in_array($network, Protocol::NATIVE_SUPPORT)) {
|
||||
$serverdata = ['detection-method' => self::DETECT_MANUAL, 'network' => $network, 'platform' => '', 'version' => '', 'site_name' => '', 'info' => ''];
|
||||
} else {
|
||||
$serverdata = self::parseNodeinfo210($curlResult);
|
||||
if (empty($serverdata)) {
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/nodeinfo', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$serverdata = self::fetchNodeinfo($url, $curlResult);
|
||||
$serverdata = self::parseNodeinfo($url, $curlResult);
|
||||
|
||||
if (empty($serverdata) || !in_array($serverdata['detection-method'], [self::DETECT_NODEINFO_20, self::DETECT_NODEINFO_21, self::DETECT_NODEINFO_22])) {
|
||||
$curlResult = DI::httpClient()->get($url . '/.well-known/x-nodeinfo2', HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
$serverdata = self::parseNodeinfo2($curlResult) ?: $serverdata;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1049,7 +1052,9 @@ class GServer
|
|||
}
|
||||
|
||||
/**
|
||||
* Detect server type by using the nodeinfo data
|
||||
* Parses Nodeinfo
|
||||
*
|
||||
* @see https://github.com/jhass/nodeinfo
|
||||
*
|
||||
* @param string $url address of the server
|
||||
* @param ICanHandleHttpResponses $httpResult
|
||||
|
@ -1058,7 +1063,7 @@ class GServer
|
|||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function fetchNodeinfo(string $url, ICanHandleHttpResponses $httpResult): array
|
||||
private static function parseNodeinfo(string $url, ICanHandleHttpResponses $httpResult): array
|
||||
{
|
||||
if (!$httpResult->isSuccess()) {
|
||||
return [];
|
||||
|
@ -1072,6 +1077,7 @@ class GServer
|
|||
|
||||
$nodeinfo1_url = '';
|
||||
$nodeinfo2_url = '';
|
||||
$detection_method = self::DETECT_MANUAL;
|
||||
|
||||
foreach ($nodeinfo['links'] as $link) {
|
||||
if (!is_array($link) || empty($link['rel']) || empty($link['href'])) {
|
||||
|
@ -1081,8 +1087,15 @@ class GServer
|
|||
|
||||
if ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/1.0') {
|
||||
$nodeinfo1_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
} elseif ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.0') {
|
||||
} elseif (($detection_method < self::DETECT_NODEINFO_20) && ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.0')) {
|
||||
$nodeinfo2_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
$detection_method = self::DETECT_NODEINFO_20;
|
||||
} elseif (($detection_method < self::DETECT_NODEINFO_21) && ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.1')) {
|
||||
$nodeinfo2_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
$detection_method = self::DETECT_NODEINFO_21;
|
||||
} elseif (($detection_method < self::DETECT_NODEINFO_22) && ($link['rel'] == 'http://nodeinfo.diaspora.software/ns/schema/2.2')) {
|
||||
$nodeinfo2_url = Network::addBasePath($link['href'], $httpResult->getUrl());
|
||||
$detection_method = self::DETECT_NODEINFO_22;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1093,18 +1106,20 @@ class GServer
|
|||
$server = [];
|
||||
|
||||
if (!empty($nodeinfo2_url)) {
|
||||
$server = self::parseNodeinfo2($nodeinfo2_url);
|
||||
$server = self::parseNodeinfo_2($nodeinfo2_url, $detection_method);
|
||||
}
|
||||
|
||||
if (empty($server) && !empty($nodeinfo1_url)) {
|
||||
$server = self::parseNodeinfo1($nodeinfo1_url);
|
||||
$server = self::parseNodeinfo_1($nodeinfo1_url);
|
||||
}
|
||||
|
||||
return $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Nodeinfo 1
|
||||
* Parses Nodeinfo with the version 1.0
|
||||
*
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/1.0
|
||||
*
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
*
|
||||
|
@ -1112,7 +1127,7 @@ class GServer
|
|||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function parseNodeinfo1(string $nodeinfo_url): array
|
||||
private static function parseNodeinfo_1(string $nodeinfo_url): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
|
@ -1125,8 +1140,10 @@ class GServer
|
|||
return [];
|
||||
}
|
||||
|
||||
$server = ['detection-method' => self::DETECT_NODEINFO_1,
|
||||
'register_policy' => Register::CLOSED];
|
||||
$server = [
|
||||
'detection-method' => self::DETECT_NODEINFO_10,
|
||||
'register_policy' => Register::CLOSED
|
||||
];
|
||||
|
||||
if (!empty($nodeinfo['openRegistrations'])) {
|
||||
$server['register_policy'] = Register::OPEN;
|
||||
|
@ -1202,17 +1219,20 @@ class GServer
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses Nodeinfo 2
|
||||
* Parses Nodeinfo with the versions 2.0, 2.1 and 2.2
|
||||
*
|
||||
* @see https://git.feneas.org/jaywink/nodeinfo2
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/2.0
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/2.1
|
||||
* @see https://github.com/jhass/nodeinfo/tree/main/schemas/2.2
|
||||
*
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
* @param int $detection_method nodeinfo version
|
||||
*
|
||||
* @return array Server data
|
||||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function parseNodeinfo2(string $nodeinfo_url): array
|
||||
private static function parseNodeinfo_2(string $nodeinfo_url, int $detection_method): array
|
||||
{
|
||||
$curlResult = DI::httpClient()->get($nodeinfo_url, HttpClientAccept::JSON, [HttpClientOptions::REQUEST => HttpClientRequest::SERVERINFO]);
|
||||
if (!$curlResult->isSuccess()) {
|
||||
|
@ -1225,7 +1245,7 @@ class GServer
|
|||
}
|
||||
|
||||
$server = [
|
||||
'detection-method' => self::DETECT_NODEINFO_2,
|
||||
'detection-method' => $detection_method,
|
||||
'register_policy' => Register::CLOSED,
|
||||
'platform' => 'unknown',
|
||||
];
|
||||
|
@ -1234,6 +1254,15 @@ class GServer
|
|||
$server['register_policy'] = Register::OPEN;
|
||||
}
|
||||
|
||||
if (!empty($nodeinfo['instance'])) {
|
||||
if (!empty($nodeinfo['instance']['name'])) {
|
||||
$server['site_name'] = $nodeinfo['instance']['name'];
|
||||
}
|
||||
if (!empty($nodeinfo['instance']['description'])) {
|
||||
$server['info'] = $nodeinfo['instance']['description'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($nodeinfo['software'])) {
|
||||
if (isset($nodeinfo['software']['name'])) {
|
||||
$server['platform'] = strtolower($nodeinfo['software']['name']);
|
||||
|
@ -1249,6 +1278,13 @@ class GServer
|
|||
if (($server['platform'] == 'mastodon') && substr($nodeinfo['software']['version'], -5) == '-qoto') {
|
||||
$server['platform'] = 'qoto';
|
||||
}
|
||||
|
||||
if (isset($nodeinfo['software']['repository'])) {
|
||||
$server['repository'] = strtolower($nodeinfo['software']['repository']);
|
||||
}
|
||||
if (isset($nodeinfo['software']['homepage'])) {
|
||||
$server['homepage'] = strtolower($nodeinfo['software']['homepage']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1260,6 +1296,9 @@ class GServer
|
|||
if (!empty($nodeinfo['metadata']['nodeName'])) {
|
||||
$server['site_name'] = $nodeinfo['metadata']['nodeName'];
|
||||
}
|
||||
if (!empty($nodeinfo['metadata']['nodeDescription'])) {
|
||||
$server['info'] = $nodeinfo['metadata']['nodeDescription'];
|
||||
}
|
||||
|
||||
if (!empty($nodeinfo['usage']['users']['total'])) {
|
||||
$server['registered-users'] = max($nodeinfo['usage']['users']['total'], 1);
|
||||
|
@ -1320,9 +1359,9 @@ class GServer
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses NodeInfo2 protocol 1.0
|
||||
* Parses NodeInfo2
|
||||
*
|
||||
* @see https://github.com/jaywink/nodeinfo2/blob/master/PROTOCOL.md
|
||||
* @see https://github.com/jaywink/nodeinfo2
|
||||
*
|
||||
* @param string $nodeinfo_url address of the nodeinfo path
|
||||
*
|
||||
|
@ -1330,7 +1369,7 @@ class GServer
|
|||
*
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
private static function parseNodeinfo210(ICanHandleHttpResponses $httpResult): array
|
||||
private static function parseNodeinfo2(ICanHandleHttpResponses $httpResult): array
|
||||
{
|
||||
if (!$httpResult->isSuccess()) {
|
||||
return [];
|
||||
|
@ -1342,8 +1381,10 @@ class GServer
|
|||
return [];
|
||||
}
|
||||
|
||||
$server = ['detection-method' => self::DETECT_NODEINFO_210,
|
||||
'register_policy' => Register::CLOSED];
|
||||
$server = [
|
||||
'detection-method' => self::DETECT_NODEINFO2_10,
|
||||
'register_policy' => Register::CLOSED
|
||||
];
|
||||
|
||||
if (!empty($nodeinfo['openRegistrations'])) {
|
||||
$server['register_policy'] = Register::OPEN;
|
||||
|
@ -2570,6 +2611,10 @@ class GServer
|
|||
return;
|
||||
}
|
||||
|
||||
if ($data['openwebauth'] == $gserver['openwebauth']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$serverdata = self::getZotData($gserver['url'], []);
|
||||
if (empty($serverdata)) {
|
||||
$serverdata = ['openwebauth' => $data['openwebauth']];
|
||||
|
|
|
@ -198,6 +198,10 @@ class Item
|
|||
$fields['external-id'] = ItemURI::getIdByURI($fields['extid']);
|
||||
}
|
||||
|
||||
if (!empty($fields['replies'])) {
|
||||
$fields['replies-id'] = ItemURI::getIdByURI($fields['replies']);
|
||||
}
|
||||
|
||||
if (!empty($fields['verb'])) {
|
||||
$fields['vid'] = Verb::getID($fields['verb']);
|
||||
}
|
||||
|
@ -415,8 +419,24 @@ class Item
|
|||
self::markForDeletion(['parent' => $item['parent'], 'deleted' => false], $priority);
|
||||
}
|
||||
|
||||
if ($item['uid'] == 0 && $item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = DI::keyValue()->get('nodeinfo_total_posts') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_total_posts', $posts - 1);
|
||||
} elseif ($item['uid'] == 0 && $item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = DI::keyValue()->get('nodeinfo_total_comments') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_total_comments', $comments - 1);
|
||||
}
|
||||
|
||||
// Is it our comment and/or our thread?
|
||||
if (($item['origin'] || $parent['origin']) && ($item['uid'] != 0)) {
|
||||
if ($item['origin'] && $item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = DI::keyValue()->get('nodeinfo_local_posts') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_local_posts', $posts - 1);
|
||||
} elseif ($item['origin'] && $item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = DI::keyValue()->get('nodeinfo_local_comments') ?? 0;
|
||||
DI::keyValue()->set('nodeinfo_local_comments', $comments - 1);
|
||||
}
|
||||
|
||||
// When we delete the original post we will delete all existing copies on the server as well
|
||||
self::markForDeletion(['uri-id' => $item['uri-id'], 'deleted' => false], $priority);
|
||||
|
||||
|
@ -536,9 +556,9 @@ class Item
|
|||
}
|
||||
|
||||
if (!empty($item['causer-id']) && Contact::isSharing($item['causer-id'], $item['uid'], true)) {
|
||||
$cdata = Contact::getPublicAndUserContactID($item['causer-id'], $item['uid']);
|
||||
if (!empty($cdata['user'])) {
|
||||
return $cdata['user'];
|
||||
$ucid = Contact::getUserContactId($item['causer-id'], $item['uid']);
|
||||
if ($ucid) {
|
||||
return $ucid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1077,6 +1097,10 @@ class Item
|
|||
$parent_id = 0;
|
||||
$parent_origin = $item['origin'];
|
||||
|
||||
if ($item['wall'] && empty($item['context'])) {
|
||||
$item['context'] = $item['parent-uri'] . '#context';
|
||||
}
|
||||
|
||||
if ($item['wall'] && empty($item['conversation'])) {
|
||||
$item['conversation'] = $item['parent-uri'] . '#context';
|
||||
}
|
||||
|
@ -1098,6 +1122,10 @@ class Item
|
|||
$item['conversation-id'] = ItemURI::getIdByURI($item['conversation']);
|
||||
}
|
||||
|
||||
if (!empty($item['context']) && empty($item['context-id'])) {
|
||||
$item['context-id'] = ItemURI::getIdByURI($item['context']);
|
||||
}
|
||||
|
||||
// Is this item available in the global items (with uid=0)?
|
||||
if ($item['uid'] == 0) {
|
||||
$item['global'] = true;
|
||||
|
@ -1165,6 +1193,10 @@ class Item
|
|||
$item['external-id'] = ItemURI::getIdByURI($item['extid']);
|
||||
}
|
||||
|
||||
if (!empty($item['replies'])) {
|
||||
$item['replies-id'] = ItemURI::getIdByURI($item['replies']);
|
||||
}
|
||||
|
||||
if ($item['verb'] == Activity::ANNOUNCE) {
|
||||
self::setOwnerforResharedItem($item);
|
||||
}
|
||||
|
@ -1334,6 +1366,14 @@ class Item
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ($posted_item['origin'] && $posted_item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = (int)(DI::keyValue()->get('nodeinfo_local_posts') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_local_posts', $posts + 1);
|
||||
} elseif ($posted_item['origin'] && $posted_item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = (int)(DI::keyValue()->get('nodeinfo_local_comments') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_local_comments', $comments + 1);
|
||||
}
|
||||
|
||||
Post\Origin::insert($posted_item);
|
||||
|
||||
// update the commented timestamp on the parent
|
||||
|
@ -1423,6 +1463,14 @@ class Item
|
|||
}
|
||||
|
||||
if ($inserted) {
|
||||
if ($posted_item['gravity'] == self::GRAVITY_PARENT) {
|
||||
$posts = (int)(DI::keyValue()->get('nodeinfo_total_posts') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_total_posts', $posts + 1);
|
||||
} elseif ($posted_item['gravity'] == self::GRAVITY_COMMENT) {
|
||||
$comments = (int)(DI::keyValue()->get('nodeinfo_total_comments') ?? 0);
|
||||
DI::keyValue()->set('nodeinfo_total_comments', $comments + 1);
|
||||
}
|
||||
|
||||
// Fill the cache with the rendered content.
|
||||
if (in_array($posted_item['gravity'], [self::GRAVITY_PARENT, self::GRAVITY_COMMENT])) {
|
||||
self::updateDisplayCache($posted_item['uri-id']);
|
||||
|
@ -2584,12 +2632,12 @@ class Item
|
|||
return;
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($item['author-id'], $item['uid']);
|
||||
if (empty($cdata['user']) || ($cdata['user'] != $item['contact-id'])) {
|
||||
$ucid = Contact::getUserContactId($item['author-id'], $item['uid']);
|
||||
if (!$ucid || ($ucid != $item['contact-id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DBA::exists('contact', ['id' => $cdata['user'], 'remote_self' => LocalRelationship::MIRROR_NATIVE_RESHARE])) {
|
||||
if (!DBA::exists('contact', ['id' => $ucid, 'remote_self' => LocalRelationship::MIRROR_NATIVE_RESHARE])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4118,6 +4166,10 @@ class Item
|
|||
return $item_id;
|
||||
}
|
||||
|
||||
if (ActivityPub\Processor::alreadyKnown($uri, '')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$hookData = [
|
||||
'uri' => $uri,
|
||||
'uid' => $uid,
|
||||
|
@ -4213,4 +4265,22 @@ class Item
|
|||
Logger::warning('Post does not exist although it was supposed to had been fetched.', ['id' => $id, 'url' => $url, 'uid' => $uid]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function incrementInbound(string $network)
|
||||
{
|
||||
$packets = (int)(DI::keyValue()->get('stats_packets_inbound_' . $network) ?? 0);
|
||||
if ($packets >= PHP_INT_MAX) {
|
||||
$packets = 0;
|
||||
}
|
||||
DI::keyValue()->set('stats_packets_inbound_' . $network, $packets + 1);
|
||||
}
|
||||
|
||||
public static function incrementOutbound(string $network)
|
||||
{
|
||||
$packets = (int)(DI::keyValue()->get('stats_packets_outbound_' . $network) ?? 0);
|
||||
if ($packets >= PHP_INT_MAX) {
|
||||
$packets = 0;
|
||||
}
|
||||
DI::keyValue()->set('stats_packets_outbound_' . $network, $packets + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ class Nodeinfo
|
|||
return;
|
||||
}
|
||||
|
||||
$logger->info('User statistics - start');
|
||||
|
||||
$userStats = User::getStatistics();
|
||||
|
||||
DI::keyValue()->set('nodeinfo_total_users', $userStats['total_users']);
|
||||
|
@ -60,21 +62,26 @@ class Nodeinfo
|
|||
DI::keyValue()->set('nodeinfo_active_users_monthly', $userStats['active_users_monthly']);
|
||||
DI::keyValue()->set('nodeinfo_active_users_weekly', $userStats['active_users_weekly']);
|
||||
|
||||
$logger->info('user statistics', $userStats);
|
||||
$logger->info('user statistics - done', $userStats);
|
||||
|
||||
$posts = DBA::count('post-thread', ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE NOT `deleted` AND `origin`)"]);
|
||||
$comments = DBA::count('post', ["NOT `deleted` AND `gravity` = ? AND `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)", Item::GRAVITY_COMMENT]);
|
||||
DI::keyValue()->set('nodeinfo_local_posts', $posts);
|
||||
DI::keyValue()->set('nodeinfo_local_comments', $comments);
|
||||
|
||||
$logger->info('User activity', ['posts' => $posts, 'comments' => $comments]);
|
||||
$posts = DBA::count('post', ['deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||
$comments = DBA::count('post', ['deleted' => false, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||
DI::keyValue()->set('nodeinfo_total_posts', $posts);
|
||||
DI::keyValue()->set('nodeinfo_total_comments', $comments);
|
||||
|
||||
$logger->info('Post statistics - done', ['posts' => $posts, 'comments' => $comments]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the supported services
|
||||
*
|
||||
* @return Object with supported services
|
||||
*/
|
||||
*/
|
||||
public static function getUsage(bool $version2 = false)
|
||||
{
|
||||
$config = DI::config();
|
||||
|
@ -101,7 +108,7 @@ class Nodeinfo
|
|||
* Return the supported services
|
||||
*
|
||||
* @return array with supported services
|
||||
*/
|
||||
*/
|
||||
public static function getServices(): array
|
||||
{
|
||||
$services = [
|
||||
|
|
|
@ -141,7 +141,7 @@ class Content
|
|||
if ($uid != 0) {
|
||||
$condition = ["MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE) AND (NOT `restricted` OR `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `uid` = ?))", $search, $uid];
|
||||
} else {
|
||||
$condition = ["MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE) AND NOT `restricted", $search];
|
||||
$condition = ["MATCH (`searchtext`) AGAINST (? IN BOOLEAN MODE) AND NOT `restricted`", $search];
|
||||
}
|
||||
return DBA::count(SearchIndex::getSearchTable(), $condition);
|
||||
}
|
||||
|
|
|
@ -88,8 +88,8 @@ class Media
|
|||
// "document" has got the lowest priority. So when the same file is both attached as document
|
||||
// and embedded as picture then we only store the picture or replace the document
|
||||
$found = DBA::selectFirst('post-media', ['type'], ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
||||
if (!$force && !empty($found) && (($found['type'] != self::DOCUMENT) || ($media['type'] == self::DOCUMENT))) {
|
||||
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
||||
if (!$force && !empty($found) && (!in_array($found['type'], [self::UNKNOWN, self::DOCUMENT]) || ($media['type'] == self::DOCUMENT))) {
|
||||
Logger::info('Media already exists', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'found' => $found['type'], 'new' => $media['type']]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -444,42 +444,46 @@ class Media
|
|||
return $data;
|
||||
}
|
||||
|
||||
$type = explode('/', current(explode(';', $data['mimetype'])));
|
||||
$data['type'] = self::getType($data['mimetype']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function getType(string $mimeType): int
|
||||
{
|
||||
$type = explode('/', current(explode(';', $mimeType)));
|
||||
if (count($type) < 2) {
|
||||
Logger::info('Unknown MimeType', ['type' => $type, 'media' => $data]);
|
||||
$data['type'] = self::UNKNOWN;
|
||||
return $data;
|
||||
Logger::info('Unknown MimeType', ['type' => $type, 'media' => $mimeType]);
|
||||
return self::UNKNOWN;
|
||||
}
|
||||
|
||||
$filetype = strtolower($type[0]);
|
||||
$subtype = strtolower($type[1]);
|
||||
|
||||
if ($filetype == 'image') {
|
||||
$data['type'] = self::IMAGE;
|
||||
$type = self::IMAGE;
|
||||
} elseif ($filetype == 'video') {
|
||||
$data['type'] = self::VIDEO;
|
||||
$type = self::VIDEO;
|
||||
} elseif ($filetype == 'audio') {
|
||||
$data['type'] = self::AUDIO;
|
||||
$type = self::AUDIO;
|
||||
} elseif (($filetype == 'text') && ($subtype == 'html')) {
|
||||
$data['type'] = self::HTML;
|
||||
$type = self::HTML;
|
||||
} elseif (($filetype == 'text') && ($subtype == 'xml')) {
|
||||
$data['type'] = self::XML;
|
||||
$type = self::XML;
|
||||
} elseif (($filetype == 'text') && ($subtype == 'plain')) {
|
||||
$data['type'] = self::PLAIN;
|
||||
$type = self::PLAIN;
|
||||
} elseif ($filetype == 'text') {
|
||||
$data['type'] = self::TEXT;
|
||||
$type = self::TEXT;
|
||||
} elseif (($filetype == 'application') && ($subtype == 'x-bittorrent')) {
|
||||
$data['type'] = self::TORRENT;
|
||||
$type = self::TORRENT;
|
||||
} elseif ($filetype == 'application') {
|
||||
$data['type'] = self::APPLICATION;
|
||||
$type = self::APPLICATION;
|
||||
} else {
|
||||
$data['type'] = self::UNKNOWN;
|
||||
Logger::info('Unknown type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $data]);
|
||||
return $data;
|
||||
$type = self::UNKNOWN;
|
||||
Logger::info('Unknown type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $mimeType]);
|
||||
}
|
||||
|
||||
Logger::debug('Detected type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $data]);
|
||||
return $data;
|
||||
Logger::debug('Detected type', ['filetype' => $filetype, 'subtype' => $subtype, 'media' => $mimeType]);
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -622,8 +622,10 @@ class Profile
|
|||
$bd_format = DI::l10n()->t('g A l F d'); // 8 AM Friday January 18
|
||||
$classtoday = '';
|
||||
|
||||
$condition = ["`uid` = ? AND `type` != 'birthday' AND `start` < ? AND `start` >= ?",
|
||||
$uid, DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now - 1 days')];
|
||||
$condition = [
|
||||
"`uid` = ? AND `type` != 'birthday' AND `start` < ? AND `start` >= ?",
|
||||
$uid, DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now - 1 days')
|
||||
];
|
||||
$s = DBA::select('event', [], $condition, ['order' => ['start']]);
|
||||
|
||||
$r = [];
|
||||
|
@ -633,9 +635,11 @@ class Profile
|
|||
$total = 0;
|
||||
|
||||
while ($rr = DBA::fetch($s)) {
|
||||
$condition = ['parent-uri' => $rr['uri'], 'uid' => $rr['uid'], 'author-id' => $pcid,
|
||||
$condition = [
|
||||
'parent-uri' => $rr['uri'], 'uid' => $rr['uid'], 'author-id' => $pcid,
|
||||
'vid' => [Verb::getID(Activity::ATTEND), Verb::getID(Activity::ATTENDMAYBE)],
|
||||
'visible' => true, 'deleted' => false];
|
||||
'visible' => true, 'deleted' => false
|
||||
];
|
||||
if (!Post::exists($condition)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -724,7 +728,8 @@ class Profile
|
|||
if (!empty($search)) {
|
||||
$publish = (DI::config()->get('system', 'publish_all') ? '' : "AND `publish` ");
|
||||
$searchTerm = '%' . $search . '%';
|
||||
$condition = ["`verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`
|
||||
$condition = [
|
||||
"`verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired`
|
||||
$publish
|
||||
AND ((`name` LIKE ?) OR
|
||||
(`nickname` LIKE ?) OR
|
||||
|
@ -735,7 +740,8 @@ class Profile
|
|||
(`pub_keywords` LIKE ?) OR
|
||||
(`prv_keywords` LIKE ?))",
|
||||
$searchTerm, $searchTerm, $searchTerm, $searchTerm,
|
||||
$searchTerm, $searchTerm, $searchTerm, $searchTerm];
|
||||
$searchTerm, $searchTerm, $searchTerm, $searchTerm
|
||||
];
|
||||
} else {
|
||||
$condition = ['verified' => true, 'blocked' => false, 'account_removed' => false, 'account_expired' => false];
|
||||
if (!DI::config()->get('system', 'publish_all')) {
|
||||
|
@ -838,4 +844,44 @@ class Profile
|
|||
DBA::delete('profile', ['id' => $profile['id']]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "about" field with the added responsible relay contact if appropriate.
|
||||
*
|
||||
* @param string $about
|
||||
* @param integer|null $parent_uid
|
||||
* @param integer $account_type
|
||||
* @param string $language
|
||||
* @return string
|
||||
*/
|
||||
public static function addResponsibleRelayContact(string $about = null, int $parent_uid = null, int $account_type, string $language): ?string
|
||||
{
|
||||
if (($account_type != User::ACCOUNT_TYPE_RELAY) || empty($parent_uid)) {
|
||||
return $about;
|
||||
}
|
||||
|
||||
$parent = User::getOwnerDataById($parent_uid);
|
||||
if (strpos($about, $parent['addr']) || strpos($about, $parent['url'])) {
|
||||
return $about;
|
||||
}
|
||||
|
||||
$l10n = DI::l10n()->withLang($language);
|
||||
|
||||
return $about .= "\n" . $l10n->t('Responsible account: %s', $parent['addr']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set "about" field with the added responsible relay contact if appropriate.
|
||||
*
|
||||
* @param integer $uid
|
||||
* @return void
|
||||
*/
|
||||
public static function setResponsibleRelayContact(int $uid)
|
||||
{
|
||||
$owner = User::getOwnerDataById($uid);
|
||||
$about = self::addResponsibleRelayContact($owner['about'], $owner['parent-uid'], $owner['account-type'], $owner['language']);
|
||||
if ($about != $owner['about']) {
|
||||
self::update(['about' => $about], $uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -412,6 +412,29 @@ class User
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user id of a given contact id
|
||||
*
|
||||
* @param int $cid
|
||||
*
|
||||
* @return integer user id
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getIdForContactId(int $cid): int
|
||||
{
|
||||
$account = Contact::selectFirstAccountUser(['pid', 'self', 'uid'], ['id' => $cid]);
|
||||
if (empty($account['pid'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($account['self']) {
|
||||
return $account['uid'];
|
||||
}
|
||||
|
||||
$self = Contact::selectFirstAccountUser(['uid'], ['pid' => $cid, 'self' => true]);
|
||||
return $self['uid'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user based on its email
|
||||
*
|
||||
|
|
|
@ -22,9 +22,11 @@
|
|||
namespace Friendica\Module\ActivityPub;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Module\Special\HTTPException;
|
||||
|
@ -103,6 +105,7 @@ class Inbox extends BaseApi
|
|||
$uid = 0;
|
||||
}
|
||||
|
||||
Item::incrementInbound(Protocol::ACTIVITYPUB);
|
||||
ActivityPub\Receiver::processInbox($postdata, $_SERVER, $uid);
|
||||
|
||||
throw new \Friendica\Network\HTTPException\AcceptedException();
|
||||
|
|
|
@ -28,6 +28,12 @@ use Friendica\Module\BaseAdmin;
|
|||
|
||||
class Index extends BaseAdmin
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
parent::content();
|
||||
|
|
|
@ -30,6 +30,12 @@ use Friendica\Util\Strings;
|
|||
|
||||
class Details extends BaseAdmin
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
parent::content();
|
||||
|
|
|
@ -29,6 +29,12 @@ use Friendica\Util\Strings;
|
|||
|
||||
class Index extends BaseAdmin
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
parent::content();
|
||||
|
|
|
@ -43,9 +43,9 @@ class Block extends BaseApi
|
|||
|
||||
Contact\User::setBlocked($this->parameters['id'], $uid, true);
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($this->parameters['id'], $uid);
|
||||
if (!empty($cdata['user'])) {
|
||||
$contact = Contact::getById($cdata['user']);
|
||||
$ucid = Contact::getUserContactId($this->parameters['id'], $uid);
|
||||
if ($ucid) {
|
||||
$contact = Contact::getById($ucid);
|
||||
if (!empty($contact)) {
|
||||
// Mastodon-expected behavior: relationship is severed on block
|
||||
Contact::terminateFriendship($contact);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon\Accounts;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Content\Widget;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
|
@ -75,6 +75,9 @@ class Followers extends BaseApi
|
|||
$params['order'] = ['pid'];
|
||||
}
|
||||
|
||||
$networks = Widget::unavailableNetworks();
|
||||
$condition = DBA::mergeConditions($condition, array_merge(["NOT `network` IN (" . substr(str_repeat("?, ", count($networks)), 0, -2) . ")"], $networks));
|
||||
|
||||
$accounts = [];
|
||||
|
||||
foreach (Contact::selectAccountToArray(['pid'], $condition, $params) as $follower) {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon\Accounts;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Content\Widget;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
|
@ -75,6 +75,9 @@ class Following extends BaseApi
|
|||
$params['order'] = ['pid'];
|
||||
}
|
||||
|
||||
$networks = Widget::unavailableNetworks();
|
||||
$condition = DBA::mergeConditions($condition, array_merge(["NOT `network` IN (" . substr(str_repeat("?, ", count($networks)), 0, -2) . ")"], $networks));
|
||||
|
||||
$accounts = [];
|
||||
|
||||
foreach (Contact::selectAccountToArray(['pid'], $condition, $params) as $follower) {
|
||||
|
|
|
@ -51,9 +51,9 @@ class Lists extends BaseApi
|
|||
|
||||
$lists = [];
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($id, $uid);
|
||||
if (!empty($cdata['user'])) {
|
||||
$circles = DBA::select('group_member', ['gid'], ['contact-id' => $cdata['user']]);
|
||||
$ucid = Contact::getUserContactId($id, $uid);
|
||||
if ($ucid) {
|
||||
$circles = DBA::select('group_member', ['gid'], ['contact-id' => $ucid]);
|
||||
while ($circle = DBA::fetch($circles)) {
|
||||
$lists[] = DI::mstdnList()->createFromCircleId($circle['gid']);
|
||||
}
|
||||
|
|
|
@ -45,12 +45,12 @@ class Note extends BaseApi
|
|||
'comment' => '',
|
||||
], $request);
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($this->parameters['id'], $uid);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($this->parameters['id'], $uid);
|
||||
if (!$ucid) {
|
||||
$this->logAndJsonError(404, $this->errorFactory->RecordNotFound());
|
||||
}
|
||||
|
||||
Contact::update(['info' => $request['comment']], ['id' => $cdata['user']]);
|
||||
Contact::update(['info' => $request['comment']], ['id' => $ucid]);
|
||||
|
||||
$this->jsonExit(DI::mstdnRelationship()->createFromContactId($this->parameters['id'], $uid)->toArray());
|
||||
}
|
||||
|
|
|
@ -40,12 +40,12 @@ class Unfollow extends BaseApi
|
|||
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($this->parameters['id'], $uid);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($this->parameters['id'], $uid);
|
||||
if (!$ucid) {
|
||||
$this->logAndJsonError(404, $this->errorFactory->RecordNotFound());
|
||||
}
|
||||
|
||||
$contact = Contact::getById($cdata['user']);
|
||||
$contact = Contact::getById($ucid);
|
||||
|
||||
Contact::unfollow($contact);
|
||||
|
||||
|
|
|
@ -100,12 +100,12 @@ class UpdateCredentials extends BaseApi
|
|||
User::update($user, $uid);
|
||||
Profile::update($profile, $uid);
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($owner['id'], $uid);
|
||||
if (empty($cdata)) {
|
||||
$ucid = Contact::getUserContactId($owner['id'], $uid);
|
||||
if (!$ucid) {
|
||||
DI::mstdnError()->InternalError();
|
||||
}
|
||||
|
||||
$account = DI::mstdnAccount()->createFromContactId($cdata['user'], $uid);
|
||||
$account = DI::mstdnAccount()->createFromContactId($ucid, $uid);
|
||||
$this->response->addJsonContent($account->toArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,13 +45,13 @@ class VerifyCredentials extends BaseApi
|
|||
DI::mstdnError()->InternalError();
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($self['id'], $uid);
|
||||
if (empty($cdata)) {
|
||||
$ucid = Contact::getUserContactId($self['id'], $uid);
|
||||
if (!$ucid) {
|
||||
DI::mstdnError()->InternalError();
|
||||
}
|
||||
|
||||
// @todo Support the source property,
|
||||
$account = DI::mstdnAccount()->createFromContactId($cdata['user'], $uid);
|
||||
$account = DI::mstdnAccount()->createFromContactId($ucid, $uid);
|
||||
$this->response->addJsonContent($account->toArray());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon;
|
||||
|
||||
use Friendica\Core\System;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
@ -47,12 +46,12 @@ class FollowRequests extends BaseApi
|
|||
$this->checkAllowedScope(self::SCOPE_FOLLOW);
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($this->parameters['id'], $uid);
|
||||
if (empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($this->parameters['id'], $uid);
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\NotFoundException('Contact not found');
|
||||
}
|
||||
|
||||
$introduction = DI::intro()->selectForContact($cdata['user']);
|
||||
$introduction = DI::intro()->selectForContact($ucid);
|
||||
|
||||
$contactId = $introduction->cid;
|
||||
|
||||
|
|
|
@ -131,12 +131,19 @@ class InstanceV2 extends BaseApi
|
|||
|
||||
return new InstanceEntity\Configuration(
|
||||
$statuses_config,
|
||||
new InstanceEntity\MediaAttachmentsConfig(Images::supportedMimeTypes(), $image_size_limit, $image_matrix_limit),
|
||||
new InstanceEntity\MediaAttachmentsConfig($this->supportedMimeTypes(), $image_size_limit, $image_matrix_limit),
|
||||
new InstanceEntity\Polls(),
|
||||
new InstanceEntity\Accounts(),
|
||||
);
|
||||
}
|
||||
|
||||
private function supportedMimeTypes(): array
|
||||
{
|
||||
$mimetypes = ['audio/aac', 'audio/flac', 'audio/mpeg', 'audio/mp4', 'audio/ogg', 'audio/wav',
|
||||
'audio/webm', 'video/mp4', 'video/ogg', 'video/webm'];
|
||||
return array_merge(Images::supportedMimeTypes(), $mimetypes);
|
||||
}
|
||||
|
||||
private function buildContactInfo(): InstanceEntity\Contact
|
||||
{
|
||||
$email = implode(',', User::getAdminEmailList());
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
namespace Friendica\Module\Api\Mastodon;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Attach;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Photo;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Module\BaseApi;
|
||||
|
@ -51,14 +52,38 @@ class Media extends BaseApi
|
|||
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
|
||||
}
|
||||
|
||||
$media = Photo::upload($uid, $_FILES['file'], '', null, null, '', '', $request['description']);
|
||||
if (empty($media)) {
|
||||
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
|
||||
$type = Post\Media::getType($_FILES['file']['type']);
|
||||
|
||||
if (in_array($type, [Post\Media::IMAGE, Post\Media::UNKNOWN])) {
|
||||
$media = Photo::upload($uid, $_FILES['file'], '', null, null, '', '', $request['description']);
|
||||
if (empty($media)) {
|
||||
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
|
||||
}
|
||||
|
||||
Logger::info('Uploaded photo', ['media' => $media]);
|
||||
|
||||
$this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id']));
|
||||
} else {
|
||||
$tempFileName = $_FILES['file']['tmp_name'];
|
||||
$fileName = basename($_FILES['file']['name']);
|
||||
$fileSize = intval($_FILES['file']['size']);
|
||||
$maxFileSize = DI::config()->get('system', 'maxfilesize');
|
||||
|
||||
if ($fileSize <= 0) {
|
||||
@unlink($tempFileName);
|
||||
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
|
||||
}
|
||||
|
||||
if ($maxFileSize && $fileSize > $maxFileSize) {
|
||||
@unlink($tempFileName);
|
||||
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
|
||||
}
|
||||
|
||||
$id = Attach::storeFile($tempFileName, self::getCurrentUserID(), $fileName, $_FILES['file']['type'], '<' . Contact::getPublicIdByUserId(self::getCurrentUserID()) . '>');
|
||||
@unlink($tempFileName);
|
||||
Logger::info('Uploaded media', ['id' => $id]);
|
||||
$this->jsonExit(DI::mstdnAttachment()->createFromAttach($id));
|
||||
}
|
||||
|
||||
Logger::info('Uploaded photo', ['media' => $media]);
|
||||
|
||||
$this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id']));
|
||||
}
|
||||
|
||||
public function put(array $request = [])
|
||||
|
@ -77,6 +102,10 @@ class Media extends BaseApi
|
|||
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
|
||||
}
|
||||
|
||||
if (DI::mstdnAttachment()->isAttach($this->parameters['id']) && Attach::exists(['id' => substr($this->parameters['id'], 7)])) {
|
||||
$this->jsonExit(DI::mstdnAttachment()->createFromAttach(substr($this->parameters['id'], 7)));
|
||||
}
|
||||
|
||||
$photo = Photo::selectFirst(['resource-id'], ['id' => $this->parameters['id'], 'uid' => $uid]);
|
||||
if (empty($photo['resource-id'])) {
|
||||
$media = Post\Media::getById($this->parameters['id']);
|
||||
|
@ -108,10 +137,15 @@ class Media extends BaseApi
|
|||
}
|
||||
|
||||
$id = $this->parameters['id'];
|
||||
if (!Photo::exists(['id' => $id, 'uid' => $uid])) {
|
||||
$this->logAndJsonError(404, $this->errorFactory->RecordNotFound());
|
||||
|
||||
if (Photo::exists(['id' => $id, 'uid' => $uid])) {
|
||||
$this->jsonExit(DI::mstdnAttachment()->createFromPhoto($id));
|
||||
}
|
||||
|
||||
$this->jsonExit(DI::mstdnAttachment()->createFromPhoto($id));
|
||||
if (DI::mstdnAttachment()->isAttach($id) && Attach::exists(['id' => substr($id, 7)])) {
|
||||
$this->jsonExit(DI::mstdnAttachment()->createFromAttach(substr($id, 7)));
|
||||
}
|
||||
|
||||
$this->logAndJsonError(404, $this->errorFactory->RecordNotFound());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,13 +98,13 @@ class PushSubscription extends BaseApi
|
|||
}
|
||||
|
||||
$fields = [
|
||||
Notification::TYPE_FOLLOW => $request['data']['alerts'][Notification::TYPE_FOLLOW] ?? false,
|
||||
Notification::TYPE_LIKE => $request['data']['alerts'][Notification::TYPE_LIKE] ?? false,
|
||||
Notification::TYPE_RESHARE => $request['data']['alerts'][Notification::TYPE_RESHARE] ?? false,
|
||||
Notification::TYPE_MENTION => $request['data']['alerts'][Notification::TYPE_MENTION] ?? false,
|
||||
Notification::TYPE_POLL => $request['data']['alerts'][Notification::TYPE_POLL] ?? false,
|
||||
Notification::TYPE_INTRODUCTION => $request['data']['alerts'][Notification::TYPE_INTRODUCTION] ?? false,
|
||||
Notification::TYPE_POST => $request['data']['alerts'][Notification::TYPE_POST] ?? false,
|
||||
Notification::TYPE_FOLLOW => $this->setBoolean($request['data']['alerts'][Notification::TYPE_FOLLOW] ?? false),
|
||||
Notification::TYPE_LIKE => $this->setBoolean($request['data']['alerts'][Notification::TYPE_LIKE] ?? false),
|
||||
Notification::TYPE_RESHARE => $this->setBoolean($request['data']['alerts'][Notification::TYPE_RESHARE] ?? false),
|
||||
Notification::TYPE_MENTION => $this->setBoolean($request['data']['alerts'][Notification::TYPE_MENTION] ?? false),
|
||||
Notification::TYPE_POLL => $this->setBoolean($request['data']['alerts'][Notification::TYPE_POLL] ?? false),
|
||||
Notification::TYPE_INTRODUCTION => $this->setBoolean($request['data']['alerts'][Notification::TYPE_INTRODUCTION] ?? false),
|
||||
Notification::TYPE_POST => $this->setBoolean($request['data']['alerts'][Notification::TYPE_POST] ?? false),
|
||||
];
|
||||
|
||||
$ret = Subscription::update($application['id'], $uid, $fields);
|
||||
|
@ -120,6 +120,14 @@ class PushSubscription extends BaseApi
|
|||
$this->response->addJsonContent($subscriptionObj->toArray());
|
||||
}
|
||||
|
||||
private function setBoolean($input): bool
|
||||
{
|
||||
if (is_bool($input)) {
|
||||
return $input;
|
||||
}
|
||||
return strtolower($input) == 'true';
|
||||
}
|
||||
|
||||
protected function delete(array $request = []): void
|
||||
{
|
||||
$this->checkAllowedScope(self::SCOPE_PUSH);
|
||||
|
|
|
@ -28,6 +28,7 @@ use Friendica\Core\Protocol;
|
|||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Attach;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Circle;
|
||||
use Friendica\Model\Item;
|
||||
|
@ -397,6 +398,20 @@ class Statuses extends BaseApi
|
|||
$item['attachments'] = [];
|
||||
|
||||
foreach ($media_ids as $id) {
|
||||
if (DI::mstdnAttachment()->isAttach($id) && Attach::exists(['id' => substr($id, 7)])) {
|
||||
$attach = Attach::selectFirst([], ['id' => substr($id, 7)]);
|
||||
$attachment = [
|
||||
'type' => Post\Media::getType($attach['filetype']),
|
||||
'mimetype' => $attach['filetype'],
|
||||
'url' => DI::baseUrl() . '/attach/' . substr($id, 7),
|
||||
'size' => $attach['filetype'],
|
||||
'name' => $attach['filename']
|
||||
];
|
||||
$item['attachments'][] = $attachment;
|
||||
Attach::setPermissionForId(substr($id, 7), $item['uid'], $item['allow_cid'], $item['allow_gid'], $item['deny_cid'], $item['deny_gid']);
|
||||
continue;
|
||||
}
|
||||
|
||||
$media = DBA::toArray(DBA::p("SELECT `resource-id`, `scale`, `type`, `desc`, `filename`, `datasize`, `width`, `height` FROM `photo`
|
||||
WHERE `resource-id` IN (SELECT `resource-id` FROM `photo` WHERE `id` = ?) AND `photo`.`uid` = ?
|
||||
ORDER BY `photo`.`width` DESC LIMIT 2", $id, $item['uid']));
|
||||
|
@ -409,13 +424,16 @@ class Statuses extends BaseApi
|
|||
|
||||
$ext = Images::getExtensionByMimeType($media[0]['type']);
|
||||
|
||||
$attachment = ['type' => Post\Media::IMAGE, 'mimetype' => $media[0]['type'],
|
||||
'url' => DI::baseUrl() . '/photo/' . $media[0]['resource-id'] . '-' . $media[0]['scale'] . $ext,
|
||||
'size' => $media[0]['datasize'],
|
||||
'name' => $media[0]['filename'] ?: $media[0]['resource-id'],
|
||||
$attachment = [
|
||||
'type' => Post\Media::IMAGE,
|
||||
'mimetype' => $media[0]['type'],
|
||||
'url' => DI::baseUrl() . '/photo/' . $media[0]['resource-id'] . '-' . $media[0]['scale'] . $ext,
|
||||
'size' => $media[0]['datasize'],
|
||||
'name' => $media[0]['filename'] ?: $media[0]['resource-id'],
|
||||
'description' => $media[0]['desc'] ?? '',
|
||||
'width' => $media[0]['width'],
|
||||
'height' => $media[0]['height']];
|
||||
'width' => $media[0]['width'],
|
||||
'height' => $media[0]['height']
|
||||
];
|
||||
|
||||
if (count($media) > 1) {
|
||||
$attachment['preview'] = DI::baseUrl() . '/photo/' . $media[1]['resource-id'] . '-' . $media[1]['scale'] . $ext;
|
||||
|
|
|
@ -110,8 +110,7 @@ class ListTimeline extends BaseApi
|
|||
|
||||
private function getStatusesForGroup(int $uid, array $request): array
|
||||
{
|
||||
$cdata = Contact::getPublicAndUserContactID((int)substr($this->parameters['id'], 6), $uid);
|
||||
$cid = $cdata['public'];
|
||||
$cid = Contact::getPublicContactId((int)substr($this->parameters['id'], 6), $uid);
|
||||
|
||||
$condition = ["(`uid` = ? OR (`uid` = ? AND NOT `global`))", 0, $uid];
|
||||
|
||||
|
|
|
@ -21,26 +21,47 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon\Timelines;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Module\Conversation\Community;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Object\Api\Mastodon\TimelineOrderByTypes;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/timelines/
|
||||
*/
|
||||
class PublicTimeline extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @var IManageConfigValues
|
||||
*/
|
||||
private $config;
|
||||
|
||||
public function __construct(IManageConfigValues $config, \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->config = $config;
|
||||
}
|
||||
/**
|
||||
* @throws HTTPException\InternalServerErrorException
|
||||
*/
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
if ($this->config->get('system', 'block_public') || $this->config->get('system', 'community_page_style') == Community::DISABLED_VISITOR) {
|
||||
$this->checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
}
|
||||
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = $this->getRequest([
|
||||
|
@ -56,6 +77,10 @@ class PublicTimeline extends BaseApi
|
|||
'friendica_order' => TimelineOrderByTypes::ID, // Sort order options (defaults to ID)
|
||||
], $request);
|
||||
|
||||
if (!$this->localAllowed() && !$this->globalAllowed()) {
|
||||
$this->jsonExit([]);
|
||||
}
|
||||
|
||||
$condition = [
|
||||
'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT], 'private' => Item::PUBLIC,
|
||||
'network' => Protocol::FEDERATED, 'author-blocked' => false, 'author-hidden' => false
|
||||
|
@ -64,13 +89,13 @@ class PublicTimeline extends BaseApi
|
|||
$condition = $this->addPagingConditions($request, $condition);
|
||||
$params = $this->buildOrderAndLimitParams($request);
|
||||
|
||||
if ($request['local']) {
|
||||
if ($request['local'] && $this->localAllowed()) {
|
||||
$condition = DBA::mergeConditions($condition, ['origin' => true]);
|
||||
} else {
|
||||
$condition = DBA::mergeConditions($condition, ['uid' => 0]);
|
||||
}
|
||||
|
||||
if ($request['remote']) {
|
||||
if ($request['remote'] && $this->globalAllowed()) {
|
||||
$condition = DBA::mergeConditions($condition, ["NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin` AND `post-user`.`uri-id` = `post-timeline-view`.`uri-id`)"]);
|
||||
}
|
||||
|
||||
|
@ -113,4 +138,14 @@ class PublicTimeline extends BaseApi
|
|||
self::setLinkHeader($request['friendica_order'] != TimelineOrderByTypes::ID);
|
||||
$this->jsonExit($statuses);
|
||||
}
|
||||
|
||||
private function localAllowed(): bool
|
||||
{
|
||||
return in_array($this->config->get('system', 'community_page_style'), [Community::LOCAL, Community::LOCAL_AND_GLOBAL, Community::DISABLED_VISITOR]);
|
||||
}
|
||||
|
||||
private function globalAllowed(): bool
|
||||
{
|
||||
return in_array($this->config->get('system', 'community_page_style'), [Community::GLOBAL, Community::LOCAL_AND_GLOBAL, Community::DISABLED_VISITOR]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,25 +21,46 @@
|
|||
|
||||
namespace Friendica\Module\Api\Mastodon\Trends;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Module\Api\ApiResponse;
|
||||
use Friendica\Module\BaseApi;
|
||||
use Friendica\Module\Conversation\Community;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @see https://docs.joinmastodon.org/methods/trends/#statuses
|
||||
*/
|
||||
class Statuses extends BaseApi
|
||||
{
|
||||
/**
|
||||
* @var IManageConfigValues
|
||||
*/
|
||||
private $config;
|
||||
|
||||
public function __construct(IManageConfigValues $config, \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->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
*/
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
if ($this->config->get('system', 'block_public') || $this->config->get('system', 'community_page_style') == Community::DISABLED_VISITOR) {
|
||||
$this->checkAllowedScope(BaseApi::SCOPE_READ);
|
||||
}
|
||||
|
||||
$uid = self::getCurrentUserID();
|
||||
|
||||
$request = $this->getRequest([
|
||||
|
|
|
@ -47,7 +47,8 @@ class Destroy extends BaseApi
|
|||
|
||||
$this->dba = $dba;
|
||||
}
|
||||
protected function rawContent(array $request = [])
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$this->checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
|
|
@ -54,7 +54,7 @@ class NewDM extends BaseApi
|
|||
$this->directMessage = $directMessage;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$this->checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
@ -81,9 +81,9 @@ class NewDM extends BaseApi
|
|||
}
|
||||
}
|
||||
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
$ucid = Contact::getUserContactId($cid, $uid);
|
||||
|
||||
$id = Mail::send($uid, $cdata['user'], $request['text'], $sub, $replyto);
|
||||
$id = Mail::send($uid, $ucid, $request['text'], $sub, $replyto);
|
||||
|
||||
if ($id > -1) {
|
||||
$ret = $this->directMessage->createFromMailId($id, $uid, $this->getRequestValue($request, 'getText', ''));
|
||||
|
|
|
@ -88,9 +88,9 @@ abstract class DirectMessagesEndpoint extends BaseApi
|
|||
|
||||
$cid = BaseApi::getContactIDForSearchterm($this->getRequestValue($request, 'screen_name', ''), $this->getRequestValue($request, 'profileurl', ''), $this->getRequestValue($request, 'user_id', 0), 0);
|
||||
if (!empty($cid)) {
|
||||
$cdata = Contact::getPublicAndUserContactID($cid, $uid);
|
||||
if (!empty($cdata['user'])) {
|
||||
$condition = DBA::mergeConditions($condition, ["`contact-id` = ?", $cdata['user']]);
|
||||
$ucid = Contact::getUserContactId($cid, $uid);
|
||||
if ($ucid) {
|
||||
$condition = DBA::mergeConditions($condition, ["`contact-id` = ?", $ucid]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,13 +71,13 @@ class Destroy extends ContactEndpoint
|
|||
}
|
||||
|
||||
// Get Contact by given id
|
||||
$cdata = Contact::getPublicAndUserContactID($contact_id, $uid);
|
||||
if (!empty($cdata['user'])) {
|
||||
$ucid = Contact::getUserContactId($contact_id, $uid);
|
||||
if (!$ucid) {
|
||||
Logger::notice(BaseApi::LOG_PREFIX . 'Not following contact', ['module' => 'api', 'action' => 'friendships_destroy']);
|
||||
throw new HTTPException\NotFoundException('Not following Contact');
|
||||
}
|
||||
|
||||
$contact = Contact::getById($cdata['user']);
|
||||
$contact = Contact::getById($ucid);
|
||||
$user = $this->twitterUser->createFromContactId($contact_id, $uid, true)->toArray();
|
||||
|
||||
try {
|
||||
|
|
|
@ -55,9 +55,9 @@ class Show extends ContactEndpoint
|
|||
$following = false;
|
||||
|
||||
if ($source_cid == Contact::getPublicIdByUserId($uid)) {
|
||||
$cdata = Contact::getPublicAndUserContactID($target_cid, $uid);
|
||||
if (!empty($cdata['user'])) {
|
||||
$usercontact = Contact::getById($cdata['user'], ['rel']);
|
||||
$ucid = Contact::getUserContactId($target_cid, $uid);
|
||||
if ($ucid) {
|
||||
$usercontact = Contact::getById($ucid, ['rel']);
|
||||
switch ($usercontact['rel'] ?? Contact::NOTHING) {
|
||||
case Contact::FOLLOWER:
|
||||
$follower = true;
|
||||
|
|
|
@ -54,7 +54,7 @@ class Create extends BaseApi
|
|||
$this->friendicaCircle = $friendicaCircle;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$this->checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
|
|
@ -54,7 +54,7 @@ class Destroy extends BaseApi
|
|||
$this->friendicaCircle = $friendicaCircle;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$this->checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
|
|
@ -54,7 +54,7 @@ class Update extends BaseApi
|
|||
$this->friendicaCircle = $friendicaCircle;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$this->checkAllowedScope(BaseApi::SCOPE_WRITE);
|
||||
$uid = BaseApi::getCurrentUserID();
|
||||
|
|
|
@ -58,7 +58,13 @@ class Contact extends BaseModule
|
|||
return;
|
||||
}
|
||||
|
||||
$redirectUrl = $_POST['redirect_url'] ?? 'contact';
|
||||
$redirectUrl = $_POST['command'] ?? '';
|
||||
if (substr($redirectUrl, 0, 7) != 'contact') {
|
||||
$redirectUrl = 'contact';
|
||||
}
|
||||
if (!empty($_POST['parameter'])) {
|
||||
$redirectUrl .= '?' . $_POST['parameter'];
|
||||
}
|
||||
|
||||
self::checkFormSecurityTokenRedirectOnError($redirectUrl, 'contact_batch_actions');
|
||||
|
||||
|
@ -253,7 +259,7 @@ class Contact extends BaseModule
|
|||
$sql_extra = " AND `archive` AND NOT `blocked` AND NOT `pending`";
|
||||
break;
|
||||
case 'pending':
|
||||
$sql_extra = " AND `pending` AND NOT `archive` AND NOT `failed` AND ((`rel` = ?)
|
||||
$sql_extra = " AND `pending` AND NOT `archive` AND ((`rel` = ?)
|
||||
OR `id` IN (SELECT `contact-id` FROM `intro` WHERE `intro`.`uid` = ? AND NOT `ignore`))";
|
||||
$sql_values[] = Model\Contact::SHARING;
|
||||
$sql_values[] = DI::userSession()->getLocalUserId();
|
||||
|
@ -459,6 +465,7 @@ class Contact extends BaseModule
|
|||
'$finding' => $searching ? DI::l10n()->t('Results for: %s', $search) : '',
|
||||
'$submit' => DI::l10n()->t('Find'),
|
||||
'$cmd' => DI::args()->getCommand(),
|
||||
'$parameter' => http_build_query($request),
|
||||
'$contacts' => $contacts,
|
||||
'$form_security_token' => BaseModule::getFormSecurityToken('contact_batch_actions'),
|
||||
'multiselect' => 1,
|
||||
|
|
|
@ -81,18 +81,18 @@ class Conversations extends BaseModule
|
|||
|
||||
// Backward compatibility: Ensure to use the public contact when the user contact is provided
|
||||
// Remove by version 2022.03
|
||||
$data = Model\Contact::getPublicAndUserContactID(intval($this->parameters['id']), $this->userSession->getLocalUserId());
|
||||
if (empty($data)) {
|
||||
$pcid = Model\Contact::getPublicContactId(intval($this->parameters['id']), $this->userSession->getLocalUserId());
|
||||
if (!$pcid) {
|
||||
throw new NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
$contact = Model\Contact::getById($data['public']);
|
||||
$contact = Model\Contact::getById($pcid);
|
||||
if (empty($contact)) {
|
||||
throw new NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
// Don't display contacts that are about to be deleted
|
||||
if (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM) {
|
||||
if ($contact['deleted'] || $contact['network'] == Protocol::PHANTOM) {
|
||||
throw new NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ class Follow extends BaseModule
|
|||
|
||||
$this->baseUrl->redirect($returnPath);
|
||||
} elseif (!empty($result['cid'])) {
|
||||
$this->baseUrl->redirect('contact/' . $result['cid']);
|
||||
$this->baseUrl->redirect('contact/' . Contact::getPublicContactId($result['cid'], $this->session->getLocalUserId()));
|
||||
}
|
||||
|
||||
$this->sysMessages->addNotice($this->t('The contact could not be added.'));
|
||||
|
|
|
@ -65,7 +65,7 @@ class Media extends BaseModule
|
|||
|
||||
$o = Contact::getTabsHTML($contact, Contact::TAB_MEDIA);
|
||||
|
||||
$o .= ModelContact::getPostsFromUrl($contact['url'], $this->userSession->getLocalUserId(), true);
|
||||
$o .= ModelContact::getPostsFromUrl($contact['url'], $this->userSession->getLocalUserId(), true, $request['last_created'] ?? '');
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
|
|
@ -73,18 +73,18 @@ class Posts extends BaseModule
|
|||
|
||||
// Backward compatibility: Ensure to use the public contact when the user contact is provided
|
||||
// Remove by version 2022.03
|
||||
$data = Model\Contact::getPublicAndUserContactID(intval($this->parameters['id']), $this->userSession->getLocalUserId());
|
||||
if (empty($data)) {
|
||||
$pcid = Model\Contact::getPublicContactId(intval($this->parameters['id']), $this->userSession->getLocalUserId());
|
||||
if (!$pcid) {
|
||||
throw new NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
$contact = Model\Contact::getById($data['public']);
|
||||
$contact = Model\Contact::getById($pcid);
|
||||
if (!DBA::isResult($contact)) {
|
||||
throw new NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
// Don't display contacts that are about to be deleted
|
||||
if (DBA::isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) {
|
||||
if ($contact['deleted'] || $contact['network'] == Protocol::PHANTOM) {
|
||||
throw new NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -91,8 +91,8 @@ class Profile extends BaseModule
|
|||
|
||||
// Backward compatibility: The update still needs a user-specific contact ID
|
||||
// Change to user-contact table check by version 2022.03
|
||||
$cdata = Contact::getPublicAndUserContactID($contact_id, $this->session->getLocalUserId());
|
||||
if (empty($cdata['user']) || !$this->db->exists('contact', ['id' => $cdata['user'], 'deleted' => false])) {
|
||||
$ucid = Contact::getUserContactId($contact_id, $this->session->getLocalUserId());
|
||||
if (!$ucid || !$this->db->exists('contact', ['id' => $ucid, 'deleted' => false])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -134,14 +134,14 @@ class Profile extends BaseModule
|
|||
}
|
||||
|
||||
if (isset($request['channel_frequency'])) {
|
||||
Contact\User::setChannelFrequency($cdata['user'], $this->session->getLocalUserId(), $request['channel_frequency']);
|
||||
Contact\User::setChannelFrequency($ucid, $this->session->getLocalUserId(), $request['channel_frequency']);
|
||||
}
|
||||
|
||||
if (isset($request['channel_only'])) {
|
||||
Contact\User::setChannelOnly($cdata['user'], $this->session->getLocalUserId(), $request['channel_only']);
|
||||
Contact\User::setChannelOnly($ucid, $this->session->getLocalUserId(), $request['channel_only']);
|
||||
}
|
||||
|
||||
if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => $this->session->getLocalUserId()])) {
|
||||
if (!Contact::update($fields, ['id' => $ucid, 'uid' => $this->session->getLocalUserId()])) {
|
||||
$this->systemMessages->addNotice($this->t('Failed to update contact record.'));
|
||||
}
|
||||
}
|
||||
|
@ -164,8 +164,22 @@ class Profile extends BaseModule
|
|||
throw new HTTPException\NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
// Fetch the protocol from the user's contact.
|
||||
if ($data['user']) {
|
||||
$usercontact = Contact::getById($data['user'], ['network', 'protocol']);
|
||||
if ($this->db->isResult($usercontact)) {
|
||||
$contact['network'] = $usercontact['network'];
|
||||
$contact['protocol'] = $usercontact['protocol'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($contact['network']) && Contact::isLocal($contact['url']) ) {
|
||||
$contact['network'] = Protocol::DFRN;
|
||||
$contact['protocol'] = Protocol::ACTIVITYPUB;
|
||||
}
|
||||
|
||||
// Don't display contacts that are about to be deleted
|
||||
if ($this->db->isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) {
|
||||
if ($contact['deleted'] || $contact['network'] == Protocol::PHANTOM) {
|
||||
throw new HTTPException\NotFoundException($this->t('Contact not found.'));
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ use Friendica\Core\Renderer;
|
|||
use Friendica\Database\Database;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model;
|
||||
use Friendica\Model\Contact as ModelContact;
|
||||
use Friendica\Module\Contact;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Module\Security\Login;
|
||||
|
@ -58,16 +59,12 @@ class Revoke extends BaseModule
|
|||
return;
|
||||
}
|
||||
|
||||
$data = Model\Contact::getPublicAndUserContactID($this->parameters['id'], DI::userSession()->getLocalUserId());
|
||||
if (!$this->dba->isResult($data)) {
|
||||
throw new HTTPException\NotFoundException($this->t('Unknown contact.'));
|
||||
}
|
||||
|
||||
if (empty($data['user'])) {
|
||||
$ucid = Model\Contact::getUserContactId($this->parameters['id'], DI::userSession()->getLocalUserId());
|
||||
if (!$ucid) {
|
||||
throw new HTTPException\ForbiddenException();
|
||||
}
|
||||
|
||||
$this->contact = Model\Contact::getById($data['user']);
|
||||
$this->contact = Model\Contact::getById($ucid);
|
||||
|
||||
if ($this->contact['deleted']) {
|
||||
throw new HTTPException\NotFoundException($this->t('Contact is deleted.'));
|
||||
|
@ -90,7 +87,7 @@ class Revoke extends BaseModule
|
|||
|
||||
DI::sysmsg()->addNotice($this->t('Follow was successfully revoked.'));
|
||||
|
||||
$this->baseUrl->redirect('contact/' . $this->parameters['id']);
|
||||
$this->baseUrl->redirect('contact/' . ModelContact::getPublicContactId($this->parameters['id'], DI::userSession()->getLocalUserId()));
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
|
|
|
@ -168,7 +168,7 @@ class Unfollow extends \Friendica\BaseModule
|
|||
$this->baseUrl->redirect($base_return_path);
|
||||
}
|
||||
|
||||
$return_path = $base_return_path . '/' . $contact['id'];
|
||||
$return_path = $base_return_path . '/' . Contact::getPublicContactId($contact['id'], $uid);
|
||||
|
||||
try {
|
||||
Contact::unfollow($contact);
|
||||
|
|
|
@ -47,10 +47,12 @@ use Friendica\Core\L10n;
|
|||
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
|
||||
use Friendica\Core\Renderer;
|
||||
use Friendica\Core\Session\Capability\IHandleUserSessions;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Circle;
|
||||
use Friendica\Model\Post;
|
||||
use Friendica\Model\Profile;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Module\Security\Login;
|
||||
|
@ -470,23 +472,20 @@ class Network extends Timeline
|
|||
$items = array_reverse($items);
|
||||
}
|
||||
|
||||
if ($this->database->isResult($items)) {
|
||||
$parents = array_column($items, 'uri-id');
|
||||
} else {
|
||||
$parents = [];
|
||||
if ($this->ping || !$this->database->isResult($items)) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
// We aren't going to try and figure out at the item, circle, and page
|
||||
// level which items you've seen and which you haven't. If you're looking
|
||||
// at the top level network page just mark everything seen.
|
||||
if (!$this->circleId && !$this->star && !$this->mention) {
|
||||
$condition = ['unseen' => true, 'uid' => $this->session->getLocalUserId()];
|
||||
$this->setItemsSeenByCondition($condition);
|
||||
} elseif (!empty($parents)) {
|
||||
$condition = ['unseen' => true, 'uid' => $this->session->getLocalUserId(), 'parent-uri-id' => $parents];
|
||||
$this->setItemsSeenByCondition($condition);
|
||||
$this->setItemsSeenByCondition(['unseen' => true, 'uid' => $this->session->getLocalUserId(), 'parent-uri-id' => array_column($items, 'uri-id')]);
|
||||
|
||||
$posts = Post::selectToArray(['uri-id'], ['unseen' => true, 'uid' => $this->session->getLocalUserId()], ['limit' => 100]);
|
||||
if (!empty($posts)) {
|
||||
$this->setItemsSeenByCondition(['unseen' => true, 'uid' => $this->session->getLocalUserId(), 'uri-id' => array_column($posts, 'uri-id')]);
|
||||
}
|
||||
|
||||
if (count($posts) == 100) {
|
||||
Worker::add(Worker::PRIORITY_MEDIUM, 'SetSeen', $this->session->getLocalUserId());
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
namespace Friendica\Module\DFRN;
|
||||
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Conversation;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
@ -45,6 +47,8 @@ class Notify extends BaseModule
|
|||
throw new HTTPException\BadRequestException();
|
||||
}
|
||||
|
||||
Item::incrementInbound(Protocol::DFRN);
|
||||
|
||||
$data = json_decode($postdata);
|
||||
if (is_object($data) && !empty($this->parameters['nickname'])) {
|
||||
$user = User::getByNickname($this->parameters['nickname']);
|
||||
|
|
|
@ -29,6 +29,12 @@ use Friendica\Util\JsonLD;
|
|||
|
||||
class ActivityPubConversion extends BaseModule
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
function visible_whitespace($s)
|
||||
|
|
|
@ -35,6 +35,12 @@ use Friendica\Util\XML;
|
|||
*/
|
||||
class Babel extends BaseModule
|
||||
{
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
function visible_whitespace($s)
|
||||
|
|
|
@ -25,6 +25,8 @@ use Friendica\App;
|
|||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Module\Response;
|
||||
use Friendica\Network\HTTPException;
|
||||
|
@ -57,6 +59,8 @@ class Receive extends BaseModule
|
|||
throw new HTTPException\ForbiddenException($this->t('Access denied.'));
|
||||
}
|
||||
|
||||
Item::incrementInbound(Protocol::DIASPORA);
|
||||
|
||||
if ($this->parameters['type'] === 'public') {
|
||||
$this->receivePublic();
|
||||
} else if ($this->parameters['type'] === 'users') {
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
namespace Friendica\Module;
|
||||
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Protocol\Feed as ProtocolFeed;
|
||||
|
@ -68,6 +70,8 @@ class Feed extends BaseModule
|
|||
throw new HTTPException\UnauthorizedException($this->t('Access to this profile has been restricted.'));
|
||||
}
|
||||
|
||||
Item::incrementOutbound(Protocol::FEED);
|
||||
|
||||
$feed = ProtocolFeed::atom($owner, $last_update, 10, $type);
|
||||
|
||||
$this->httpExit($feed, Response::TYPE_ATOM);
|
||||
|
|
|
@ -36,7 +36,7 @@ use Friendica\Protocol\Diaspora;
|
|||
*/
|
||||
class Activity extends BaseModule
|
||||
{
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
if (!DI::userSession()->isAuthenticated()) {
|
||||
throw new HTTPException\ForbiddenException();
|
||||
|
|
|
@ -33,7 +33,7 @@ use Friendica\Network\HTTPException;
|
|||
*/
|
||||
class Follow extends BaseModule
|
||||
{
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$l10n = DI::l10n();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ use Friendica\Network\HTTPException;
|
|||
*/
|
||||
class Ignore extends BaseModule
|
||||
{
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$l10n = DI::l10n();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ use Friendica\Network\HTTPException;
|
|||
*/
|
||||
class Pin extends BaseModule
|
||||
{
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$l10n = DI::l10n();
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ use Friendica\Network\HTTPException;
|
|||
*/
|
||||
class Star extends BaseModule
|
||||
{
|
||||
protected function rawContent(array $request = [])
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
$l10n = DI::l10n();
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ class Upload extends \Friendica\BaseModule
|
|||
$this->return(401, $msg);
|
||||
}
|
||||
|
||||
$newid = Attach::storeFile($tempFileName, $owner['uid'], $fileName, '<' . $owner['id'] . '>');
|
||||
$newid = Attach::storeFile($tempFileName, $owner['uid'], $fileName, $_FILES['userfile']['type'] ?? '', '<' . $owner['id'] . '>');
|
||||
|
||||
@unlink($tempFileName);
|
||||
|
||||
|
|
|
@ -45,6 +45,12 @@ class Source extends BaseModeration
|
|||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
parent::content();
|
||||
|
|
|
@ -48,6 +48,12 @@ class Reports extends BaseModeration
|
|||
$this->database = $database;
|
||||
}
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
parent::content();
|
||||
|
|
|
@ -56,10 +56,11 @@ class NodeInfo120 extends BaseModule
|
|||
],
|
||||
'protocols' => ['dfrn', 'activitypub'],
|
||||
'services' => Nodeinfo::getServices(),
|
||||
'usage' => Nodeinfo::getUsage(),
|
||||
'openRegistrations' => Register::getPolicy() !== Register::CLOSED,
|
||||
'usage' => Nodeinfo::getUsage(),
|
||||
'metadata' => [
|
||||
'nodeName' => $this->config->get('config', 'sitename'),
|
||||
'nodeName' => $this->config->get('config', 'sitename'),
|
||||
'nodeDescription' => $this->config->get('config', 'info'),
|
||||
],
|
||||
];
|
||||
|
||||
|
|
90
src/Module/NodeInfo121.php
Normal file
90
src/Module/NodeInfo121.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?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\Module;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Capabilities\ICanCreateResponses;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Model\Nodeinfo;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Version 2.1 of Nodeinfo, a standardized way of exposing metadata about a server running one of the distributed social networks.
|
||||
* @see https://github.com/jhass/nodeinfo/blob/master/PROTOCOL.md
|
||||
*/
|
||||
class NodeInfo121 extends BaseModule
|
||||
{
|
||||
/** @var IManageConfigValues */
|
||||
protected $config;
|
||||
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IManageConfigValues $config, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$nodeinfo = [
|
||||
'version' => '2.1',
|
||||
'software' => [
|
||||
'name' => 'friendica',
|
||||
'version' => App::VERSION . '-' . DB_UPDATE_VERSION,
|
||||
'repository' => 'https://github.com/friendica/friendica',
|
||||
'homepage' => 'https://friendi.ca',
|
||||
],
|
||||
'protocols' => ['dfrn', 'activitypub'],
|
||||
'services' => Nodeinfo::getServices(),
|
||||
'openRegistrations' => Register::getPolicy() !== Register::CLOSED,
|
||||
'usage' => Nodeinfo::getUsage(),
|
||||
'metadata' => [
|
||||
'nodeName' => $this->config->get('config', 'sitename'),
|
||||
'nodeDescription' => $this->config->get('config', 'info'),
|
||||
],
|
||||
];
|
||||
|
||||
if (!empty($this->config->get('system', 'diaspora_enabled'))) {
|
||||
$nodeinfo['protocols'][] = 'diaspora';
|
||||
}
|
||||
|
||||
if (empty($this->config->get('system', 'ostatus_disabled'))) {
|
||||
$nodeinfo['protocols'][] = 'ostatus';
|
||||
}
|
||||
|
||||
$nodeinfo['services']['inbound'][] = 'atom1.0';
|
||||
$nodeinfo['services']['inbound'][] = 'rss2.0';
|
||||
$nodeinfo['services']['outbound'][] = 'atom1.0';
|
||||
|
||||
if (function_exists('imap_open') && !$this->config->get('system', 'imap_disabled')) {
|
||||
$nodeinfo['services']['inbound'][] = 'imap';
|
||||
}
|
||||
|
||||
$nodeinfo['metadata']['explicitContent'] = $this->config->get('system', 'explicit_content', false) == true;
|
||||
|
||||
$this->response->setType(ICanCreateResponses::TYPE_JSON, 'application/json; charset=utf-8');
|
||||
$this->response->addContent(json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
}
|
91
src/Module/NodeInfo122.php
Normal file
91
src/Module/NodeInfo122.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?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\Module;
|
||||
|
||||
use Friendica\App;
|
||||
use Friendica\BaseModule;
|
||||
use Friendica\Capabilities\ICanCreateResponses;
|
||||
use Friendica\Core\Config\Capability\IManageConfigValues;
|
||||
use Friendica\Core\L10n;
|
||||
use Friendica\Model\Nodeinfo;
|
||||
use Friendica\Util\Profiler;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Version 2.2 of Nodeinfo, a standardized way of exposing metadata about a server running one of the distributed social networks.
|
||||
* @see https://github.com/jhass/nodeinfo/blob/master/PROTOCOL.md
|
||||
*/
|
||||
class NodeInfo122 extends BaseModule
|
||||
{
|
||||
/** @var IManageConfigValues */
|
||||
protected $config;
|
||||
|
||||
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IManageConfigValues $config, array $server, array $parameters = [])
|
||||
{
|
||||
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
|
||||
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
protected function rawContent(array $request = [])
|
||||
{
|
||||
$nodeinfo = [
|
||||
'version' => '2.2',
|
||||
'instance' => [
|
||||
'name' => $this->config->get('config', 'sitename'),
|
||||
'description' => $this->config->get('config', 'info'),
|
||||
],
|
||||
'software' => [
|
||||
'name' => 'friendica',
|
||||
'version' => App::VERSION . '-' . DB_UPDATE_VERSION,
|
||||
'repository' => 'https://github.com/friendica/friendica',
|
||||
'homepage' => 'https://friendi.ca',
|
||||
],
|
||||
'protocols' => ['dfrn', 'activitypub'],
|
||||
'services' => Nodeinfo::getServices(),
|
||||
'openRegistrations' => Register::getPolicy() !== Register::CLOSED,
|
||||
'usage' => Nodeinfo::getUsage(),
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
if (!empty($this->config->get('system', 'diaspora_enabled'))) {
|
||||
$nodeinfo['protocols'][] = 'diaspora';
|
||||
}
|
||||
|
||||
if (empty($this->config->get('system', 'ostatus_disabled'))) {
|
||||
$nodeinfo['protocols'][] = 'ostatus';
|
||||
}
|
||||
|
||||
$nodeinfo['services']['inbound'][] = 'atom1.0';
|
||||
$nodeinfo['services']['inbound'][] = 'rss2.0';
|
||||
$nodeinfo['services']['outbound'][] = 'atom1.0';
|
||||
|
||||
if (function_exists('imap_open') && !$this->config->get('system', 'imap_disabled')) {
|
||||
$nodeinfo['services']['inbound'][] = 'imap';
|
||||
}
|
||||
|
||||
$nodeinfo['metadata']['explicitContent'] = $this->config->get('system', 'explicit_content', false) == true;
|
||||
|
||||
$this->response->setType(ICanCreateResponses::TYPE_JSON, 'application/json; charset=utf-8');
|
||||
$this->response->addContent(json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ use Psr\Log\LoggerInterface;
|
|||
|
||||
/**
|
||||
* Version 1.0 of Nodeinfo 2, a sStandardized way of exposing metadata about a server running one of the distributed social networks.
|
||||
* @see https://github.com/jhass/nodeinfo/blob/master/PROTOCOL.md
|
||||
* @see https://github.com/jaywink/nodeinfo2/blob/master/PROTOCOL.md
|
||||
*/
|
||||
class NodeInfo210 extends BaseModule
|
||||
{
|
||||
|
|
|
@ -77,6 +77,12 @@ class Introductions extends BaseNotifications
|
|||
];
|
||||
}
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
Nav::setSelected('introductions');
|
||||
|
|
|
@ -96,6 +96,12 @@ class Notifications extends BaseNotifications
|
|||
];
|
||||
}
|
||||
|
||||
protected function post(array $request = [])
|
||||
{
|
||||
// @todo check if POST is really used here
|
||||
$this->content($request);
|
||||
}
|
||||
|
||||
protected function content(array $request = []): string
|
||||
{
|
||||
Nav::setSelected('notifications');
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue