Merge remote-tracking branch 'upstream/develop' into imagick-blurhash
This commit is contained in:
commit
b93f100c97
28 changed files with 1367 additions and 666 deletions
133
database.sql
133
database.sql
|
|
@ -1,6 +1,6 @@
|
|||
-- ------------------------------------------
|
||||
-- Friendica 2022.12-dev (Giant Rhubarb)
|
||||
-- DB_UPDATE_VERSION 1497
|
||||
-- DB_UPDATE_VERSION 1500
|
||||
-- ------------------------------------------
|
||||
|
||||
|
||||
|
|
@ -578,6 +578,40 @@ CREATE TABLE IF NOT EXISTS `delayed-post` (
|
|||
FOREIGN KEY (`wid`) REFERENCES `workerqueue` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Posts that are about to be distributed at a later time';
|
||||
|
||||
--
|
||||
-- TABLE diaspora-contact
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `diaspora-contact` (
|
||||
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the contact URL',
|
||||
`addr` varchar(255) COMMENT '',
|
||||
`alias` varchar(255) COMMENT '',
|
||||
`nick` varchar(255) COMMENT '',
|
||||
`name` varchar(255) COMMENT '',
|
||||
`given-name` varchar(255) COMMENT '',
|
||||
`family-name` varchar(255) COMMENT '',
|
||||
`photo` varchar(255) COMMENT '',
|
||||
`photo-medium` varchar(255) COMMENT '',
|
||||
`photo-small` varchar(255) COMMENT '',
|
||||
`batch` varchar(255) COMMENT '',
|
||||
`notify` varchar(255) COMMENT '',
|
||||
`poll` varchar(255) COMMENT '',
|
||||
`subscribe` varchar(255) COMMENT '',
|
||||
`searchable` boolean COMMENT '',
|
||||
`pubkey` text COMMENT '',
|
||||
`gsid` int unsigned COMMENT 'Global Server ID',
|
||||
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
|
||||
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
|
||||
`interacting_count` int unsigned DEFAULT 0 COMMENT 'Number of contacts this contact interactes with',
|
||||
`interacted_count` int unsigned DEFAULT 0 COMMENT 'Number of contacts that interacted with this contact',
|
||||
`post_count` int unsigned DEFAULT 0 COMMENT 'Number of posts and comments',
|
||||
PRIMARY KEY(`uri-id`),
|
||||
UNIQUE INDEX `addr` (`addr`),
|
||||
INDEX `alias` (`alias`),
|
||||
INDEX `gsid` (`gsid`),
|
||||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||||
FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Diaspora compatible contacts - used in the Diaspora implementation';
|
||||
|
||||
--
|
||||
-- TABLE diaspora-interaction
|
||||
--
|
||||
|
|
@ -633,39 +667,6 @@ CREATE TABLE IF NOT EXISTS `event` (
|
|||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Events';
|
||||
|
||||
--
|
||||
-- TABLE fcontact
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS `fcontact` (
|
||||
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
|
||||
`guid` varbinary(255) NOT NULL DEFAULT '' COMMENT 'unique id',
|
||||
`url` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`uri-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the fcontact url',
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||
`photo` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`request` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`nick` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||
`addr` varchar(255) NOT NULL DEFAULT '' COMMENT '',
|
||||
`batch` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`notify` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`poll` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`confirm` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`priority` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
|
||||
`network` char(4) NOT NULL DEFAULT '' COMMENT '',
|
||||
`alias` varbinary(383) NOT NULL DEFAULT '' COMMENT '',
|
||||
`pubkey` text COMMENT '',
|
||||
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
|
||||
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
|
||||
`interacting_count` int unsigned DEFAULT 0 COMMENT 'Number of contacts this contact interactes with',
|
||||
`interacted_count` int unsigned DEFAULT 0 COMMENT 'Number of contacts that interacted with this contact',
|
||||
`post_count` int unsigned DEFAULT 0 COMMENT 'Number of posts and comments',
|
||||
PRIMARY KEY(`id`),
|
||||
INDEX `addr` (`addr`(32)),
|
||||
UNIQUE INDEX `url` (`url`(190)),
|
||||
UNIQUE INDEX `uri-id` (`uri-id`),
|
||||
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
|
||||
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Diaspora compatible contacts - used in the Diaspora implementation';
|
||||
|
||||
--
|
||||
-- TABLE fetch-entry
|
||||
--
|
||||
|
|
@ -2802,11 +2803,11 @@ CREATE VIEW `account-view` AS SELECT
|
|||
`contact`.`blocked` AS `blocked`,
|
||||
`contact`.`notify` AS `dfrn-notify`,
|
||||
`contact`.`poll` AS `dfrn-poll`,
|
||||
`fcontact`.`guid` AS `diaspora-guid`,
|
||||
`fcontact`.`batch` AS `diaspora-batch`,
|
||||
`fcontact`.`notify` AS `diaspora-notify`,
|
||||
`fcontact`.`poll` AS `diaspora-poll`,
|
||||
`fcontact`.`alias` AS `diaspora-alias`,
|
||||
`item-uri`.`guid` AS `diaspora-guid`,
|
||||
`diaspora-contact`.`batch` AS `diaspora-batch`,
|
||||
`diaspora-contact`.`notify` AS `diaspora-notify`,
|
||||
`diaspora-contact`.`poll` AS `diaspora-poll`,
|
||||
`diaspora-contact`.`alias` AS `diaspora-alias`,
|
||||
`apcontact`.`uuid` AS `ap-uuid`,
|
||||
`apcontact`.`type` AS `ap-type`,
|
||||
`apcontact`.`following` AS `ap-following`,
|
||||
|
|
@ -2824,7 +2825,7 @@ CREATE VIEW `account-view` AS SELECT
|
|||
FROM `contact`
|
||||
LEFT JOIN `item-uri` ON `item-uri`.`id` = `contact`.`uri-id`
|
||||
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `contact`.`uri-id`
|
||||
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = contact.`uri-id`
|
||||
LEFT JOIN `diaspora-contact` ON `diaspora-contact`.`uri-id` = contact.`uri-id`
|
||||
LEFT JOIN `gserver` ON `gserver`.`id` = contact.`gsid`
|
||||
WHERE `contact`.`uid` = 0;
|
||||
|
||||
|
|
@ -2903,14 +2904,14 @@ CREATE VIEW `account-user-view` AS SELECT
|
|||
`ucontact`.`reason` AS `reason`,
|
||||
`contact`.`notify` AS `dfrn-notify`,
|
||||
`contact`.`poll` AS `dfrn-poll`,
|
||||
`fcontact`.`guid` AS `diaspora-guid`,
|
||||
`fcontact`.`batch` AS `diaspora-batch`,
|
||||
`fcontact`.`notify` AS `diaspora-notify`,
|
||||
`fcontact`.`poll` AS `diaspora-poll`,
|
||||
`fcontact`.`alias` AS `diaspora-alias`,
|
||||
`fcontact`.`interacting_count` AS `diaspora-interacting_count`,
|
||||
`fcontact`.`interacted_count` AS `diaspora-interacted_count`,
|
||||
`fcontact`.`post_count` AS `diaspora-post_count`,
|
||||
`item-uri`.`guid` AS `diaspora-guid`,
|
||||
`diaspora-contact`.`batch` AS `diaspora-batch`,
|
||||
`diaspora-contact`.`notify` AS `diaspora-notify`,
|
||||
`diaspora-contact`.`poll` AS `diaspora-poll`,
|
||||
`diaspora-contact`.`alias` AS `diaspora-alias`,
|
||||
`diaspora-contact`.`interacting_count` AS `diaspora-interacting_count`,
|
||||
`diaspora-contact`.`interacted_count` AS `diaspora-interacted_count`,
|
||||
`diaspora-contact`.`post_count` AS `diaspora-post_count`,
|
||||
`apcontact`.`uuid` AS `ap-uuid`,
|
||||
`apcontact`.`type` AS `ap-type`,
|
||||
`apcontact`.`following` AS `ap-following`,
|
||||
|
|
@ -2929,7 +2930,7 @@ CREATE VIEW `account-user-view` AS SELECT
|
|||
INNER JOIN `contact` ON `contact`.`uri-id` = `ucontact`.`uri-id` AND `contact`.`uid` = 0
|
||||
LEFT JOIN `item-uri` ON `item-uri`.`id` = `ucontact`.`uri-id`
|
||||
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `ucontact`.`uri-id`
|
||||
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = `ucontact`.`uri-id` AND `fcontact`.`network` = 'dspr'
|
||||
LEFT JOIN `diaspora-contact` ON `diaspora-contact`.`uri-id` = `ucontact`.`uri-id`
|
||||
LEFT JOIN `gserver` ON `gserver`.`id` = contact.`gsid`;
|
||||
|
||||
--
|
||||
|
|
@ -3006,3 +3007,37 @@ CREATE VIEW `profile_field-view` AS SELECT
|
|||
`profile_field`.`edited` AS `edited`
|
||||
FROM `profile_field`
|
||||
INNER JOIN `permissionset` ON `permissionset`.`id` = `profile_field`.`psid`;
|
||||
|
||||
--
|
||||
-- VIEW diaspora-contact-view
|
||||
--
|
||||
DROP VIEW IF EXISTS `diaspora-contact-view`;
|
||||
CREATE VIEW `diaspora-contact-view` AS SELECT
|
||||
`diaspora-contact`.`uri-id` AS `uri-id`,
|
||||
`item-uri`.`uri` AS `url`,
|
||||
`item-uri`.`guid` AS `guid`,
|
||||
`diaspora-contact`.`addr` AS `addr`,
|
||||
`diaspora-contact`.`alias` AS `alias`,
|
||||
`diaspora-contact`.`nick` AS `nick`,
|
||||
`diaspora-contact`.`name` AS `name`,
|
||||
`diaspora-contact`.`given-name` AS `given-name`,
|
||||
`diaspora-contact`.`family-name` AS `family-name`,
|
||||
`diaspora-contact`.`photo` AS `photo`,
|
||||
`diaspora-contact`.`photo-medium` AS `photo-medium`,
|
||||
`diaspora-contact`.`photo-small` AS `photo-small`,
|
||||
`diaspora-contact`.`batch` AS `batch`,
|
||||
`diaspora-contact`.`notify` AS `notify`,
|
||||
`diaspora-contact`.`poll` AS `poll`,
|
||||
`diaspora-contact`.`subscribe` AS `subscribe`,
|
||||
`diaspora-contact`.`searchable` AS `searchable`,
|
||||
`diaspora-contact`.`pubkey` AS `pubkey`,
|
||||
`gserver`.`url` AS `baseurl`,
|
||||
`diaspora-contact`.`gsid` AS `gsid`,
|
||||
`diaspora-contact`.`created` AS `created`,
|
||||
`diaspora-contact`.`updated` AS `updated`,
|
||||
`diaspora-contact`.`interacting_count` AS `interacting_count`,
|
||||
`diaspora-contact`.`interacted_count` AS `interacted_count`,
|
||||
`diaspora-contact`.`post_count` AS `post_count`
|
||||
FROM `diaspora-contact`
|
||||
INNER JOIN `item-uri` ON `item-uri`.`id` = `diaspora-contact`.`uri-id`
|
||||
LEFT JOIN `gserver` ON `gserver`.`id` = `diaspora-contact`.`gsid`;
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ Database Tables
|
|||
| [contact-relation](help/database/db_contact-relation) | Contact relations |
|
||||
| [conv](help/database/db_conv) | private messages |
|
||||
| [delayed-post](help/database/db_delayed-post) | Posts that are about to be distributed at a later time |
|
||||
| [diaspora-contact](help/database/db_diaspora-contact) | Diaspora compatible contacts - used in the Diaspora implementation |
|
||||
| [diaspora-interaction](help/database/db_diaspora-interaction) | Signed Diaspora Interaction |
|
||||
| [endpoint](help/database/db_endpoint) | ActivityPub endpoints - used in the ActivityPub implementation |
|
||||
| [event](help/database/db_event) | Events |
|
||||
| [fcontact](help/database/db_fcontact) | Diaspora compatible contacts - used in the Diaspora implementation |
|
||||
| [fetch-entry](help/database/db_fetch-entry) | |
|
||||
| [fetched-activity](help/database/db_fetched-activity) | Id of fetched activities |
|
||||
| [fsuggest](help/database/db_fsuggest) | friend suggestion stuff |
|
||||
|
|
|
|||
52
doc/database/db_diaspora-contact.md
Normal file
52
doc/database/db_diaspora-contact.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
Table diaspora-contact
|
||||
===========
|
||||
|
||||
Diaspora compatible contacts - used in the Diaspora implementation
|
||||
|
||||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ----------------- | ------------------------------------------------------------ | ------------ | ---- | --- | ------------------- | ----- |
|
||||
| uri-id | Id of the item-uri table entry that contains the contact URL | int unsigned | NO | PRI | NULL | |
|
||||
| addr | | varchar(255) | YES | | NULL | |
|
||||
| alias | | varchar(255) | YES | | NULL | |
|
||||
| nick | | varchar(255) | YES | | NULL | |
|
||||
| name | | varchar(255) | YES | | NULL | |
|
||||
| given-name | | varchar(255) | YES | | NULL | |
|
||||
| family-name | | varchar(255) | YES | | NULL | |
|
||||
| photo | | varchar(255) | YES | | NULL | |
|
||||
| photo-medium | | varchar(255) | YES | | NULL | |
|
||||
| photo-small | | varchar(255) | YES | | NULL | |
|
||||
| batch | | varchar(255) | YES | | NULL | |
|
||||
| notify | | varchar(255) | YES | | NULL | |
|
||||
| poll | | varchar(255) | YES | | NULL | |
|
||||
| subscribe | | varchar(255) | YES | | NULL | |
|
||||
| searchable | | boolean | YES | | NULL | |
|
||||
| pubkey | | text | YES | | NULL | |
|
||||
| gsid | Global Server ID | int unsigned | YES | | NULL | |
|
||||
| created | | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| updated | | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| interacting_count | Number of contacts this contact interactes with | int unsigned | YES | | 0 | |
|
||||
| interacted_count | Number of contacts that interacted with this contact | int unsigned | YES | | 0 | |
|
||||
| post_count | Number of posts and comments | int unsigned | YES | | 0 | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
||||
| Name | Fields |
|
||||
| ------- | ------------ |
|
||||
| PRIMARY | uri-id |
|
||||
| addr | UNIQUE, addr |
|
||||
| alias | alias |
|
||||
| gsid | gsid |
|
||||
|
||||
Foreign Keys
|
||||
------------
|
||||
|
||||
| Field | Target Table | Target Field |
|
||||
|-------|--------------|--------------|
|
||||
| uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
| gsid | [gserver](help/database/db_gserver) | id |
|
||||
|
||||
Return to [database documentation](help/database)
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
Table fcontact
|
||||
===========
|
||||
|
||||
Diaspora compatible contacts - used in the Diaspora implementation
|
||||
|
||||
Fields
|
||||
------
|
||||
|
||||
| Field | Description | Type | Null | Key | Default | Extra |
|
||||
| ----------------- | ------------------------------------------------------------- | ---------------- | ---- | --- | ------------------- | -------------- |
|
||||
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
|
||||
| guid | unique id | varbinary(255) | NO | | | |
|
||||
| url | | varbinary(383) | NO | | | |
|
||||
| uri-id | Id of the item-uri table entry that contains the fcontact url | int unsigned | YES | | NULL | |
|
||||
| name | | varchar(255) | NO | | | |
|
||||
| photo | | varbinary(383) | NO | | | |
|
||||
| request | | varbinary(383) | NO | | | |
|
||||
| nick | | varchar(255) | NO | | | |
|
||||
| addr | | varchar(255) | NO | | | |
|
||||
| batch | | varbinary(383) | NO | | | |
|
||||
| notify | | varbinary(383) | NO | | | |
|
||||
| poll | | varbinary(383) | NO | | | |
|
||||
| confirm | | varbinary(383) | NO | | | |
|
||||
| priority | | tinyint unsigned | NO | | 0 | |
|
||||
| network | | char(4) | NO | | | |
|
||||
| alias | | varbinary(383) | NO | | | |
|
||||
| pubkey | | text | YES | | NULL | |
|
||||
| created | | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| updated | | datetime | NO | | 0001-01-01 00:00:00 | |
|
||||
| interacting_count | Number of contacts this contact interactes with | int unsigned | YES | | 0 | |
|
||||
| interacted_count | Number of contacts that interacted with this contact | int unsigned | YES | | 0 | |
|
||||
| post_count | Number of posts and comments | int unsigned | YES | | 0 | |
|
||||
|
||||
Indexes
|
||||
------------
|
||||
|
||||
| Name | Fields |
|
||||
| ------- | ---------------- |
|
||||
| PRIMARY | id |
|
||||
| addr | addr(32) |
|
||||
| url | UNIQUE, url(190) |
|
||||
| uri-id | UNIQUE, uri-id |
|
||||
|
||||
Foreign Keys
|
||||
------------
|
||||
|
||||
| Field | Target Table | Target Field |
|
||||
|-------|--------------|--------------|
|
||||
| uri-id | [item-uri](help/database/db_item-uri) | id |
|
||||
|
||||
Return to [database documentation](help/database)
|
||||
|
|
@ -131,9 +131,9 @@ HELP;
|
|||
$this->out('Updating event table fields');
|
||||
$this->database->replaceInTableFields('event', ['uri'], $old_url, $new_url);
|
||||
|
||||
$this->out('Updating fcontact table fields');
|
||||
$this->database->replaceInTableFields('fcontact', ['url', 'photo', 'request', 'batch', 'poll', 'confirm', 'alias'], $old_url, $new_url);
|
||||
$this->database->replaceInTableFields('fcontact', ['addr'], $old_host, $new_host);
|
||||
$this->out('Updating diaspora-contact table fields');
|
||||
$this->database->replaceInTableFields('diaspora-contact', ['alias', 'photo', 'photo-medium', 'photo-small', 'batch', 'notify', 'poll', 'subscribe'], $old_url, $new_url);
|
||||
$this->database->replaceInTableFields('diaspora-contact', ['addr'], $old_host, $new_host);
|
||||
|
||||
$this->out('Updating fsuggest table fields');
|
||||
$this->database->replaceInTableFields('fsuggest', ['url', 'request', 'photo'], $old_url, $new_url);
|
||||
|
|
|
|||
|
|
@ -599,6 +599,11 @@ abstract class DI
|
|||
return self::$dice->create(Protocol\Activity::class);
|
||||
}
|
||||
|
||||
public static function dsprContact(): Protocol\Diaspora\Repository\DiasporaContact
|
||||
{
|
||||
return self::$dice->create(Protocol\Diaspora\Repository\DiasporaContact::class);
|
||||
}
|
||||
|
||||
//
|
||||
// "Security" namespace instances
|
||||
//
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class DBStructure
|
|||
$old_tables = ['fserver', 'gcign', 'gcontact', 'gcontact-relation', 'gfollower' ,'glink', 'item-delivery-data',
|
||||
'item-activity', 'item-content', 'item_id', 'participation', 'poll', 'poll_result', 'queue', 'retriever_rule',
|
||||
'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge',
|
||||
'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation'];
|
||||
'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact'];
|
||||
|
||||
$tables = DBA::selectToArray('INFORMATION_SCHEMA.TABLES', ['TABLE_NAME'],
|
||||
['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']);
|
||||
|
|
|
|||
|
|
@ -833,7 +833,7 @@ class Database
|
|||
/**
|
||||
* Check if data exists
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $condition Array of fields for condition
|
||||
*
|
||||
* @return boolean Are there rows for that condition?
|
||||
|
|
@ -1017,7 +1017,7 @@ class Database
|
|||
/**
|
||||
* Insert a row into a table. Field value objects will be cast as string.
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $param parameter array
|
||||
* @param int $duplicate_mode What to do on a duplicated entry
|
||||
*
|
||||
|
|
@ -1068,7 +1068,7 @@ class Database
|
|||
* Inserts a row with the provided data in the provided table.
|
||||
* If the data corresponds to an existing row through a UNIQUE or PRIMARY index constraints, it updates the row instead.
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $param parameter array
|
||||
* @return boolean was the insert successful?
|
||||
* @throws \Exception
|
||||
|
|
@ -1116,7 +1116,7 @@ class Database
|
|||
*
|
||||
* This function can be extended in the future to accept a table array as well.
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @return boolean was the lock successful?
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
|
@ -1314,7 +1314,7 @@ class Database
|
|||
* Only set $old_fields to a boolean value when you are sure that you will update a single row.
|
||||
* When you set $old_fields to "true" then $fields must contain all relevant fields!
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $fields contains the fields that are updated
|
||||
* @param array $condition condition array with the key values
|
||||
* @param array|boolean $old_fields array with the old field values that are about to be replaced (true = update on duplicate, false = don't update identical fields)
|
||||
|
|
@ -1380,7 +1380,7 @@ class Database
|
|||
/**
|
||||
* Retrieve a single record from a table and returns it in an associative array
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $fields Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
|
|
@ -1406,7 +1406,7 @@ class Database
|
|||
/**
|
||||
* Select rows from a table and fills an array with the data
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $fields Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
|
|
@ -1479,7 +1479,7 @@ class Database
|
|||
*
|
||||
* $data = DBA::select($table, $fields, $condition, $params);
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $fields Array of selected fields, empty for all
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
|
|
@ -1519,7 +1519,7 @@ class Database
|
|||
/**
|
||||
* Counts the rows from a table satisfying the provided condition
|
||||
*
|
||||
* @param string $table Table name in format schema.table (while scheme is optiona)
|
||||
* @param string $table Table name in format [schema.]table
|
||||
* @param array $condition Array of fields for condition
|
||||
* @param array $params Array of several parameters
|
||||
*
|
||||
|
|
|
|||
|
|
@ -899,6 +899,11 @@ class PostUpdate
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!DBStructure::existsTable('fcontact')) {
|
||||
DI::config()->set('system', 'post_update_version', 1425);
|
||||
return true;
|
||||
}
|
||||
|
||||
$condition = ["`uri-id` IS NULL"];
|
||||
Logger::info('Start', ['rest' => DBA::count('fcontact', $condition)]);
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ class Status extends BaseFactory
|
|||
*/
|
||||
public function createFromUriId(int $uriId, int $uid = 0, bool $reblog = true): \Friendica\Object\Api\Mastodon\Status
|
||||
{
|
||||
$fields = ['uri-id', 'uid', 'author-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', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id',
|
||||
'created', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id'];
|
||||
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
|
||||
if (!$item) {
|
||||
|
|
@ -97,9 +97,18 @@ class Status extends BaseFactory
|
|||
throw new HTTPException\NotFoundException('Item with URI ID ' . $uriId . ' not found' . ($uid ? ' for user ' . $uid : '.'));
|
||||
}
|
||||
|
||||
$is_reshare = $reblog && !is_null($item['causer-uri-id']) && ($item['post-reason'] == Item::PR_ANNOUNCEMENT);
|
||||
|
||||
$account = $this->mstdnAccountFactory->createFromUriId($is_reshare ? $item['causer-uri-id']:$item['author-uri-id'], $uid);
|
||||
if (($item['gravity'] == Item::GRAVITY_ACTIVITY) && ($item['vid'] == Verb::getID(Activity::ANNOUNCE))) {
|
||||
$is_reshare = true;
|
||||
$account = $this->mstdnAccountFactory->createFromUriId($item['author-uri-id'], $uid);
|
||||
$uriId = $item['thr-parent-id'];
|
||||
$item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]);
|
||||
if (!$item) {
|
||||
throw new HTTPException\NotFoundException('Item with URI ID ' . $uriId . ' not found' . ($uid ? ' for user ' . $uid : '.'));
|
||||
}
|
||||
} else {
|
||||
$is_reshare = $reblog && !is_null($item['causer-uri-id']) && ($item['causer-id'] != $item['author-id']) && ($item['post-reason'] == Item::PR_ANNOUNCEMENT);
|
||||
$account = $this->mstdnAccountFactory->createFromUriId($is_reshare ? $item['causer-uri-id'] : $item['author-uri-id'], $uid);
|
||||
}
|
||||
|
||||
$count_announce = Post::countPosts([
|
||||
'thr-parent-id' => $uriId,
|
||||
|
|
@ -190,19 +199,13 @@ class Status extends BaseFactory
|
|||
}
|
||||
}
|
||||
|
||||
if ($item['vid'] == Verb::getID(Activity::ANNOUNCE)) {
|
||||
$reshare = $this->createFromUriId($item['thr-parent-id'], $uid)->toArray();
|
||||
$reshared_item = Post::selectFirst(['title', 'body'], ['uri-id' => $item['thr-parent-id'],'uid' => [0, $uid]]);
|
||||
$item['title'] = $reshared_item['title'] ?? $item['title'];
|
||||
$item['body'] = $reshared_item['body'] ?? $item['body'];
|
||||
} else {
|
||||
$item['body'] = $this->contentItem->addSharedPost($item);
|
||||
$item['raw-body'] = $this->contentItem->addSharedPost($item, $item['raw-body']);
|
||||
$reshare = [];
|
||||
}
|
||||
$item['body'] = $this->contentItem->addSharedPost($item);
|
||||
$item['raw-body'] = $this->contentItem->addSharedPost($item, $item['raw-body']);
|
||||
|
||||
if ($is_reshare) {
|
||||
$reshare = $this->createFromUriId($uriId, $uid, false)->toArray();
|
||||
} else {
|
||||
$reshare = [];
|
||||
}
|
||||
|
||||
return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $reshare, $poll);
|
||||
|
|
|
|||
|
|
@ -1395,7 +1395,7 @@ class Contact
|
|||
}
|
||||
|
||||
if ($data['network'] == Protocol::DIASPORA) {
|
||||
FContact::updateFromProbeArray($data);
|
||||
DI::dsprContact()->updateFromProbeArray($data);
|
||||
}
|
||||
|
||||
self::updateFromProbeArray($contact_id, $data);
|
||||
|
|
@ -2486,7 +2486,7 @@ class Contact
|
|||
$ret = Probe::uri($contact['url'], $network, $contact['uid']);
|
||||
|
||||
if ($ret['network'] == Protocol::DIASPORA) {
|
||||
FContact::updateFromProbeArray($ret);
|
||||
DI::dsprContact()->updateFromProbeArray($ret);
|
||||
}
|
||||
|
||||
return self::updateFromProbeArray($id, $ret);
|
||||
|
|
|
|||
|
|
@ -1,161 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Model;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Core\Protocol;
|
||||
use Friendica\Core\Worker;
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Friendica\Util\Strings;
|
||||
|
||||
class FContact
|
||||
{
|
||||
/**
|
||||
* Fetches data for a given handle
|
||||
*
|
||||
* @param string $handle The handle
|
||||
* @param boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||
*
|
||||
* @return array the queried data
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function getByURL(string $handle, $update = null): array
|
||||
{
|
||||
Logger::debug('Fetch fcontact', ['handle' => $handle, 'update' => $update]);
|
||||
$person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'addr' => $handle]);
|
||||
if (!DBA::isResult($person)) {
|
||||
$urls = [$handle, str_replace('http://', 'https://', $handle), Strings::normaliseLink($handle)];
|
||||
$person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'url' => $urls]);
|
||||
}
|
||||
|
||||
if (DBA::isResult($person)) {
|
||||
Logger::debug('In cache', ['handle' => $handle]);
|
||||
|
||||
if (is_null($update)) {
|
||||
$update = empty($person['guid']) || empty($person['uri-id']) || ($person['created'] <= DBA::NULL_DATETIME);
|
||||
if (GServer::getNextUpdateDate(true, $person['created'], $person['updated'], false) < DateTimeFormat::utcNow()) {
|
||||
Logger::debug('Start background update', ['handle' => $handle]);
|
||||
Worker::add(['priority' => Worker::PRIORITY_LOW, 'dont_fork' => true], 'UpdateFContact', $handle);
|
||||
}
|
||||
}
|
||||
} elseif (is_null($update)) {
|
||||
$update = true;
|
||||
} else {
|
||||
$person = [];
|
||||
}
|
||||
|
||||
if ($update) {
|
||||
Logger::info('create or refresh', ['handle' => $handle]);
|
||||
$data = Probe::uri($handle, Protocol::DIASPORA);
|
||||
|
||||
// Note that Friendica contacts will return a "Diaspora person"
|
||||
// if Diaspora connectivity is enabled on their server
|
||||
if ($data['network'] ?? '' === Protocol::DIASPORA) {
|
||||
self::updateFromProbeArray($data);
|
||||
|
||||
$person = self::getByURL($handle, false);
|
||||
}
|
||||
}
|
||||
|
||||
return $person;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the fcontact table
|
||||
*
|
||||
* @param array $arr The fcontact data
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function updateFromProbeArray(array $arr)
|
||||
{
|
||||
$uriid = ItemURI::insert(['uri' => $arr['url'], 'guid' => $arr['guid']]);
|
||||
|
||||
$fcontact = DBA::selectFirst('fcontact', ['created'], ['url' => $arr['url'], 'network' => $arr['network']]);
|
||||
$contact = Contact::getByUriId($uriid, ['id', 'created']);
|
||||
$apcontact = APContact::getByURL($arr['url'], false);
|
||||
if (!empty($apcontact)) {
|
||||
$interacted = $apcontact['following_count'];
|
||||
$interacting = $apcontact['followers_count'];
|
||||
$posts = $apcontact['statuses_count'];
|
||||
} elseif (!empty($contact['id'])) {
|
||||
$last_interaction = DateTimeFormat::utc('now - 180 days');
|
||||
|
||||
$interacted = DBA::count('contact-relation', ["`cid` = ? AND NOT `follows` AND `last-interaction` > ?", $contact['id'], $last_interaction]);
|
||||
$interacting = DBA::count('contact-relation', ["`relation-cid` = ? AND NOT `follows` AND `last-interaction` > ?", $contact['id'], $last_interaction]);
|
||||
$posts = DBA::count('post', ['author-id' => $contact['id'], 'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT]]);
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'name' => $arr['name'],
|
||||
'photo' => $arr['photo'],
|
||||
'request' => $arr['request'],
|
||||
'nick' => $arr['nick'],
|
||||
'addr' => strtolower($arr['addr']),
|
||||
'guid' => $arr['guid'],
|
||||
'batch' => $arr['batch'],
|
||||
'notify' => $arr['notify'],
|
||||
'poll' => $arr['poll'],
|
||||
'confirm' => $arr['confirm'],
|
||||
'alias' => $arr['alias'],
|
||||
'pubkey' => $arr['pubkey'],
|
||||
'uri-id' => $uriid,
|
||||
'interacting_count' => $interacting ?? 0,
|
||||
'interacted_count' => $interacted ?? 0,
|
||||
'post_count' => $posts ?? 0,
|
||||
'updated' => DateTimeFormat::utcNow(),
|
||||
];
|
||||
|
||||
if (empty($fcontact['created'])) {
|
||||
$fields['created'] = $fields['updated'];
|
||||
} elseif (!empty($contact['created']) && ($fcontact['created'] <= DBA::NULL_DATETIME)) {
|
||||
$fields['created'] = $contact['created'];
|
||||
}
|
||||
|
||||
$fields = DI::dbaDefinition()->truncateFieldsForTable('fcontact', $fields);
|
||||
DBA::update('fcontact', $fields, ['url' => $arr['url'], 'network' => $arr['network']], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a url (scheme://domain.tld/u/user) from a given Diaspora*
|
||||
* fcontact guid
|
||||
*
|
||||
* @param string $fcontact_guid Hexadecimal string guid
|
||||
* @return string|null the contact url or null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getUrlByGuid(string $fcontact_guid)
|
||||
{
|
||||
Logger::info('fcontact', ['guid' => $fcontact_guid]);
|
||||
|
||||
$fcontact = DBA::selectFirst('fcontact', ['url'], ["`url` != ? AND `network` = ? AND `guid` = ?", '', Protocol::DIASPORA, $fcontact_guid]);
|
||||
if (DBA::isResult($fcontact)) {
|
||||
return $fcontact['url'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -80,8 +80,15 @@ class Statuses extends BaseApi
|
|||
}
|
||||
|
||||
if (!$request['pinned'] && !$request['only_media']) {
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` IN (?, ?) OR (`gravity` = ? AND `vid` = ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE)]);
|
||||
if ($request['exclude_replies']) {
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` = ? OR (`gravity` = ? AND `vid` = ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE)]);
|
||||
} else {
|
||||
$condition = DBA::mergeConditions($condition, ["(`gravity` IN (?, ?) OR (`gravity` = ? AND `vid` = ?))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE)]);
|
||||
}
|
||||
} elseif ($request['exclude_replies']) {
|
||||
$condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
|
||||
}
|
||||
|
||||
if (!empty($request['max_id'])) {
|
||||
|
|
@ -97,16 +104,10 @@ class Statuses extends BaseApi
|
|||
$params['order'] = ['uri-id'];
|
||||
}
|
||||
|
||||
if (($request['pinned'] || $request['only_media']) && $request['exclude_replies']) {
|
||||
$condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
|
||||
}
|
||||
|
||||
if ($request['pinned']) {
|
||||
$items = DBA::select('collection-view', ['uri-id'], $condition, $params);
|
||||
} elseif ($request['only_media']) {
|
||||
$items = DBA::select('media-view', ['uri-id'], $condition, $params);
|
||||
} elseif ($request['exclude_replies']) {
|
||||
$items = Post::selectThreadForUser($uid, ['uri-id'], $condition, $params);
|
||||
} else {
|
||||
$items = Post::selectForUser($uid, ['uri-id'], $condition, $params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ class Status extends BaseProfile
|
|||
|
||||
$condition = DBA::mergeConditions($condition, ["((`gravity` = ? AND `wall`) OR
|
||||
(`gravity` = ? AND `vid` = ? AND `origin`
|
||||
AND `thr-parent-id` IN (SELECT `uri-id` FROM `post` WHERE `gravity` = ? AND `network` IN (?, ?))))",
|
||||
AND EXISTS(SELECT `uri-id` FROM `post` WHERE `uri-id` = `post-user-view`.`thr-parent-id` AND `gravity` = ? AND `network` IN (?, ?))))",
|
||||
Item::GRAVITY_PARENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), Item::GRAVITY_PARENT, Protocol::ACTIVITYPUB, Protocol::DFRN]);
|
||||
|
||||
$condition = DBA::mergeConditions($condition, ['uid' => $profile['uid'], 'network' => Protocol::FEDERATED,
|
||||
|
|
|
|||
|
|
@ -110,7 +110,8 @@ class Probe
|
|||
*/
|
||||
private static function rearrangeData(array $data): array
|
||||
{
|
||||
$fields = ['name', 'nick', 'guid', 'url', 'addr', 'alias', 'photo', 'header',
|
||||
$fields = ['name', 'given_name', 'family_name', 'nick', 'guid', 'url', 'addr', 'alias',
|
||||
'photo', 'photo_medium', 'photo_small', 'header',
|
||||
'account-type', 'community', 'keywords', 'location', 'about', 'xmpp', 'matrix',
|
||||
'hide', 'batch', 'notify', 'poll', 'request', 'confirm', 'subscribe', 'poco',
|
||||
'following', 'followers', 'inbox', 'outbox', 'sharedinbox',
|
||||
|
|
@ -124,7 +125,7 @@ class Probe
|
|||
if (in_array($field, $numeric_fields)) {
|
||||
$newdata[$field] = (int)$data[$field];
|
||||
} else {
|
||||
$newdata[$field] = $data[$field];
|
||||
$newdata[$field] = trim($data[$field]);
|
||||
}
|
||||
} elseif (!in_array($field, $numeric_fields)) {
|
||||
$newdata[$field] = '';
|
||||
|
|
@ -1290,9 +1291,19 @@ class Probe
|
|||
$data['name'] = $search->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
$search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' given_name ')]", $vcard); // */
|
||||
if ($search->length > 0) {
|
||||
$data["given_name"] = $search->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
$search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' family_name ')]", $vcard); // */
|
||||
if ($search->length > 0) {
|
||||
$data["family_name"] = $search->item(0)->nodeValue;
|
||||
}
|
||||
|
||||
$search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' searchable ')]", $vcard); // */
|
||||
if ($search->length > 0) {
|
||||
$data['searchable'] = $search->item(0)->nodeValue;
|
||||
$data['hide'] = (strtolower($search->item(0)->nodeValue) != 'true');
|
||||
}
|
||||
|
||||
$search = $xpath->query("//*[contains(concat(' ', @class, ' '), ' key ')]", $vcard); // */
|
||||
|
|
@ -1309,7 +1320,7 @@ class Probe
|
|||
}
|
||||
}
|
||||
|
||||
$avatar = [];
|
||||
$avatars = [];
|
||||
if (!empty($vcard)) {
|
||||
$photos = $xpath->query("//*[contains(concat(' ', @class, ' '), ' photo ') or contains(concat(' ', @class, ' '), ' avatar ')]", $vcard); // */
|
||||
foreach ($photos as $photo) {
|
||||
|
|
@ -1319,20 +1330,27 @@ class Probe
|
|||
}
|
||||
|
||||
if (isset($attr['src']) && isset($attr['width'])) {
|
||||
$avatar[$attr['width']] = $attr['src'];
|
||||
$avatars[$attr['width']] = self::fixAvatar($attr['src'], $data['baseurl']);
|
||||
}
|
||||
|
||||
// We don't have a width. So we just take everything that we got.
|
||||
// This is a Hubzilla workaround which doesn't send a width.
|
||||
if ((sizeof($avatar) == 0) && !empty($attr['src'])) {
|
||||
$avatar[] = $attr['src'];
|
||||
if (!$avatars && !empty($attr['src'])) {
|
||||
$avatars[] = self::fixAvatar($attr['src'], $data['baseurl']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sizeof($avatar)) {
|
||||
ksort($avatar);
|
||||
$data['photo'] = self::fixAvatar(array_pop($avatar), $data['baseurl']);
|
||||
if ($avatars) {
|
||||
ksort($avatars);
|
||||
$data['photo'] = array_pop($avatars);
|
||||
if ($avatars) {
|
||||
$data['photo_medium'] = array_pop($avatars);
|
||||
}
|
||||
|
||||
if ($avatars) {
|
||||
$data['photo_small'] = array_pop($avatars);
|
||||
}
|
||||
}
|
||||
|
||||
if ($dfrn) {
|
||||
|
|
@ -1356,7 +1374,6 @@ class Probe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ use Friendica\DI;
|
|||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Conversation;
|
||||
use Friendica\Model\Event;
|
||||
use Friendica\Model\FContact;
|
||||
use Friendica\Model\GServer;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\ItemURI;
|
||||
|
|
@ -45,6 +44,7 @@ use Friendica\Model\Post;
|
|||
use Friendica\Model\Profile;
|
||||
use Friendica\Model\Tag;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Util\Crypto;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
|
@ -981,12 +981,12 @@ class DFRN
|
|||
}
|
||||
}
|
||||
|
||||
$fcontact = FContact::getByURL($contact['addr']);
|
||||
if (empty($fcontact)) {
|
||||
try {
|
||||
$pubkey = DI::dsprContact()->getByAddr(WebFingerUri::fromString($contact['addr']))->pubKey;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
Logger::notice('Unable to find contact details for ' . $contact['id'] . ' - ' . $contact['addr']);
|
||||
return -22;
|
||||
}
|
||||
$pubkey = $fcontact['pubkey'] ?? '';
|
||||
} else {
|
||||
$pubkey = '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ use Friendica\Database\DBA;
|
|||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Conversation;
|
||||
use Friendica\Model\FContact;
|
||||
use Friendica\Model\GServer;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\ItemURI;
|
||||
|
|
@ -42,6 +41,7 @@ use Friendica\Model\Post;
|
|||
use Friendica\Model\Tag;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Util\Crypto;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
|
@ -161,8 +161,12 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$key = self::key($handle);
|
||||
if ($key == '') {
|
||||
try {
|
||||
$key = self::key(WebFingerUri::fromString($handle));
|
||||
if ($key == '') {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::notice("Couldn't get a key for handle " . $handle . ". Discarding.");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -300,8 +304,13 @@ class Diaspora
|
|||
}
|
||||
}
|
||||
|
||||
$key = self::key($author_addr);
|
||||
if ($key == '') {
|
||||
try {
|
||||
$author = WebFingerUri::fromString($author_addr);
|
||||
$key = self::key($author);
|
||||
if ($key == '') {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::notice("Couldn't get a key for handle " . $author_addr . ". Discarding.");
|
||||
if ($no_exit) {
|
||||
return false;
|
||||
|
|
@ -322,8 +331,8 @@ class Diaspora
|
|||
|
||||
return [
|
||||
'message' => (string)Strings::base64UrlDecode($base->data),
|
||||
'author' => XML::unescape($author_addr),
|
||||
'key' => (string)$key
|
||||
'author' => $author->getAddr(),
|
||||
'key' => (string)$key
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -356,7 +365,7 @@ class Diaspora
|
|||
|
||||
if ($children->header) {
|
||||
$public = true;
|
||||
$author_link = str_replace('acct:', '', $children->header->author_id);
|
||||
$idom = $children->header;
|
||||
} else {
|
||||
// This happens with posts from a relais
|
||||
if (empty($privKey)) {
|
||||
|
|
@ -384,8 +393,13 @@ class Diaspora
|
|||
|
||||
$inner_iv = base64_decode($idom->iv);
|
||||
$inner_aes_key = base64_decode($idom->aes_key);
|
||||
}
|
||||
|
||||
$author_link = str_replace('acct:', '', $idom->author_id);
|
||||
try {
|
||||
$author = WebFingerUri::fromString($idom->author_id);
|
||||
} catch (\Throwable $e) {
|
||||
Logger::notice('Could not retrieve author URI.', ['idom' => $idom]);
|
||||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
}
|
||||
|
||||
$dom = $basedom->children(ActivityNamespace::SALMON_ME);
|
||||
|
|
@ -439,17 +453,11 @@ class Diaspora
|
|||
$inner_decrypted = self::aesDecrypt($inner_aes_key, $inner_iv, $inner_encrypted);
|
||||
}
|
||||
|
||||
if (!$author_link) {
|
||||
Logger::notice('Could not retrieve author URI.');
|
||||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
}
|
||||
// Once we have the author URI, go to the web and try to find their public key
|
||||
// (first this will look it up locally if it is in the fcontact cache)
|
||||
// (first this will look it up locally if it is in the diaspora-contact cache)
|
||||
// This will also convert diaspora public key from pkcs#1 to pkcs#8
|
||||
|
||||
Logger::notice('Fetching key for '.$author_link);
|
||||
$key = self::key($author_link);
|
||||
|
||||
Logger::notice('Fetching key for ' . $author);
|
||||
$key = self::key($author);
|
||||
if (!$key) {
|
||||
Logger::notice('Could not retrieve author key.');
|
||||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
|
|
@ -465,9 +473,9 @@ class Diaspora
|
|||
Logger::notice('Message verified.');
|
||||
|
||||
return [
|
||||
'message' => (string)$inner_decrypted,
|
||||
'author' => XML::unescape($author_link),
|
||||
'key' => (string)$key
|
||||
'message' => $inner_decrypted,
|
||||
'author' => $author->getAddr(),
|
||||
'key' => $key
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -520,7 +528,7 @@ class Diaspora
|
|||
{
|
||||
// The sender is the handle of the contact that sent the message.
|
||||
// This will often be different with relayed messages (for example "like" and "comment")
|
||||
$sender = $msg['author'];
|
||||
$sender = WebFingerUri::fromString($msg['author']);
|
||||
|
||||
// This is only needed for private postings since this is already done for public ones before
|
||||
if (is_null($fields)) {
|
||||
|
|
@ -535,7 +543,7 @@ class Diaspora
|
|||
|
||||
$type = $fields->getName();
|
||||
|
||||
Logger::info('Received message', ['type' => $type, 'sender' => $sender, 'user' => $importer['uid']]);
|
||||
Logger::info('Received message', ['type' => $type, 'sender' => $sender->getAddr(), 'user' => $importer['uid']]);
|
||||
|
||||
switch ($type) {
|
||||
case 'account_migration':
|
||||
|
|
@ -743,7 +751,7 @@ class Diaspora
|
|||
}
|
||||
|
||||
if (isset($parent_author_signature)) {
|
||||
$key = self::key($msg['author']);
|
||||
$key = self::key(WebFingerUri::fromString($msg['author']));
|
||||
if (empty($key)) {
|
||||
Logger::info('No key found for parent', ['author' => $msg['author']]);
|
||||
return false;
|
||||
|
|
@ -755,8 +763,12 @@ class Diaspora
|
|||
}
|
||||
}
|
||||
|
||||
$key = self::key($fields->author);
|
||||
if (empty($key)) {
|
||||
try {
|
||||
$key = self::key(WebFingerUri::fromString($fields->author));
|
||||
if (empty($key)) {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Logger::info('No key found', ['author' => $fields->author]);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -772,55 +784,51 @@ class Diaspora
|
|||
/**
|
||||
* Fetches the public key for a given handle
|
||||
*
|
||||
* @param string $handle The handle
|
||||
* @param WebFingerUri $uri The handle
|
||||
*
|
||||
* @return string The public key
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function key(string $handle = null): string
|
||||
private static function key(WebFingerUri $uri): string
|
||||
{
|
||||
$handle = strval($handle);
|
||||
|
||||
Logger::notice('Fetching diaspora key', ['handle' => $handle, 'callstack' => System::callstack(20)]);
|
||||
|
||||
$fcontact = FContact::getByURL($handle);
|
||||
if (!empty($fcontact['pubkey'])) {
|
||||
return $fcontact['pubkey'];
|
||||
Logger::notice('Fetching diaspora key', ['handle' => $uri->getAddr(), 'callstack' => System::callstack(20)]);
|
||||
try {
|
||||
return DI::dsprContact()->getByAddr($uri)->pubKey;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a contact id for a given handle
|
||||
*
|
||||
* @todo Move to Friendica\Model\Contact
|
||||
*
|
||||
* @param int $uid The user id
|
||||
* @param string $handle The handle in the format user@domain.tld
|
||||
* @param int $uid The user id
|
||||
* @param WebFingerUri $uri
|
||||
*
|
||||
* @return array Contact data
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function contactByHandle(int $uid, string $handle): array
|
||||
private static function contactByHandle(int $uid, WebFingerUri $uri): array
|
||||
{
|
||||
return Contact::getByURL($handle, null, [], $uid);
|
||||
return Contact::getByURL($uri->getAddr(), null, [], $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given contact url does support ActivityPub
|
||||
*
|
||||
* @param string $url profile url
|
||||
* @param boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||
* @param string $url profile url or WebFinger address
|
||||
* @param boolean|null $update true = always update, false = never update, null = update when not found or outdated
|
||||
* @return boolean
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function isSupportedByContactUrl(string $url, $update = null)
|
||||
public static function isSupportedByContactUrl(string $url, ?bool $update = null): bool
|
||||
{
|
||||
return !empty(FContact::getByURL($url, $update));
|
||||
$contact = Contact::getByURL($url, $update);
|
||||
|
||||
return DI::dsprContact()->existsByUriId($contact['uri-id'] ?? 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -874,21 +882,22 @@ class Diaspora
|
|||
/**
|
||||
* Fetches the contact id for a handle and checks if posting is allowed
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $handle The checked handle in the format user@domain.tld
|
||||
* @param bool $is_comment Is the check for a comment?
|
||||
* @param array $importer Array of the importer user
|
||||
* @param WebFingerUri $contact_uri The checked contact
|
||||
* @param bool $is_comment Is the check for a comment?
|
||||
*
|
||||
* @return array|bool The contact data or false on error
|
||||
* @throws \Exception
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function allowedContactByHandle(array $importer, string $handle, bool $is_comment = false)
|
||||
private static function allowedContactByHandle(array $importer, WebFingerUri $contact_uri, bool $is_comment = false)
|
||||
{
|
||||
$contact = self::contactByHandle($importer['uid'], $handle);
|
||||
$contact = self::contactByHandle($importer['uid'], $contact_uri);
|
||||
if (!$contact) {
|
||||
Logger::notice('A Contact for handle ' . $handle . ' and user ' . $importer['uid'] . ' was not found');
|
||||
Logger::notice('A Contact for handle ' . $contact_uri . ' and user ' . $importer['uid'] . ' was not found');
|
||||
// If a contact isn't found, we accept it anyway if it is a comment
|
||||
if ($is_comment && ($importer['uid'] != 0)) {
|
||||
return self::contactByHandle(0, $handle);
|
||||
return self::contactByHandle(0, $contact_uri);
|
||||
} elseif ($is_comment) {
|
||||
return $importer;
|
||||
} else {
|
||||
|
|
@ -897,7 +906,7 @@ class Diaspora
|
|||
}
|
||||
|
||||
if (!self::postAllow($importer, $contact, $is_comment)) {
|
||||
Logger::notice('The handle: ' . $handle . ' is not allowed to post to user ' . $importer['uid']);
|
||||
Logger::notice('The handle: ' . $contact_uri . ' is not allowed to post to user ' . $importer['uid']);
|
||||
return false;
|
||||
}
|
||||
return $contact;
|
||||
|
|
@ -966,7 +975,7 @@ class Diaspora
|
|||
// 0 => '[url=/people/0123456789abcdef]Foo Bar[/url]'
|
||||
// 1 => '0123456789abcdef'
|
||||
// 2 => 'Foo Bar'
|
||||
$handle = FContact::getUrlByGuid($match[1]);
|
||||
$handle = DI::dsprContact()->getUrlByGuid($match[1]);
|
||||
|
||||
if ($handle) {
|
||||
$return = '@[url=' . $handle . ']' . $match[2] . '[/url]';
|
||||
|
|
@ -1011,7 +1020,7 @@ class Diaspora
|
|||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function storeByGuid(string $guid, string $server, bool $force)
|
||||
private static function storeByGuid(string $guid, string $server, bool $force)
|
||||
{
|
||||
$serverparts = parse_url($server);
|
||||
|
||||
|
|
@ -1092,25 +1101,27 @@ class Diaspora
|
|||
return self::message($source_xml->root_guid, $server, ++$level);
|
||||
}
|
||||
|
||||
$author = '';
|
||||
$author_handle = '';
|
||||
|
||||
// Fetch the author - for the old and the new Diaspora version
|
||||
if ($source_xml->post->status_message && $source_xml->post->status_message->diaspora_handle) {
|
||||
$author = (string)$source_xml->post->status_message->diaspora_handle;
|
||||
$author_handle = (string)$source_xml->post->status_message->diaspora_handle;
|
||||
} elseif ($source_xml->author && ($source_xml->getName() == 'status_message')) {
|
||||
$author = (string)$source_xml->author;
|
||||
$author_handle = (string)$source_xml->author;
|
||||
}
|
||||
|
||||
// If this isn't a "status_message" then quit
|
||||
if (!$author) {
|
||||
try {
|
||||
$author = WebFingerUri::fromString($author_handle);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// If this isn't a "status_message" then quit
|
||||
Logger::info("Message doesn't seem to be a status message");
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'message' => $x,
|
||||
'author' => $author,
|
||||
'key' => self::key($author)
|
||||
'author' => $author->getAddr(),
|
||||
'key' => self::key($author)
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -1157,15 +1168,15 @@ class Diaspora
|
|||
/**
|
||||
* Fetches the item record of a given guid
|
||||
*
|
||||
* @param int $uid The user id
|
||||
* @param string $guid message guid
|
||||
* @param string $author The handle of the item
|
||||
* @param array $contact The contact of the item owner
|
||||
* @param int $uid The user id
|
||||
* @param string $guid message guid
|
||||
* @param WebFingerUri $author
|
||||
* @param array $contact The contact of the item owner
|
||||
*
|
||||
* @return array|bool the item record or false on failure
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function parentItem(int $uid, string $guid, string $author, array $contact)
|
||||
private static function parentItem(int $uid, string $guid, WebFingerUri $author, array $contact)
|
||||
{
|
||||
$fields = ['id', 'parent', 'body', 'wall', 'uri', 'guid', 'private', 'origin',
|
||||
'author-name', 'author-link', 'author-avatar', 'gravity',
|
||||
|
|
@ -1175,18 +1186,21 @@ class Diaspora
|
|||
$item = Post::selectFirst($fields, $condition);
|
||||
|
||||
if (!DBA::isResult($item)) {
|
||||
$person = FContact::getByURL($author);
|
||||
$result = self::storeByGuid($guid, $person['url'], false);
|
||||
try {
|
||||
$result = self::storeByGuid($guid, DI::dsprContact()->getByAddr($author)->url, false);
|
||||
|
||||
// We don't have an url for items that arrived at the public dispatcher
|
||||
if (!$result && !empty($contact['url'])) {
|
||||
$result = self::storeByGuid($guid, $contact['url'], false);
|
||||
}
|
||||
// We don't have an url for items that arrived at the public dispatcher
|
||||
if (!$result && !empty($contact['url'])) {
|
||||
$result = self::storeByGuid($guid, $contact['url'], false);
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
Logger::info('Fetched missing item ' . $guid . ' - result: ' . $result);
|
||||
if ($result) {
|
||||
Logger::info('Fetched missing item ' . $guid . ' - result: ' . $result);
|
||||
|
||||
$item = Post::selectFirst($fields, $condition);
|
||||
$item = Post::selectFirst($fields, $condition);
|
||||
}
|
||||
} catch (HTTPException\NotFoundException $e) {
|
||||
Logger::notice('Unable to retrieve author details', ['author' => $author->getAddr()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1200,20 +1214,20 @@ class Diaspora
|
|||
}
|
||||
|
||||
/**
|
||||
* returns contact details
|
||||
* returns contact details for the given user
|
||||
*
|
||||
* @param array $def_contact The default contact if the person isn't found
|
||||
* @param array $person The record of the person
|
||||
* @param int $uid The user id
|
||||
* @param array $def_contact The default details if the contact isn't found
|
||||
* @param string $contact_url The url of the contact
|
||||
* @param int $uid The user id
|
||||
*
|
||||
* @return array
|
||||
* 'cid' => contact id
|
||||
* 'network' => network type
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function authorContactByUrl(array $def_contact, array $person, int $uid): array
|
||||
private static function authorContactByUrl(array $def_contact, string $contact_url, int $uid): array
|
||||
{
|
||||
$condition = ['nurl' => Strings::normaliseLink($person['url']), 'uid' => $uid];
|
||||
$condition = ['nurl' => Strings::normaliseLink($contact_url), 'uid' => $uid];
|
||||
$contact = DBA::selectFirst('contact', ['id', 'network'], $condition);
|
||||
if (DBA::isResult($contact)) {
|
||||
$cid = $contact['id'];
|
||||
|
|
@ -1318,21 +1332,27 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveAccountMigration(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$old_handle = XML::unescape($data->author);
|
||||
$new_handle = XML::unescape($data->profile->author);
|
||||
$signature = XML::unescape($data->signature);
|
||||
|
||||
$contact = self::contactByHandle($importer['uid'], $old_handle);
|
||||
if (!$contact) {
|
||||
Logger::notice('Cannot find contact for sender: ' . $old_handle . ' and user ' . $importer['uid']);
|
||||
try {
|
||||
$old_author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$new_author = WebFingerUri::fromString(XML::unescape($data->profile->author));
|
||||
} catch (\Throwable $e) {
|
||||
Logger::notice('Cannot find handles for sender and user', ['data' => $data]);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::notice('Got migration for ' . $old_handle . ', to ' . $new_handle . ' with user ' . $importer['uid']);
|
||||
$signature = XML::unescape($data->signature);
|
||||
|
||||
$contact = self::contactByHandle($importer['uid'], $old_author);
|
||||
if (!$contact) {
|
||||
Logger::notice('Cannot find contact for sender: ' . $old_author . ' and user ' . $importer['uid']);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::notice('Got migration for ' . $old_author . ', to ' . $new_author . ' with user ' . $importer['uid']);
|
||||
|
||||
// Check signature
|
||||
$signed_text = 'AccountMigration:' . $old_handle . ':' . $new_handle;
|
||||
$key = self::key($old_handle);
|
||||
$signed_text = 'AccountMigration:' . $old_author . ':' . $new_author;
|
||||
$key = self::key($old_author);
|
||||
if (!Crypto::rsaVerify($signed_text, $signature, $key, 'sha256')) {
|
||||
Logger::notice('No valid signature for migration.');
|
||||
return false;
|
||||
|
|
@ -1342,9 +1362,9 @@ class Diaspora
|
|||
self::receiveProfile($importer, $data->profile);
|
||||
|
||||
// change the technical stuff in contact
|
||||
$data = Probe::uri($new_handle);
|
||||
$data = Probe::uri($new_author);
|
||||
if ($data['network'] == Protocol::PHANTOM) {
|
||||
Logger::notice("Account for " . $new_handle . " couldn't be probed.");
|
||||
Logger::notice("Account for " . $new_author . " couldn't be probed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1360,7 +1380,7 @@ class Diaspora
|
|||
'network' => $data['network'],
|
||||
];
|
||||
|
||||
Contact::update($fields, ['addr' => $old_handle]);
|
||||
Contact::update($fields, ['addr' => $old_author->getAddr()]);
|
||||
|
||||
Logger::notice('Contacts are updated.');
|
||||
|
||||
|
|
@ -1377,15 +1397,15 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveAccountDeletion(SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
|
||||
$contacts = DBA::select('contact', ['id'], ['addr' => $author]);
|
||||
$contacts = DBA::select('contact', ['id'], ['addr' => $author_handle]);
|
||||
while ($contact = DBA::fetch($contacts)) {
|
||||
Contact::remove($contact['id']);
|
||||
}
|
||||
DBA::close($contacts);
|
||||
|
||||
Logger::notice('Removed contacts for ' . $author);
|
||||
Logger::notice('Removed contacts for ' . $author_handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1393,27 +1413,24 @@ class Diaspora
|
|||
/**
|
||||
* Fetch the uri from our database if we already have this item (maybe from ourselves)
|
||||
*
|
||||
* @param string $author Author handle
|
||||
* @param string $guid Message guid
|
||||
* @param boolean $onlyfound Only return uri when found in the database
|
||||
* @param string $guid Message guid
|
||||
* @param WebFingerUri|null $person_uri Optional person to derive the base URL from
|
||||
*
|
||||
* @return string The constructed uri or the one from our database or empty string on if $onlyfound is true
|
||||
* @return string The constructed uri or the one from our database or empty string
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function getUriFromGuid(string $author, string $guid, bool $onlyfound = false): string
|
||||
private static function getUriFromGuid(string $guid, WebFingerUri $person_uri = null): string
|
||||
{
|
||||
$item = Post::selectFirst(['uri'], ['guid' => $guid]);
|
||||
if (DBA::isResult($item)) {
|
||||
if ($item) {
|
||||
return $item['uri'];
|
||||
} elseif (!$onlyfound) {
|
||||
$person = FContact::getByURL($author);
|
||||
|
||||
$parts = parse_url($person['url']);
|
||||
unset($parts['path']);
|
||||
$host_url = (string)Uri::fromParts($parts);
|
||||
|
||||
return $host_url . '/objects/' . $guid;
|
||||
} elseif ($person_uri) {
|
||||
try {
|
||||
return DI::dsprContact()->selectOneByAddr($person_uri)->baseurl . '/objects/' . $guid;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
|
|
@ -1444,31 +1461,31 @@ class Diaspora
|
|||
continue;
|
||||
}
|
||||
|
||||
$person = FContact::getByURL($match[3]);
|
||||
if (empty($person)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$contact = DI::dsprContact()->getByUrl(new Uri($match[3]));
|
||||
Tag::storeByHash($uriid, $match[1], $contact->name ?: $contact->nick, $contact->url);
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
Tag::storeByHash($uriid, $match[1], $person['name'] ?: $person['nick'], $person['url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an incoming comment
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $sender The sender of the message
|
||||
* @param array $importer Array of the importer user
|
||||
* @param WebFingerUri $sender The sender of the message
|
||||
* @param SimpleXMLElement $data The message object
|
||||
* @param string $xml The original XML of the message
|
||||
* @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH)
|
||||
* @param string $xml The original XML of the message
|
||||
* @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH)
|
||||
*
|
||||
* @return int The message id of the generated comment or "false" if there was an error
|
||||
* @return bool The message id of the generated comment or "false" if there was an error
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function receiveComment(array $importer, string $sender, SimpleXMLElement $data, string $xml, int $direction): bool
|
||||
private static function receiveComment(array $importer, WebFingerUri $sender, SimpleXMLElement $data, string $xml, int $direction): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$parent_guid = XML::unescape($data->parent_guid);
|
||||
$text = XML::unescape($data->text);
|
||||
|
|
@ -1481,7 +1498,7 @@ class Diaspora
|
|||
|
||||
if (isset($data->thread_parent_guid)) {
|
||||
$thread_parent_guid = XML::unescape($data->thread_parent_guid);
|
||||
$thr_parent = self::getUriFromGuid('', $thread_parent_guid, true);
|
||||
$thr_parent = self::getUriFromGuid($thread_parent_guid);
|
||||
} else {
|
||||
$thr_parent = '';
|
||||
}
|
||||
|
|
@ -1505,14 +1522,15 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$person = FContact::getByURL($author);
|
||||
if (!is_array($person)) {
|
||||
Logger::notice('Unable to find author details');
|
||||
try {
|
||||
$author_url = (string)DI::dsprContact()->getByAddr($author)->url;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
Logger::notice('Unable to find author details', ['author' => $author->getAddr()]);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch the contact id - if we know this contact
|
||||
$author_contact = self::authorContactByUrl($contact, $person, $importer['uid']);
|
||||
$author_contact = self::authorContactByUrl($contact, $author_url, $importer['uid']);
|
||||
|
||||
$datarray = [];
|
||||
|
||||
|
|
@ -1520,17 +1538,17 @@ class Diaspora
|
|||
$datarray['contact-id'] = $author_contact['cid'];
|
||||
$datarray['network'] = $author_contact['network'];
|
||||
|
||||
$datarray['author-link'] = $person['url'];
|
||||
$datarray['author-id'] = Contact::getIdForURL($person['url'], 0);
|
||||
$datarray['author-link'] = $author_url;
|
||||
$datarray['author-id'] = Contact::getIdForURL($author_url);
|
||||
|
||||
$datarray['owner-link'] = $contact['url'];
|
||||
$datarray['owner-id'] = Contact::getIdForURL($contact['url'], 0);
|
||||
$datarray['owner-id'] = Contact::getIdForURL($contact['url']);
|
||||
|
||||
// Will be overwritten for sharing accounts in Item::insert
|
||||
$datarray = self::setDirection($datarray, $direction);
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = self::getUriFromGuid($guid, $author);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
$datarray['verb'] = Activity::POST;
|
||||
|
|
@ -1551,7 +1569,7 @@ class Diaspora
|
|||
$datarray['plink'] = self::plink($author, $guid, $toplevel_parent_item['guid']);
|
||||
$body = Markdown::toBBCode($text);
|
||||
|
||||
$datarray['body'] = self::replacePeopleGuid($body, $person['url']);
|
||||
$datarray['body'] = self::replacePeopleGuid($body, $author_url);
|
||||
|
||||
self::storeMentions($datarray['uri-id'], $text);
|
||||
Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray['body']);
|
||||
|
|
@ -1601,20 +1619,26 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveConversationMessage(array $importer, array $contact, SimpleXMLElement $data, array $msg, $mesg, array $conversation): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
$guid = XML::unescape($data->guid);
|
||||
$subject = XML::unescape($data->subject);
|
||||
|
||||
// "diaspora_handle" is the element name from the old version
|
||||
// "author" is the element name from the new version
|
||||
if ($mesg->author) {
|
||||
$msg_author = XML::unescape($mesg->author);
|
||||
$msg_author_handle = XML::unescape($mesg->author);
|
||||
} elseif ($mesg->diaspora_handle) {
|
||||
$msg_author = XML::unescape($mesg->diaspora_handle);
|
||||
$msg_author_handle = XML::unescape($mesg->diaspora_handle);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$msg_author_uri = WebFingerUri::fromString($msg_author_handle);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$msg_guid = XML::unescape($mesg->guid);
|
||||
$msg_conversation_guid = XML::unescape($mesg->conversation_guid);
|
||||
$msg_text = XML::unescape($mesg->text);
|
||||
|
|
@ -1625,23 +1649,20 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$body = Markdown::toBBCode($msg_text);
|
||||
$message_uri = $msg_author . ':' . $msg_guid;
|
||||
|
||||
$person = FContact::getByURL($msg_author);
|
||||
$msg_author = DI::dsprContact()->getByAddr($msg_author_uri);
|
||||
|
||||
return Mail::insert([
|
||||
'uid' => $importer['uid'],
|
||||
'guid' => $msg_guid,
|
||||
'convid' => $conversation['id'],
|
||||
'from-name' => $person['name'],
|
||||
'from-photo' => $person['photo'],
|
||||
'from-url' => $person['url'],
|
||||
'from-name' => $msg_author->name,
|
||||
'from-photo' => (string)$msg_author->photo,
|
||||
'from-url' => (string)$msg_author->url,
|
||||
'contact-id' => $contact['id'],
|
||||
'title' => $subject,
|
||||
'body' => $body,
|
||||
'uri' => $message_uri,
|
||||
'parent-uri' => $author . ':' . $guid,
|
||||
'body' => Markdown::toBBCode($msg_text),
|
||||
'uri' => $msg_author_handle . ':' . $msg_guid,
|
||||
'parent-uri' => $author_handle . ':' . $guid,
|
||||
'created' => $msg_created_at
|
||||
]);
|
||||
}
|
||||
|
|
@ -1658,7 +1679,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveConversation(array $importer, array $msg, SimpleXMLElement $data)
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
$guid = XML::unescape($data->guid);
|
||||
$subject = XML::unescape($data->subject);
|
||||
$created_at = DateTimeFormat::utc(XML::unescape($data->created_at));
|
||||
|
|
@ -1671,7 +1692,7 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$contact = self::allowedContactByHandle($importer, $msg['author'], true);
|
||||
$contact = self::allowedContactByHandle($importer, WebFingerUri::fromString($msg['author']), true);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1685,7 +1706,7 @@ class Diaspora
|
|||
$r = DBA::insert('conv', [
|
||||
'uid' => $importer['uid'],
|
||||
'guid' => $guid,
|
||||
'creator' => $author,
|
||||
'creator' => $author_handle,
|
||||
'created' => $created_at,
|
||||
'updated' => DateTimeFormat::utcNow(),
|
||||
'subject' => $subject,
|
||||
|
|
@ -1711,18 +1732,18 @@ class Diaspora
|
|||
/**
|
||||
* Processes "like" messages
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $sender The sender of the message
|
||||
* @param array $importer Array of the importer user
|
||||
* @param WebFingerUri $sender The sender of the message
|
||||
* @param SimpleXMLElement $data The message object
|
||||
* @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH)
|
||||
* @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH)
|
||||
*
|
||||
* @return bool Success or failure
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function receiveLike(array $importer, string $sender, SimpleXMLElement $data, int $direction): bool
|
||||
private static function receiveLike(array $importer, WebFingerUri $sender, SimpleXMLElement $data, int $direction): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$parent_guid = XML::unescape($data->parent_guid);
|
||||
$parent_type = XML::unescape($data->parent_type);
|
||||
|
|
@ -1753,14 +1774,15 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$person = FContact::getByURL($author);
|
||||
if (!is_array($person)) {
|
||||
Logger::notice('Unable to find author details');
|
||||
try {
|
||||
$author_url = (string)DI::dsprContact()->getByAddr($author)->url;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
Logger::notice('Unable to find author details', ['author' => $author->getAddr()]);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch the contact id - if we know this contact
|
||||
$author_contact = self::authorContactByUrl($contact, $person, $importer['uid']);
|
||||
$author_contact = self::authorContactByUrl($contact, $author_url, $importer['uid']);
|
||||
|
||||
// "positive" = "false" would be a Dislike - wich isn't currently supported by Diaspora
|
||||
// We would accept this anyhow.
|
||||
|
|
@ -1780,11 +1802,11 @@ class Diaspora
|
|||
|
||||
$datarray = self::setDirection($datarray, $direction);
|
||||
|
||||
$datarray['owner-link'] = $datarray['author-link'] = $person['url'];
|
||||
$datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($person['url'], 0);
|
||||
$datarray['owner-link'] = $datarray['author-link'] = $author_url;
|
||||
$datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($author_url);
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = self::getUriFromGuid($guid, $author);
|
||||
|
||||
$datarray['verb'] = $verb;
|
||||
$datarray['gravity'] = Item::GRAVITY_ACTIVITY;
|
||||
|
|
@ -1843,13 +1865,13 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveMessage(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_uri = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$conversation_guid = XML::unescape($data->conversation_guid);
|
||||
$text = XML::unescape($data->text);
|
||||
$created_at = DateTimeFormat::utc(XML::unescape($data->created_at));
|
||||
|
||||
$contact = self::allowedContactByHandle($importer, $author, true);
|
||||
$contact = self::allowedContactByHandle($importer, $author_uri, true);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1858,41 +1880,37 @@ class Diaspora
|
|||
GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA);
|
||||
}
|
||||
|
||||
$conversation = null;
|
||||
|
||||
$condition = ['uid' => $importer['uid'], 'guid' => $conversation_guid];
|
||||
$conversation = DBA::selectFirst('conv', [], $condition);
|
||||
|
||||
if (!DBA::isResult($conversation)) {
|
||||
Logger::notice('Conversation not available.');
|
||||
return false;
|
||||
}
|
||||
|
||||
$message_uri = $author . ':' . $guid;
|
||||
|
||||
$person = FContact::getByURL($author);
|
||||
if (!$person) {
|
||||
Logger::notice('Unable to find author details');
|
||||
try {
|
||||
$author = DI::dsprContact()->getByAddr($author_uri);
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
Logger::notice('Unable to find author details', ['author' => $author_uri->getAddr()]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = Markdown::toBBCode($text);
|
||||
|
||||
$body = self::replacePeopleGuid($body, $person['url']);
|
||||
$body = self::replacePeopleGuid($body, $author->url);
|
||||
|
||||
return Mail::insert([
|
||||
'uid' => $importer['uid'],
|
||||
'guid' => $guid,
|
||||
'convid' => $conversation['id'],
|
||||
'from-name' => $person['name'],
|
||||
'from-photo' => $person['photo'],
|
||||
'from-url' => $person['url'],
|
||||
'from-name' => $author->name,
|
||||
'from-photo' => (string)$author->photo,
|
||||
'from-url' => (string)$author->url,
|
||||
'contact-id' => $contact['id'],
|
||||
'title' => $conversation['subject'],
|
||||
'body' => $body,
|
||||
'reply' => 1,
|
||||
'uri' => $message_uri,
|
||||
'parent-uri' => $author . ':' . $conversation['guid'],
|
||||
'uri' => $author_uri . ':' . $guid,
|
||||
'parent-uri' => $author_uri . ':' . $conversation['guid'],
|
||||
'created' => $created_at
|
||||
]);
|
||||
}
|
||||
|
|
@ -1910,7 +1928,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveParticipation(array $importer, SimpleXMLElement $data, int $direction): bool
|
||||
{
|
||||
$author = strtolower(XML::unescape($data->author));
|
||||
$author = WebFingerUri::fromString(strtolower(XML::unescape($data->author)));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$parent_guid = XML::unescape($data->parent_guid);
|
||||
|
||||
|
|
@ -1941,13 +1959,14 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$person = FContact::getByURL($author);
|
||||
if (!is_array($person)) {
|
||||
Logger::notice('Person not found: ' . $author);
|
||||
try {
|
||||
$author_url = (string)DI::dsprContact()->getByAddr($author)->url;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
Logger::notice('unable to find author details', ['author' => $author->getAddr()]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$author_contact = self::authorContactByUrl($contact, $person, $importer['uid']);
|
||||
$author_contact = self::authorContactByUrl($contact, $author_url, $importer['uid']);
|
||||
|
||||
// Store participation
|
||||
$datarray = [];
|
||||
|
|
@ -1960,11 +1979,11 @@ class Diaspora
|
|||
|
||||
$datarray = self::setDirection($datarray, $direction);
|
||||
|
||||
$datarray['owner-link'] = $datarray['author-link'] = $person['url'];
|
||||
$datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($person['url'], 0);
|
||||
$datarray['owner-link'] = $datarray['author-link'] = $author_url;
|
||||
$datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($author_url);
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = self::getUriFromGuid($guid, $author);
|
||||
|
||||
$datarray['verb'] = Activity::FOLLOW;
|
||||
$datarray['gravity'] = Item::GRAVITY_ACTIVITY;
|
||||
|
|
@ -2056,7 +2075,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveProfile(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = strtolower(XML::unescape($data->author));
|
||||
$author = WebFingerUri::fromString(strtolower(XML::unescape($data->author)));
|
||||
|
||||
$contact = self::contactByHandle($importer['uid'], $author);
|
||||
if (!$contact) {
|
||||
|
|
@ -2084,16 +2103,13 @@ class Diaspora
|
|||
|
||||
$keywords = implode(', ', $keywords);
|
||||
|
||||
$handle_parts = explode('@', $author);
|
||||
$nick = $handle_parts[0];
|
||||
|
||||
if ($name === '') {
|
||||
$name = $handle_parts[0];
|
||||
$name = $author->getUser();
|
||||
}
|
||||
|
||||
if (preg_match('|^https?://|', $image_url) === 0) {
|
||||
// @TODO No HTTPS here?
|
||||
$image_url = 'http://' . $handle_parts[1] . $image_url;
|
||||
$image_url = 'http://' . $author->getFullHost() . $image_url;
|
||||
}
|
||||
|
||||
Contact::updateAvatar($contact['id'], $image_url);
|
||||
|
|
@ -2115,7 +2131,7 @@ class Diaspora
|
|||
|
||||
$fields = ['name' => $name, 'location' => $location,
|
||||
'name-date' => DateTimeFormat::utcNow(), 'about' => $about,
|
||||
'addr' => $author, 'nick' => $nick, 'keywords' => $keywords,
|
||||
'addr' => $author->getAddr(), 'nick' => $author->getUser(), 'keywords' => $keywords,
|
||||
'unsearchable' => !$searchable, 'sensitive' => $nsfw];
|
||||
|
||||
if (!empty($birthday)) {
|
||||
|
|
@ -2158,13 +2174,15 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveContactRequest(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
$recipient = XML::unescape($data->recipient);
|
||||
|
||||
if (!$author || !$recipient) {
|
||||
if (!$author_handle || !$recipient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$author = WebFingerUri::fromString($author_handle);
|
||||
|
||||
// the current protocol version doesn't know these fields
|
||||
// That means that we will assume their existance
|
||||
if (isset($data->following)) {
|
||||
|
|
@ -2222,22 +2240,24 @@ class Diaspora
|
|||
Logger::info("Author " . $author . " wants to listen to us.");
|
||||
}
|
||||
|
||||
$ret = FContact::getByURL($author);
|
||||
|
||||
if (!$ret || ($ret['network'] != Protocol::DIASPORA)) {
|
||||
Logger::notice("Cannot resolve diaspora handle " . $author . " for ".$recipient);
|
||||
try {
|
||||
$author_url = (string)DI::dsprContact()->getByAddr($author)->url;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
Logger::notice('Cannot resolve diaspora handle for recipient', ['author' => $author->getAddr(), 'recipient' => $recipient]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cid = Contact::getIdForURL($ret['url'], $importer['uid']);
|
||||
$cid = Contact::getIdForURL($author_url, $importer['uid']);
|
||||
if (!empty($cid)) {
|
||||
$contact = DBA::selectFirst('contact', [], ['id' => $cid, 'network' => Protocol::NATIVE_SUPPORT]);
|
||||
} else {
|
||||
$contact = [];
|
||||
}
|
||||
|
||||
$item = ['author-id' => Contact::getIdForURL($ret['url']),
|
||||
'author-link' => $ret['url']];
|
||||
$item = [
|
||||
'author-id' => Contact::getIdForURL($author_url),
|
||||
'author-link' => $author_url
|
||||
];
|
||||
|
||||
$result = Contact::addRelationship($importer, $contact, $item, false);
|
||||
if ($result === true) {
|
||||
|
|
@ -2262,12 +2282,15 @@ class Diaspora
|
|||
/**
|
||||
* Stores a reshare activity
|
||||
*
|
||||
* @param array $item Array of reshare post
|
||||
* @param integer $parent_message_id Id of the parent post
|
||||
* @param string $guid GUID string of reshare action
|
||||
* @param string $author Author handle
|
||||
* @param array $item Array of reshare post
|
||||
* @param integer $parent_message_id Id of the parent post
|
||||
* @param string $guid GUID string of reshare action
|
||||
* @param WebFingerUri $author Author handle
|
||||
* @return false|void
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function addReshareActivity(array $item, int $parent_message_id, string $guid, string $author)
|
||||
private static function addReshareActivity(array $item, int $parent_message_id, string $guid, WebFingerUri $author)
|
||||
{
|
||||
$parent = Post::selectFirst(['uri', 'guid'], ['id' => $parent_message_id]);
|
||||
|
||||
|
|
@ -2284,7 +2307,7 @@ class Diaspora
|
|||
$datarray['owner-id'] = $datarray['author-id'];
|
||||
|
||||
$datarray['guid'] = $parent['guid'] . '-' . $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $datarray['guid']);
|
||||
$datarray['uri'] = self::getUriFromGuid($datarray['guid'], $author);
|
||||
$datarray['thr-parent'] = $parent['uri'];
|
||||
|
||||
$datarray['verb'] = $datarray['body'] = Activity::ANNOUNCE;
|
||||
|
|
@ -2329,15 +2352,20 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveReshare(array $importer, SimpleXMLElement $data, string $xml, int $direction): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$created_at = DateTimeFormat::utc(XML::unescape($data->created_at));
|
||||
$root_author = XML::unescape($data->root_author);
|
||||
try {
|
||||
$root_author = WebFingerUri::fromString(XML::unescape($data->root_author));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$root_guid = XML::unescape($data->root_guid);
|
||||
/// @todo handle unprocessed property "provider_display_name"
|
||||
$public = XML::unescape($data->public);
|
||||
|
||||
$contact = self::allowedContactByHandle($importer, $author, false);
|
||||
$contact = self::allowedContactByHandle($importer, $author);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2351,8 +2379,9 @@ class Diaspora
|
|||
return true;
|
||||
}
|
||||
|
||||
$original_person = FContact::getByURL($root_author);
|
||||
if (!$original_person) {
|
||||
try {
|
||||
$original_person = DI::dsprContact()->getByAddr($root_author);
|
||||
} catch (HTTPException\NotFoundException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2369,7 +2398,7 @@ class Diaspora
|
|||
$datarray['owner-id'] = $datarray['author-id'];
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($guid, $author);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
$datarray['verb'] = Activity::POST;
|
||||
|
|
@ -2380,7 +2409,7 @@ class Diaspora
|
|||
|
||||
$datarray = self::setDirection($datarray, $direction);
|
||||
|
||||
$datarray['quote-uri-id'] = self::getQuoteUriId($root_guid, $importer['uid'], $original_person['url']);
|
||||
$datarray['quote-uri-id'] = self::getQuoteUriId($root_guid, $importer['uid'], $original_person->url);
|
||||
if (empty($datarray['quote-uri-id'])) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2448,19 +2477,18 @@ class Diaspora
|
|||
*/
|
||||
private static function itemRetraction(array $importer, array $contact, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_uri = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$target_guid = XML::unescape($data->target_guid);
|
||||
$target_type = XML::unescape($data->target_type);
|
||||
|
||||
$person = FContact::getByURL($author);
|
||||
if (!is_array($person)) {
|
||||
Logger::notice('Unable to find author detail for ' . $author);
|
||||
try {
|
||||
$author = DI::dsprContact()->getByAddr($author_uri);
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
Logger::notice('Unable to find details for author', ['author' => $author_uri->getAddr()]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($contact['url'])) {
|
||||
$contact['url'] = $person['url'];
|
||||
}
|
||||
$contact_url = $contact['url'] ?? '' ?: (string)$author->url;
|
||||
|
||||
// Fetch items that are about to be deleted
|
||||
$fields = ['uid', 'id', 'parent', 'author-link', 'uri-id'];
|
||||
|
|
@ -2488,8 +2516,8 @@ class Diaspora
|
|||
$parent = Post::selectFirst(['author-link'], ['id' => $item['parent']]);
|
||||
|
||||
// Only delete it if the parent author really fits
|
||||
if (!Strings::compareLink($parent['author-link'], $contact['url']) && !Strings::compareLink($item['author-link'], $contact['url'])) {
|
||||
Logger::info("Thread author " . $parent['author-link'] . " and item author " . $item['author-link'] . " don't fit to expected contact " . $contact['url']);
|
||||
if (!Strings::compareLink($parent['author-link'], $contact_url) && !Strings::compareLink($item['author-link'], $contact_url)) {
|
||||
Logger::info("Thread author " . $parent['author-link'] . " and item author " . $item['author-link'] . " don't fit to expected contact " . $contact_url);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2505,14 +2533,14 @@ class Diaspora
|
|||
/**
|
||||
* Receives retraction messages
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $sender The sender of the message
|
||||
* @param array $importer Array of the importer user
|
||||
* @param WebFingerUri $sender The sender of the message
|
||||
* @param SimpleXMLElement $data The message object
|
||||
*
|
||||
* @return bool Success
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function receiveRetraction(array $importer, string $sender, SimpleXMLElement $data)
|
||||
private static function receiveRetraction(array $importer, WebFingerUri $sender, SimpleXMLElement $data)
|
||||
{
|
||||
$target_type = XML::unescape($data->target_type);
|
||||
|
||||
|
|
@ -2639,14 +2667,14 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveStatusMessage(array $importer, SimpleXMLElement $data, string $xml, int $direction)
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$created_at = DateTimeFormat::utc(XML::unescape($data->created_at));
|
||||
$public = XML::unescape($data->public);
|
||||
$text = XML::unescape($data->text);
|
||||
$provider_display_name = XML::unescape($data->provider_display_name);
|
||||
|
||||
$contact = self::allowedContactByHandle($importer, $author, false);
|
||||
$contact = self::allowedContactByHandle($importer, $author);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2672,7 +2700,7 @@ class Diaspora
|
|||
$datarray = [];
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($guid, $author);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
// Attach embedded pictures to the body
|
||||
|
|
@ -2954,13 +2982,13 @@ class Diaspora
|
|||
|
||||
$logid = Strings::getRandomHex(4);
|
||||
|
||||
// We always try to use the data from the fcontact table.
|
||||
// We always try to use the data from the diaspora-contact table.
|
||||
// This is important for transmitting data to Friendica servers.
|
||||
if (!empty($contact['addr'])) {
|
||||
$fcontact = FContact::getByURL($contact['addr']);
|
||||
if (!empty($fcontact)) {
|
||||
$dest_url = ($public_batch ? $fcontact['batch'] : $fcontact['notify']);
|
||||
}
|
||||
try {
|
||||
$target = DI::dsprContact()->getByAddr(WebFingerUri::fromString($contact['addr']));
|
||||
$dest_url = $public_batch ? $target->batch : $target->notify;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
|
||||
}
|
||||
|
||||
if (empty($dest_url)) {
|
||||
|
|
@ -3029,18 +3057,19 @@ class Diaspora
|
|||
}
|
||||
|
||||
// When sending content to Friendica contacts using the Diaspora protocol
|
||||
// we have to fetch the public key from the fcontact.
|
||||
// we have to fetch the public key from the diaspora-contact.
|
||||
// This is due to the fact that legacy DFRN had unique keys for every contact.
|
||||
$pubkey = $contact['pubkey'];
|
||||
if (!empty($contact['addr'])) {
|
||||
$fcontact = FContact::getByURL($contact['addr']);
|
||||
if (!empty($fcontact)) {
|
||||
$pubkey = $fcontact['pubkey'];
|
||||
try {
|
||||
$pubkey = DI::dsprContact()->getByAddr(WebFingerUri::fromString($contact['addr']))->pubKey;
|
||||
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {
|
||||
|
||||
}
|
||||
} else {
|
||||
// The "addr" field should always be filled.
|
||||
// If this isn't the case, it will raise a notice some lines later.
|
||||
// And in the log we will see where it came from and we can handle it there.
|
||||
// And in the log we will see where it came from, and we can handle it there.
|
||||
Logger::notice('Empty addr', ['contact' => $contact ?? [], 'callstack' => System::callstack(20)]);
|
||||
}
|
||||
|
||||
|
|
@ -3089,16 +3118,16 @@ class Diaspora
|
|||
$owner = User::getOwnerDataById($item['uid']);
|
||||
}
|
||||
|
||||
$author = self::myHandle($owner);
|
||||
$author_handle = self::myHandle($owner);
|
||||
|
||||
$message = [
|
||||
'author' => $author,
|
||||
'author' => $author_handle,
|
||||
'guid' => System::createUUID(),
|
||||
'parent_type' => 'Post',
|
||||
'parent_guid' => $item['guid']
|
||||
];
|
||||
|
||||
Logger::info('Send participation for ' . $item['guid'] . ' by ' . $author);
|
||||
Logger::info('Send participation for ' . $item['guid'] . ' by ' . $author_handle);
|
||||
|
||||
// It doesn't matter what we store, we only want to avoid sending repeated notifications for the same item
|
||||
DI::cache()->set($cachekey, $item['guid'], Duration::QUARTER_HOUR);
|
||||
|
|
@ -4024,6 +4053,8 @@ class Diaspora
|
|||
*
|
||||
* @param integer $parent_id
|
||||
* @return boolean
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function parentSupportDiaspora(int $parent_id): bool
|
||||
{
|
||||
|
|
@ -4033,7 +4064,7 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
if (empty(FContact::getByURL($parent_post['author-link'], false))) {
|
||||
if (!self::isSupportedByContactUrl($parent_post['author-link'], false)) {
|
||||
Logger::info('Parent author is no Diaspora contact.', ['parent-id' => $parent_id]);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
140
src/Protocol/Diaspora/Entity/DiasporaContact.php
Normal file
140
src/Protocol/Diaspora/Entity/DiasporaContact.php
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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\Protocol\Diaspora\Entity;
|
||||
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @property-read $uriId
|
||||
* @property-read $url
|
||||
* @property-read $guid
|
||||
* @property-read $addr
|
||||
* @property-read $alias
|
||||
* @property-read $nick
|
||||
* @property-read $name
|
||||
* @property-read $givenName
|
||||
* @property-read $familyName
|
||||
* @property-read $photo
|
||||
* @property-read $photoMedium
|
||||
* @property-read $photoSmall
|
||||
* @property-read $batch
|
||||
* @property-read $notify
|
||||
* @property-read $poll
|
||||
* @property-read $subscribe
|
||||
* @property-read $searchable
|
||||
* @property-read $pubKey
|
||||
* @property-read $baseurl
|
||||
* @property-read $gsid
|
||||
* @property-read $created
|
||||
* @property-read $updated
|
||||
* @property-read $interacting_count
|
||||
* @property-read $interacted_count
|
||||
* @property-read $post_count
|
||||
*/
|
||||
class DiasporaContact extends \Friendica\BaseEntity
|
||||
{
|
||||
/** @var int */
|
||||
protected $uriId;
|
||||
/** @var UriInterface */
|
||||
protected $url;
|
||||
/** @var string */
|
||||
protected $guid;
|
||||
/** @var string */
|
||||
protected $addr;
|
||||
/** @var UriInterface */
|
||||
protected $alias;
|
||||
/** @var string */
|
||||
protected $nick;
|
||||
/** @var string */
|
||||
protected $name;
|
||||
/** @var string */
|
||||
protected $givenName;
|
||||
/** @var string */
|
||||
protected $familyName;
|
||||
/** @var UriInterface */
|
||||
protected $photo;
|
||||
/** @var UriInterface */
|
||||
protected $photoMedium;
|
||||
/** @var UriInterface */
|
||||
protected $photoSmall;
|
||||
/** @var UriInterface */
|
||||
protected $batch;
|
||||
/** @var UriInterface */
|
||||
protected $notify;
|
||||
/** @var UriInterface */
|
||||
protected $poll;
|
||||
/** @var UriInterface */
|
||||
protected $subscribe;
|
||||
/** @var bool */
|
||||
protected $searchable;
|
||||
/** @var string */
|
||||
protected $pubKey;
|
||||
/** @var UriInterface */
|
||||
protected $baseurl;
|
||||
/** @var int */
|
||||
protected $gsid;
|
||||
/** @var \DateTime */
|
||||
protected $created;
|
||||
/** @var \DateTime */
|
||||
protected $updated;
|
||||
/** @var int */
|
||||
protected $interacting_count;
|
||||
/** @var int */
|
||||
protected $interacted_count;
|
||||
/** @var int */
|
||||
protected $post_count;
|
||||
|
||||
public function __construct(
|
||||
UriInterface $url, \DateTime $created, string $guid = null, string $addr = null, UriInterface $alias = null,
|
||||
string $nick = null, string $name = null, string $givenName = null, string $familyName = null,
|
||||
UriInterface $photo = null, UriInterface $photoMedium = null, UriInterface $photoSmall = null,
|
||||
UriInterface $batch = null, UriInterface $notify = null, UriInterface $poll = null, UriInterface $subscribe = null,
|
||||
bool $searchable = null, string $pubKey = null, UriInterface $baseurl = null, int $gsid = null,
|
||||
\DateTime $updated = null, int $interacting_count = 0, int $interacted_count = 0, int $post_count = 0, int $uriId = null
|
||||
) {
|
||||
$this->uriId = $uriId;
|
||||
$this->url = $url;
|
||||
$this->guid = $guid;
|
||||
$this->addr = $addr;
|
||||
$this->alias = $alias;
|
||||
$this->nick = $nick;
|
||||
$this->name = $name;
|
||||
$this->givenName = $givenName;
|
||||
$this->familyName = $familyName;
|
||||
$this->photo = $photo;
|
||||
$this->photoMedium = $photoMedium;
|
||||
$this->photoSmall = $photoSmall;
|
||||
$this->batch = $batch;
|
||||
$this->notify = $notify;
|
||||
$this->poll = $poll;
|
||||
$this->subscribe = $subscribe;
|
||||
$this->searchable = $searchable;
|
||||
$this->pubKey = $pubKey;
|
||||
$this->baseurl = $baseurl;
|
||||
$this->gsid = $gsid;
|
||||
$this->created = $created;
|
||||
$this->updated = $updated;
|
||||
$this->interacting_count = $interacting_count;
|
||||
$this->interacted_count = $interacted_count;
|
||||
$this->post_count = $post_count;
|
||||
}
|
||||
}
|
||||
102
src/Protocol/Diaspora/Factory/DiasporaContact.php
Normal file
102
src/Protocol/Diaspora/Factory/DiasporaContact.php
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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\Protocol\Diaspora\Factory;
|
||||
|
||||
use Friendica\Capabilities\ICanCreateFromTableRow;
|
||||
use Friendica\Database\DBA;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
|
||||
class DiasporaContact extends \Friendica\BaseFactory implements ICanCreateFromTableRow
|
||||
{
|
||||
public function createFromTableRow(array $row): \Friendica\Protocol\Diaspora\Entity\DiasporaContact
|
||||
{
|
||||
return new \Friendica\Protocol\Diaspora\Entity\DiasporaContact(
|
||||
new Uri($row['url']),
|
||||
new \DateTime($row['created'], new \DateTimeZone('UTC')),
|
||||
$row['guid'],
|
||||
$row['addr'],
|
||||
$row['alias'] ? new Uri($row['alias']) : null,
|
||||
$row['nick'],
|
||||
$row['name'],
|
||||
$row['given-name'],
|
||||
$row['family-name'],
|
||||
$row['photo'] ? new Uri($row['photo']) : null,
|
||||
$row['photo-medium'] ? new Uri($row['photo-medium']) : null,
|
||||
$row['photo-small'] ? new Uri($row['photo-small']) : null,
|
||||
$row['batch'] ? new Uri($row['batch']) : null,
|
||||
$row['notify'] ? new Uri($row['notify']) : null,
|
||||
$row['poll'] ? new Uri($row['poll']) : null,
|
||||
$row['subscribe'] ? new Uri($row['subscribe']) : null,
|
||||
$row['searchable'],
|
||||
$row['pubkey'],
|
||||
$row['baseurl'] ? new Uri($row['baseurl']) : null,
|
||||
$row['gsid'],
|
||||
$row['updated'] !== DBA::NULL_DATETIME ? new \DateTime($row['updated'], new \DateTimeZone('UTC')) : null,
|
||||
$row['interacting_count'],
|
||||
$row['interacted_count'],
|
||||
$row['post_count'],
|
||||
$row['uri-id'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data Data returned by \Friendica\Network\Probe::uri()
|
||||
* @param int $uriId The URI ID of the Diaspora contact URL + GUID
|
||||
* @param \DateTime $created
|
||||
* @param int $interacting_count
|
||||
* @param int $interacted_count
|
||||
* @param int $post_count
|
||||
* @return \Friendica\Protocol\Diaspora\Entity\DiasporaContact
|
||||
*/
|
||||
public function createfromProbeData(array $data, int $uriId, \DateTime $created, int $interacting_count = 0, int $interacted_count = 0, int $post_count = 0): \Friendica\Protocol\Diaspora\Entity\DiasporaContact
|
||||
{
|
||||
$alias = $data['alias'] != $data['url'] ? $data['alias'] : null;
|
||||
|
||||
return new \Friendica\Protocol\Diaspora\Entity\DiasporaContact(
|
||||
new Uri($data['url']),
|
||||
$created,
|
||||
$data['guid'],
|
||||
$data['addr'],
|
||||
$alias ? new Uri($alias) : null,
|
||||
$data['nick'],
|
||||
$data['name'],
|
||||
$data['given-name'] ?? '',
|
||||
$data['family-name'] ?? '',
|
||||
$data['photo'] ? new Uri($data['photo']) : null,
|
||||
!empty($data['photo_medium']) ? new Uri($data['photo_medium']) : null,
|
||||
!empty($data['photo_small']) ? new Uri($data['photo_small']) : null,
|
||||
$data['batch'] ? new Uri($data['batch']) : null,
|
||||
$data['notify'] ? new Uri($data['notify']) : null,
|
||||
$data['poll'] ? new Uri($data['poll']) : null,
|
||||
$data['subscribe'] ? new Uri($data['subscribe']) : null,
|
||||
!$data['hide'],
|
||||
$data['pubkey'],
|
||||
$data['baseurl'] ? new Uri($data['baseurl']) : null,
|
||||
$data['gsid'],
|
||||
null,
|
||||
$interacting_count,
|
||||
$interacted_count,
|
||||
$post_count,
|
||||
$uriId,
|
||||
);
|
||||
}
|
||||
}
|
||||
283
src/Protocol/Diaspora/Repository/DiasporaContact.php
Normal file
283
src/Protocol/Diaspora/Repository/DiasporaContact.php
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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\Protocol\Diaspora\Repository;
|
||||
|
||||
use Friendica\BaseRepository;
|
||||
use Friendica\Core\System;
|
||||
use Friendica\Database\Database;
|
||||
use Friendica\Database\Definition\DbaDefinition;
|
||||
use Friendica\Model\APContact;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\ItemURI;
|
||||
use Friendica\Network\HTTPException;
|
||||
use Friendica\Protocol\Diaspora\Entity;
|
||||
use Friendica\Protocol\Diaspora\Factory;
|
||||
use Friendica\Protocol\WebFingerUri;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class DiasporaContact extends BaseRepository
|
||||
{
|
||||
const ALWAYS_UPDATE = true;
|
||||
const NEVER_UPDATE = false;
|
||||
const UPDATE_IF_MISSING_OR_OUTDATED = null;
|
||||
|
||||
protected static $table_name = 'diaspora-contact-view';
|
||||
|
||||
/** @var Factory\DiasporaContact */
|
||||
protected $factory;
|
||||
/** @var DbaDefinition */
|
||||
private $definition;
|
||||
|
||||
public function __construct(DbaDefinition $definition, Database $database, LoggerInterface $logger, Factory\DiasporaContact $factory)
|
||||
{
|
||||
parent::__construct($database, $logger, $factory);
|
||||
|
||||
$this->definition = $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $condition
|
||||
* @param array $params
|
||||
* @return Entity\DiasporaContact
|
||||
* @throws HTTPException\NotFoundException
|
||||
*/
|
||||
public function selectOne(array $condition, array $params = []): Entity\DiasporaContact
|
||||
{
|
||||
return parent::_selectOne($condition, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId
|
||||
* @return Entity\DiasporaContact
|
||||
* @throws HTTPException\NotFoundException
|
||||
*/
|
||||
public function selectOneByUriId(int $uriId): Entity\DiasporaContact
|
||||
{
|
||||
return $this->selectOne(['uri-id' => $uriId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UriInterface $uri
|
||||
* @return Entity\DiasporaContact
|
||||
* @throws HTTPException\NotFoundException
|
||||
*/
|
||||
public function selectOneByUri(UriInterface $uri): Entity\DiasporaContact
|
||||
{
|
||||
try {
|
||||
return $this->selectOne(['url' => (string) $uri]);
|
||||
} catch (HTTPException\NotFoundException $e) {
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->selectOne(['addr' => (string) $uri]);
|
||||
} catch (HTTPException\NotFoundException $e) {
|
||||
}
|
||||
|
||||
return $this->selectOne(['alias' => (string) $uri]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebFingerUri $uri
|
||||
* @return Entity\DiasporaContact
|
||||
* @throws HTTPException\NotFoundException
|
||||
*/
|
||||
public function selectOneByAddr(WebFingerUri $uri): Entity\DiasporaContact
|
||||
{
|
||||
return $this->selectOne(['addr' => $uri->getAddr()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $uriId
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function existsByUriId(int $uriId): bool
|
||||
{
|
||||
return $this->db->exists(self::$table_name, ['uri-id' => $uriId]);
|
||||
}
|
||||
|
||||
public function save(Entity\DiasporaContact $DiasporaContact): Entity\DiasporaContact
|
||||
{
|
||||
$uriId = $DiasporaContact->uriId ?? ItemURI::insert(['uri' => $DiasporaContact->url, 'guid' => $DiasporaContact->guid]);
|
||||
|
||||
$fields = [
|
||||
'uri-id' => $uriId,
|
||||
'addr' => $DiasporaContact->addr,
|
||||
'alias' => (string)$DiasporaContact->alias,
|
||||
'nick' => $DiasporaContact->nick,
|
||||
'name' => $DiasporaContact->name,
|
||||
'given-name' => $DiasporaContact->givenName,
|
||||
'family-name' => $DiasporaContact->familyName,
|
||||
'photo' => (string)$DiasporaContact->photo,
|
||||
'photo-medium' => (string)$DiasporaContact->photoMedium,
|
||||
'photo-small' => (string)$DiasporaContact->photoSmall,
|
||||
'batch' => (string)$DiasporaContact->batch,
|
||||
'notify' => (string)$DiasporaContact->notify,
|
||||
'poll' => (string)$DiasporaContact->poll,
|
||||
'subscribe' => (string)$DiasporaContact->subscribe,
|
||||
'searchable' => $DiasporaContact->searchable,
|
||||
'pubkey' => $DiasporaContact->pubKey,
|
||||
'gsid' => $DiasporaContact->gsid,
|
||||
'created' => $DiasporaContact->created->format(DateTimeFormat::MYSQL),
|
||||
'updated' => DateTimeFormat::utcNow(),
|
||||
'interacting_count' => $DiasporaContact->interacting_count,
|
||||
'interacted_count' => $DiasporaContact->interacted_count,
|
||||
'post_count' => $DiasporaContact->post_count,
|
||||
];
|
||||
|
||||
// Limit the length on incoming fields
|
||||
$fields = $this->definition->truncateFieldsForTable('diaspora-contact', $fields);
|
||||
|
||||
$this->db->insert('diaspora-contact', $fields, Database::INSERT_UPDATE);
|
||||
|
||||
return $this->selectOneByUriId($uriId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a Diaspora profile from a given WebFinger address and updates it depending on the mode
|
||||
*
|
||||
* @param WebFingerUri $uri Profile address
|
||||
* @param boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||
* @return Entity\DiasporaContact
|
||||
* @throws HTTPException\NotFoundException
|
||||
*/
|
||||
public function getByAddr(WebFingerUri $uri, ?bool $update = self::UPDATE_IF_MISSING_OR_OUTDATED): Entity\DiasporaContact
|
||||
{
|
||||
if ($update !== self::ALWAYS_UPDATE) {
|
||||
try {
|
||||
$dcontact = $this->selectOneByAddr($uri);
|
||||
if ($update === self::NEVER_UPDATE) {
|
||||
return $dcontact;
|
||||
}
|
||||
} catch (HTTPException\NotFoundException $e) {
|
||||
if ($update === self::NEVER_UPDATE) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// This is necessary for Contact::getByURL in case the base contact record doesn't need probing,
|
||||
// but we still need the result of a probe to create the missing diaspora-contact record.
|
||||
$update = self::ALWAYS_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
$contact = Contact::getByURL($uri, $update, ['uri-id']);
|
||||
if (empty($contact['uri-id'])) {
|
||||
throw new HTTPException\NotFoundException('Diaspora profile with URI ' . $uri . ' not found');
|
||||
}
|
||||
|
||||
return self::selectOneByUriId($contact['uri-id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a Diaspora profile from a given profile URL and updates it depending on the mode
|
||||
*
|
||||
* @param UriInterface $uri Profile URL
|
||||
* @param boolean $update true = always update, false = never update, null = update when not found or outdated
|
||||
* @return Entity\DiasporaContact
|
||||
* @throws HTTPException\NotFoundException
|
||||
*/
|
||||
public function getByUrl(UriInterface $uri, ?bool $update = self::UPDATE_IF_MISSING_OR_OUTDATED): Entity\DiasporaContact
|
||||
{
|
||||
if ($update !== self::ALWAYS_UPDATE) {
|
||||
try {
|
||||
$dcontact = $this->selectOneByUriId(ItemURI::getIdByURI($uri));
|
||||
if ($update === self::NEVER_UPDATE) {
|
||||
return $dcontact;
|
||||
}
|
||||
} catch (HTTPException\NotFoundException $e) {
|
||||
if ($update === self::NEVER_UPDATE) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// This is necessary for Contact::getByURL in case the base contact record doesn't need probing,
|
||||
// but we still need the result of a probe to create the missing diaspora-contact record.
|
||||
$update = self::ALWAYS_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
$contact = Contact::getByURL($uri, $update, ['uri-id']);
|
||||
if (empty($contact['uri-id'])) {
|
||||
throw new HTTPException\NotFoundException('Diaspora profile with URI ' . $uri . ' not found');
|
||||
}
|
||||
|
||||
return self::selectOneByUriId($contact['uri-id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update or create a diaspora-contact entry via a probe array
|
||||
*
|
||||
* @param array $data Probe array
|
||||
* @return Entity\DiasporaContact
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function updateFromProbeArray(array $data): Entity\DiasporaContact
|
||||
{
|
||||
$uriId = ItemURI::insert(['uri' => $data['url'], 'guid' => $data['guid']]);
|
||||
|
||||
$contact = Contact::getByUriId($uriId, ['id', 'created']);
|
||||
$apcontact = APContact::getByURL($data['url'], false);
|
||||
if (!empty($apcontact)) {
|
||||
$interacting_count = $apcontact['followers_count'];
|
||||
$interacted_count = $apcontact['following_count'];
|
||||
$post_count = $apcontact['statuses_count'];
|
||||
} elseif (!empty($contact['id'])) {
|
||||
$last_interaction = DateTimeFormat::utc('now - 180 days');
|
||||
|
||||
$interacting_count = $this->db->count('contact-relation', ["`relation-cid` = ? AND NOT `follows` AND `last-interaction` > ?", $contact['id'], $last_interaction]);
|
||||
$interacted_count = $this->db->count('contact-relation', ["`cid` = ? AND NOT `follows` AND `last-interaction` > ?", $contact['id'], $last_interaction]);
|
||||
$post_count = $this->db->count('post', ['author-id' => $contact['id'], 'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT]]);
|
||||
}
|
||||
|
||||
$DiasporaContact = $this->factory->createfromProbeData(
|
||||
$data,
|
||||
$uriId,
|
||||
new \DateTime($contact['created'] ?? 'now', new \DateTimeZone('UTC')),
|
||||
$interacting_count ?? 0,
|
||||
$interacted_count ?? 0,
|
||||
$post_count ?? 0
|
||||
);
|
||||
|
||||
$DiasporaContact = $this->save($DiasporaContact);
|
||||
|
||||
$this->logger->info('Updated diaspora-contact', ['url' => (string) $DiasporaContact->url, 'callstack' => System::callstack(20)]);
|
||||
|
||||
return $DiasporaContact;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a url (scheme://domain.tld/u/user) from a given contact guid
|
||||
*
|
||||
* @param mixed $guid Hexadecimal string guid
|
||||
*
|
||||
* @return string the contact url or null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getUrlByGuid(string $guid): ?string
|
||||
{
|
||||
$diasporaContact = $this->db->selectFirst(self::$table_name, ['url'], ['guid' => $guid]);
|
||||
|
||||
return $diasporaContact['url'] ?? null;
|
||||
}
|
||||
}
|
||||
113
src/Protocol/WebFingerUri.php
Normal file
113
src/Protocol/WebFingerUri.php
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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\Protocol;
|
||||
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
|
||||
class WebFingerUri
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $user;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $port;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $path;
|
||||
|
||||
private function __construct(string $user, string $host, int $port = null, string $path = null)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
$this->path = $path;
|
||||
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $addr
|
||||
* @return WebFingerUri
|
||||
*/
|
||||
public static function fromString(string $addr): WebFingerUri
|
||||
{
|
||||
$uri = new Uri('acct://' . preg_replace('/^acct:/', '', $addr));
|
||||
|
||||
return new self($uri->getUserInfo(), $uri->getHost(), $uri->getPort(), $uri->getPath());
|
||||
}
|
||||
|
||||
private function validate()
|
||||
{
|
||||
if (!$this->user) {
|
||||
throw new \InvalidArgumentException('WebFinger URI User part is required');
|
||||
}
|
||||
|
||||
if (!$this->host) {
|
||||
throw new \InvalidArgumentException('WebFinger URI Host part is required');
|
||||
}
|
||||
}
|
||||
|
||||
public function getUser(): string
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getHost(): string
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
public function getFullHost(): string
|
||||
{
|
||||
return $this->host
|
||||
. ($this->port ? ':' . $this->port : '') .
|
||||
($this->path ?: '');
|
||||
}
|
||||
|
||||
public function getLongForm(): string
|
||||
{
|
||||
return 'acct:' . $this->getShortForm();
|
||||
}
|
||||
|
||||
public function getShortForm(): string
|
||||
{
|
||||
return $this->user . '@' . $this->getFullHost();
|
||||
}
|
||||
|
||||
public function getAddr(): string
|
||||
{
|
||||
return $this->getShortForm();
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getShortForm();
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,6 @@ use Friendica\Core\Worker;
|
|||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
use Friendica\Model\FContact;
|
||||
use Friendica\Model\GServer;
|
||||
use Friendica\Model\Item;
|
||||
use Friendica\Model\Post;
|
||||
|
|
@ -94,7 +93,7 @@ class Delivery
|
|||
if ($item['verb'] == Activity::ANNOUNCE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($item['id'] == $parent_id) {
|
||||
$parent = $item;
|
||||
}
|
||||
|
|
@ -278,7 +277,7 @@ class Delivery
|
|||
private static function deliverDFRN(string $cmd, array $contact, array $owner, array $items, array $target_item, bool $public_message, bool $top_level, bool $followup, int $server_protocol = null)
|
||||
{
|
||||
// Transmit Diaspora reshares via Diaspora if the Friendica contact support Diaspora
|
||||
if (Diaspora::getReshareDetails($target_item ?? []) && !empty(FContact::getByURL($contact['addr'], false))) {
|
||||
if (Diaspora::getReshareDetails($target_item ?? []) && Diaspora::isSupportedByContactUrl($contact['addr'], false)) {
|
||||
Logger::info('Reshare will be transmitted via Diaspora', ['url' => $contact['url'], 'guid' => ($target_item['guid'] ?? '') ?: $target_item['id']]);
|
||||
self::deliverDiaspora($cmd, $contact, $owner, $items, $target_item, $public_message, $top_level, $followup);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ class ExpirePosts
|
|||
AND NOT EXISTS(SELECT `uri-id` FROM `user-contact` WHERE `uri-id` = `item-uri`.`id`)
|
||||
AND NOT EXISTS(SELECT `uri-id` FROM `contact` WHERE `uri-id` = `item-uri`.`id`)
|
||||
AND NOT EXISTS(SELECT `uri-id` FROM `apcontact` WHERE `uri-id` = `item-uri`.`id`)
|
||||
AND NOT EXISTS(SELECT `uri-id` FROM `fcontact` WHERE `uri-id` = `item-uri`.`id`)
|
||||
AND NOT EXISTS(SELECT `uri-id` FROM `diaspora-contact` WHERE `uri-id` = `item-uri`.`id`)
|
||||
AND NOT EXISTS(SELECT `uri-id` FROM `inbox-status` WHERE `uri-id` = `item-uri`.`id`)
|
||||
AND NOT EXISTS(SELECT `uri-id` FROM `post-delivery` WHERE `uri-id` = `item-uri`.`id`)
|
||||
AND NOT EXISTS(SELECT `uri-id` FROM `post-delivery` WHERE `inbox-id` = `item-uri`.`id`)
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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\Worker;
|
||||
|
||||
use Friendica\Core\Logger;
|
||||
use Friendica\Model\FContact;
|
||||
|
||||
class UpdateFContact
|
||||
{
|
||||
/**
|
||||
* Update fcontact data via probe
|
||||
*
|
||||
* @param string $handle Contact handle
|
||||
* @return void
|
||||
*/
|
||||
public static function execute(string $handle)
|
||||
{
|
||||
$success = FContact::getByURL($handle, true);
|
||||
|
||||
Logger::info('Updated from probe', ['handle' => $handle, 'success' => $success]);
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
use Friendica\Database\DBA;
|
||||
|
||||
if (!defined('DB_UPDATE_VERSION')) {
|
||||
define('DB_UPDATE_VERSION', 1497);
|
||||
define('DB_UPDATE_VERSION', 1500);
|
||||
}
|
||||
|
||||
return [
|
||||
|
|
@ -637,6 +637,39 @@ return [
|
|||
"wid" => ["wid"],
|
||||
]
|
||||
],
|
||||
"diaspora-contact" => [
|
||||
"comment" => "Diaspora compatible contacts - used in the Diaspora implementation",
|
||||
"fields" => [
|
||||
"uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the contact URL"],
|
||||
"addr" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"alias" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"nick" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"name" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"given-name" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"family-name" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"photo" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"photo-medium" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"photo-small" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"batch" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"notify" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"poll" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"subscribe" => ["type" => "varchar(255)", "comment" => ""],
|
||||
"searchable" => ["type" => "boolean", "comment" => ""],
|
||||
"pubkey" => ["type" => "text", "comment" => ""],
|
||||
"gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID"],
|
||||
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
|
||||
"updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
|
||||
"interacting_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of contacts this contact interactes with"],
|
||||
"interacted_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of contacts that interacted with this contact"],
|
||||
"post_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of posts and comments"],
|
||||
],
|
||||
"indexes" => [
|
||||
"PRIMARY" => ["uri-id"],
|
||||
"addr" => ["UNIQUE", "addr"],
|
||||
"alias" => ["alias"],
|
||||
"gsid" => ["gsid"],
|
||||
]
|
||||
],
|
||||
"diaspora-interaction" => [
|
||||
"comment" => "Signed Diaspora Interaction",
|
||||
"fields" => [
|
||||
|
|
@ -690,39 +723,6 @@ return [
|
|||
"uri-id" => ["uri-id"],
|
||||
]
|
||||
],
|
||||
"fcontact" => [
|
||||
"comment" => "Diaspora compatible contacts - used in the Diaspora implementation",
|
||||
"fields" => [
|
||||
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
|
||||
"guid" => ["type" => "varbinary(255)", "not null" => "1", "default" => "", "comment" => "unique id"],
|
||||
"url" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"uri-id" => ["type" => "int unsigned", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the fcontact url"],
|
||||
"name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"photo" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"request" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"addr" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"batch" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"notify" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"poll" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"confirm" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"priority" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
|
||||
"network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"alias" => ["type" => "varbinary(383)", "not null" => "1", "default" => "", "comment" => ""],
|
||||
"pubkey" => ["type" => "text", "comment" => ""],
|
||||
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
|
||||
"updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
|
||||
"interacting_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of contacts this contact interactes with"],
|
||||
"interacted_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of contacts that interacted with this contact"],
|
||||
"post_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of posts and comments"],
|
||||
],
|
||||
"indexes" => [
|
||||
"PRIMARY" => ["id"],
|
||||
"addr" => ["addr(32)"],
|
||||
"url" => ["UNIQUE", "url(190)"],
|
||||
"uri-id" => ["UNIQUE", "uri-id"],
|
||||
]
|
||||
],
|
||||
"fetch-entry" => [
|
||||
"comment" => "",
|
||||
"fields" => [
|
||||
|
|
@ -870,7 +870,7 @@ return [
|
|||
"fields" => [
|
||||
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
|
||||
"uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "User id"],
|
||||
"fid" => ["type" => "int unsigned", "relation" => ["fcontact" => "id"], "comment" => "deprecated"],
|
||||
"fid" => ["type" => "int unsigned", "comment" => "deprecated"],
|
||||
"contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["contact" => "id"], "comment" => ""],
|
||||
"suggest-cid" => ["type" => "int unsigned", "foreign" => ["contact" => "id"], "comment" => "Suggested contact"],
|
||||
"knowyou" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
|
||||
|
|
|
|||
|
|
@ -155,7 +155,6 @@
|
|||
"author-hidden" => ["author", "hidden"],
|
||||
"author-updated" => ["author", "updated"],
|
||||
"author-gsid" => ["author", "gsid"],
|
||||
"author-uri-id" => ["author", "uri-id"],
|
||||
"owner-id" => ["post-user", "owner-id"],
|
||||
"owner-uri-id" => ["owner", "uri-id"],
|
||||
"owner-link" => ["owner", "url"],
|
||||
|
|
@ -332,7 +331,6 @@
|
|||
"author-hidden" => ["author", "hidden"],
|
||||
"author-updated" => ["author", "updated"],
|
||||
"author-gsid" => ["author", "gsid"],
|
||||
"author-uri-id" => ["author", "uri-id"],
|
||||
"owner-id" => ["post-thread-user", "owner-id"],
|
||||
"owner-uri-id" => ["owner", "uri-id"],
|
||||
"owner-link" => ["owner", "url"],
|
||||
|
|
@ -495,7 +493,6 @@
|
|||
"author-hidden" => ["author", "hidden"],
|
||||
"author-updated" => ["author", "updated"],
|
||||
"author-gsid" => ["author", "gsid"],
|
||||
"author-uri-id" => ["author", "uri-id"],
|
||||
"owner-id" => ["post", "owner-id"],
|
||||
"owner-uri-id" => ["owner", "uri-id"],
|
||||
"owner-link" => ["owner", "url"],
|
||||
|
|
@ -634,7 +631,6 @@
|
|||
"author-hidden" => ["author", "hidden"],
|
||||
"author-updated" => ["author", "updated"],
|
||||
"author-gsid" => ["author", "gsid"],
|
||||
"author-uri-id" => ["author", "uri-id"],
|
||||
"owner-id" => ["post-thread", "owner-id"],
|
||||
"owner-uri-id" => ["owner", "uri-id"],
|
||||
"owner-link" => ["owner", "url"],
|
||||
|
|
@ -994,11 +990,11 @@
|
|||
"blocked" => ["contact", "blocked"],
|
||||
"dfrn-notify" => ["contact", "notify"],
|
||||
"dfrn-poll" => ["contact", "poll"],
|
||||
"diaspora-guid" => ["fcontact", "guid"],
|
||||
"diaspora-batch" => ["fcontact", "batch"],
|
||||
"diaspora-notify" => ["fcontact", "notify"],
|
||||
"diaspora-poll" => ["fcontact", "poll"],
|
||||
"diaspora-alias" => ["fcontact", "alias"],
|
||||
"diaspora-guid" => ["item-uri", "guid"],
|
||||
"diaspora-batch" => ["diaspora-contact", "batch"],
|
||||
"diaspora-notify" => ["diaspora-contact", "notify"],
|
||||
"diaspora-poll" => ["diaspora-contact", "poll"],
|
||||
"diaspora-alias" => ["diaspora-contact", "alias"],
|
||||
"ap-uuid" => ["apcontact", "uuid"],
|
||||
"ap-type" => ["apcontact", "type"],
|
||||
"ap-following" => ["apcontact", "following"],
|
||||
|
|
@ -1017,9 +1013,9 @@
|
|||
"query" => "FROM `contact`
|
||||
LEFT JOIN `item-uri` ON `item-uri`.`id` = `contact`.`uri-id`
|
||||
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `contact`.`uri-id`
|
||||
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = contact.`uri-id`
|
||||
LEFT JOIN `diaspora-contact` ON `diaspora-contact`.`uri-id` = contact.`uri-id`
|
||||
LEFT JOIN `gserver` ON `gserver`.`id` = contact.`gsid`
|
||||
WHERE `contact`.`uid` = 0"
|
||||
WHERE `contact`.`uid` = 0"
|
||||
],
|
||||
"account-user-view" => [
|
||||
"fields" => [
|
||||
|
|
@ -1093,14 +1089,14 @@
|
|||
"reason" => ["ucontact", "reason"],
|
||||
"dfrn-notify" => ["contact", "notify"],
|
||||
"dfrn-poll" => ["contact", "poll"],
|
||||
"diaspora-guid" => ["fcontact", "guid"],
|
||||
"diaspora-batch" => ["fcontact", "batch"],
|
||||
"diaspora-notify" => ["fcontact", "notify"],
|
||||
"diaspora-poll" => ["fcontact", "poll"],
|
||||
"diaspora-alias" => ["fcontact", "alias"],
|
||||
"diaspora-interacting_count" => ["fcontact", "interacting_count"],
|
||||
"diaspora-interacted_count" => ["fcontact", "interacted_count"],
|
||||
"diaspora-post_count" => ["fcontact", "post_count"],
|
||||
"diaspora-guid" => ["item-uri", "guid"],
|
||||
"diaspora-batch" => ["diaspora-contact", "batch"],
|
||||
"diaspora-notify" => ["diaspora-contact", "notify"],
|
||||
"diaspora-poll" => ["diaspora-contact", "poll"],
|
||||
"diaspora-alias" => ["diaspora-contact", "alias"],
|
||||
"diaspora-interacting_count" => ["diaspora-contact", "interacting_count"],
|
||||
"diaspora-interacted_count" => ["diaspora-contact", "interacted_count"],
|
||||
"diaspora-post_count" => ["diaspora-contact", "post_count"],
|
||||
"ap-uuid" => ["apcontact", "uuid"],
|
||||
"ap-type" => ["apcontact", "type"],
|
||||
"ap-following" => ["apcontact", "following"],
|
||||
|
|
@ -1120,7 +1116,7 @@
|
|||
INNER JOIN `contact` ON `contact`.`uri-id` = `ucontact`.`uri-id` AND `contact`.`uid` = 0
|
||||
LEFT JOIN `item-uri` ON `item-uri`.`id` = `ucontact`.`uri-id`
|
||||
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `ucontact`.`uri-id`
|
||||
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = `ucontact`.`uri-id` AND `fcontact`.`network` = 'dspr'
|
||||
LEFT JOIN `diaspora-contact` ON `diaspora-contact`.`uri-id` = `ucontact`.`uri-id`
|
||||
LEFT JOIN `gserver` ON `gserver`.`id` = contact.`gsid`"
|
||||
],
|
||||
"pending-view" => [
|
||||
|
|
@ -1190,5 +1186,36 @@
|
|||
"query" => "FROM `profile_field`
|
||||
INNER JOIN `permissionset` ON `permissionset`.`id` = `profile_field`.`psid`"
|
||||
],
|
||||
"diaspora-contact-view" => [
|
||||
"fields" => [
|
||||
"uri-id" => ["diaspora-contact", "uri-id"],
|
||||
"url" => ["item-uri", "uri"],
|
||||
"guid" => ["item-uri", "guid"],
|
||||
"addr" => ["diaspora-contact", "addr"],
|
||||
"alias" => ["diaspora-contact", "alias"],
|
||||
"nick" => ["diaspora-contact", "nick"],
|
||||
"name" => ["diaspora-contact", "name"],
|
||||
"given-name" => ["diaspora-contact", "given-name"],
|
||||
"family-name" => ["diaspora-contact", "family-name"],
|
||||
"photo" => ["diaspora-contact", "photo"],
|
||||
"photo-medium" => ["diaspora-contact", "photo-medium"],
|
||||
"photo-small" => ["diaspora-contact", "photo-small"],
|
||||
"batch" => ["diaspora-contact", "batch"],
|
||||
"notify" => ["diaspora-contact", "notify"],
|
||||
"poll" => ["diaspora-contact", "poll"],
|
||||
"subscribe" => ["diaspora-contact", "subscribe"],
|
||||
"searchable" => ["diaspora-contact", "searchable"],
|
||||
"pubkey" => ["diaspora-contact", "pubkey"],
|
||||
"baseurl" => ["gserver", "url"],
|
||||
"gsid" => ["diaspora-contact", "gsid"],
|
||||
"created" => ["diaspora-contact", "created"],
|
||||
"updated" => ["diaspora-contact", "updated"],
|
||||
"interacting_count" => ["diaspora-contact", "interacting_count"],
|
||||
"interacted_count" => ["diaspora-contact", "interacted_count"],
|
||||
"post_count" => ["diaspora-contact", "post_count"],
|
||||
],
|
||||
"query" => "FROM `diaspora-contact`
|
||||
INNER JOIN `item-uri` ON `item-uri`.`id` = `diaspora-contact`.`uri-id`
|
||||
LEFT JOIN `gserver` ON `gserver`.`id` = `diaspora-contact`.`gsid`"
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
|||
135
tests/src/Protocol/WebFingerUriTest.php
Normal file
135
tests/src/Protocol/WebFingerUriTest.php
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, 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/>.
|
||||
*
|
||||
* Main database structure configuration file.
|
||||
*
|
||||
* Here are described all the tables, fields and indexes Friendica needs to work.
|
||||
* The entry order is mostly alphabetic - with the exception of tables that are used in foreign keys.
|
||||
*
|
||||
* Syntax (braces indicate optionale values):
|
||||
* "<table name>" => [
|
||||
* "comment" => "Description of the table",
|
||||
* "fields" => [
|
||||
* "<field name>" => [
|
||||
* "type" => "<field type>{(<field size>)} <unsigned>",
|
||||
* "not null" => 0|1,
|
||||
* {"extra" => "auto_increment",}
|
||||
* {"default" => "<default value>",}
|
||||
* {"default" => NULL_DATE,} (for datetime fields)
|
||||
* {"primary" => "1",}
|
||||
* {"foreign|relation" => ["<foreign key table name>" => "<foreign key field name>"],}
|
||||
* "comment" => "Description of the fields"
|
||||
* ],
|
||||
* ...
|
||||
* ],
|
||||
* "indexes" => [
|
||||
* "PRIMARY" => ["<primary key field name>", ...],
|
||||
* "<index name>" => [{"UNIQUE",} "<field name>{(<key size>)}", ...]
|
||||
* ...
|
||||
* ],
|
||||
* ],
|
||||
*
|
||||
* Whenever possible prefer "foreign" before "relation" with the foreign keys.
|
||||
* "foreign" adds true foreign keys on the database level, while "relation" is just an indicator of a table relation without any consequences
|
||||
*
|
||||
* If you need to make any change, make sure to increment the DB_UPDATE_VERSION constant value below.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Test\src\Protocol;
|
||||
|
||||
use Friendica\Protocol\WebFingerUri;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class WebFingerUriTest extends TestCase
|
||||
{
|
||||
public function dataFromString(): array
|
||||
{
|
||||
return [
|
||||
'long' => [
|
||||
'expectedLong' => 'acct:selma@www.example.com:8080/friend',
|
||||
'expectedShort' => 'selma@www.example.com:8080/friend',
|
||||
'input' => 'acct:selma@www.example.com:8080/friend',
|
||||
],
|
||||
'short' => [
|
||||
'expectedLong' => 'acct:selma@www.example.com:8080/friend',
|
||||
'expectedShort' => 'selma@www.example.com:8080/friend',
|
||||
'input' => 'selma@www.example.com:8080/friend',
|
||||
],
|
||||
'minimal' => [
|
||||
'expectedLong' => 'acct:bob@example.com',
|
||||
'expectedShort' => 'bob@example.com',
|
||||
'input' => 'bob@example.com',
|
||||
],
|
||||
'acct:' => [
|
||||
'expectedLong' => 'acct:alice@example.acct:90',
|
||||
'expectedShort' => 'alice@example.acct:90',
|
||||
'input' => 'alice@example.acct:90',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataFromString
|
||||
* @param string $expectedLong
|
||||
* @param string $expectedShort
|
||||
* @param string $input
|
||||
* @return void
|
||||
*/
|
||||
public function testFromString(string $expectedLong, string $expectedShort, string $input)
|
||||
{
|
||||
$uri = WebFingerUri::fromString($input);
|
||||
|
||||
$this->assertEquals($expectedLong, $uri->getLongForm());
|
||||
$this->assertEquals($expectedShort, $uri->getShortForm());
|
||||
}
|
||||
|
||||
public function dataFromStringFailure()
|
||||
{
|
||||
return [
|
||||
'missing user' => [
|
||||
'input' => 'example.com',
|
||||
],
|
||||
'missing user @' => [
|
||||
'input' => '@example.com',
|
||||
],
|
||||
'missing host' => [
|
||||
'input' => 'alice',
|
||||
],
|
||||
'missing host @' => [
|
||||
'input' => 'alice@',
|
||||
],
|
||||
'missing everything' => [
|
||||
'input' => '',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataFromStringFailure
|
||||
* @param string $input
|
||||
* @return void
|
||||
*/
|
||||
public function testFromStringFailure(string $input)
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
WebFingerUri::fromString($input);
|
||||
}
|
||||
}
|
||||
|
|
@ -974,7 +974,7 @@ function update_1429()
|
|||
return Update::FAILED;
|
||||
}
|
||||
|
||||
if (!DBA::e("UPDATE `fcontact` SET `uri-id` = null WHERE NOT `uri-id` IS NULL")) {
|
||||
if (DBStructure::existsTable('fcontact') && !DBA::e("UPDATE `fcontact` SET `uri-id` = null WHERE NOT `uri-id` IS NULL")) {
|
||||
return Update::FAILED;
|
||||
}
|
||||
|
||||
|
|
@ -1013,6 +1013,10 @@ function update_1438()
|
|||
|
||||
function update_1439()
|
||||
{
|
||||
if (!DBStructure::existsTable('fcontact')) {
|
||||
return Update::SUCCESS;
|
||||
}
|
||||
|
||||
$intros = DBA::select('intro', ['id', 'fid'], ["NOT `fid` IS NULL AND `fid` != ?", 0]);
|
||||
while ($intro = DBA::fetch($intros)) {
|
||||
$fcontact = DBA::selectFirst('fcontact', ['url'], ['id' => $intro['fid']]);
|
||||
|
|
@ -1024,6 +1028,8 @@ function update_1439()
|
|||
}
|
||||
}
|
||||
DBA::close($intros);
|
||||
|
||||
return Update::SUCCESS;
|
||||
}
|
||||
|
||||
function update_1440()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue