diff --git a/database.sql b/database.sql index eff8f83faf..3e7e65e726 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ --- Friendica 2021.09-dev (Siberian Iris) --- DB_UPDATE_VERSION 1434 +-- Friendica 2021.12-dev (Siberian Iris) +-- DB_UPDATE_VERSION 1435 -- ------------------------------------------ @@ -114,29 +114,16 @@ CREATE TABLE IF NOT EXISTS `contact` ( `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `updated` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last contact update', - `self` boolean NOT NULL DEFAULT '0' COMMENT '1 if the contact is the user him/her self', - `remote_self` boolean NOT NULL DEFAULT '0' COMMENT '', - `rel` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'The kind of the relation between the user and the contact', - `duplex` boolean NOT NULL DEFAULT '0' COMMENT 'Deprecated', `network` char(4) NOT NULL DEFAULT '' COMMENT 'Network of the contact', - `protocol` char(4) NOT NULL DEFAULT '' COMMENT 'Protocol of the contact', `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name that this contact is known by', `nick` varchar(255) NOT NULL DEFAULT '' COMMENT 'Nick- and user name of the contact', `location` varchar(255) DEFAULT '' COMMENT '', `about` text COMMENT '', `keywords` text COMMENT 'public keywords (interests) of the contact', - `gender` varchar(32) NOT NULL DEFAULT '' COMMENT 'Deprecated', `xmpp` varchar(255) NOT NULL DEFAULT '' COMMENT 'XMPP address', `matrix` varchar(255) NOT NULL DEFAULT '' COMMENT 'Matrix address', - `attag` varchar(255) NOT NULL DEFAULT '' COMMENT '', `avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `photo` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo of the contact', - `thumb` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo (thumb size)', - `micro` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo (micro size)', `header` varchar(255) COMMENT 'Header picture', - `site-pubkey` text COMMENT 'Deprecated', - `issued-id` varchar(255) NOT NULL DEFAULT '' COMMENT 'Deprecated', - `dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT 'Deprecated', `url` varchar(255) NOT NULL DEFAULT '' COMMENT '', `nurl` varchar(255) NOT NULL DEFAULT '' COMMENT '', `uri-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the contact url', @@ -145,54 +132,67 @@ CREATE TABLE IF NOT EXISTS `contact` ( `pubkey` text COMMENT 'RSA public key 4096 bit', `prvkey` text COMMENT 'RSA private key 4096 bit', `batch` varchar(255) NOT NULL DEFAULT '' COMMENT '', - `request` varchar(255) COMMENT '', `notify` varchar(255) COMMENT '', `poll` varchar(255) COMMENT '', - `confirm` varchar(255) COMMENT '', `subscribe` varchar(255) COMMENT '', - `poco` varchar(255) COMMENT '', - `aes_allow` boolean NOT NULL DEFAULT '0' COMMENT 'Deprecated', - `ret-aes` boolean NOT NULL DEFAULT '0' COMMENT 'Deprecated', - `usehub` boolean NOT NULL DEFAULT '0' COMMENT '', - `subhub` boolean NOT NULL DEFAULT '0' COMMENT '', - `hub-verify` varchar(255) NOT NULL DEFAULT '' COMMENT '', `last-update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last try to update the contact info', `success_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last successful contact update', `failure_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last failed update', `failed` boolean COMMENT 'Connection failed', - `name-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `uri-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `avatar-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `term-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `last-item` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'date of the last post', `last-discovery` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'date of the last follower discovery', - `priority` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', `blocked` boolean NOT NULL DEFAULT '1' COMMENT 'Node-wide block status', `block_reason` text COMMENT 'Node-wide block reason', `readonly` boolean NOT NULL DEFAULT '0' COMMENT 'posts of the contact are readonly', - `writable` boolean NOT NULL DEFAULT '0' COMMENT '', - `forum` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a forum', - `prv` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a private group', - `contact-type` tinyint NOT NULL DEFAULT 0 COMMENT '', - `manually-approve` boolean COMMENT '', - `hidden` boolean NOT NULL DEFAULT '0' COMMENT '', + `contact-type` tinyint NOT NULL DEFAULT 0 COMMENT 'Person, organisation, news, community, relay', + `manually-approve` boolean COMMENT 'Contact requests have to be approved manually', `archive` boolean NOT NULL DEFAULT '0' COMMENT '', - `pending` boolean NOT NULL DEFAULT '1' COMMENT '', - `deleted` boolean NOT NULL DEFAULT '0' COMMENT 'Contact has been deleted', - `rating` tinyint NOT NULL DEFAULT 0 COMMENT '', `unsearchable` boolean NOT NULL DEFAULT '0' COMMENT 'Contact prefers to not be searchable', `sensitive` boolean NOT NULL DEFAULT '0' COMMENT 'Contact posts sensitive content', `baseurl` varchar(255) DEFAULT '' COMMENT 'baseurl of the contact', `gsid` int unsigned COMMENT 'Global Server ID', - `reason` text COMMENT '', - `closeness` tinyint unsigned NOT NULL DEFAULT 99 COMMENT '', - `info` mediumtext COMMENT '', - `profile-id` int unsigned COMMENT 'Deprecated', - `bdyear` varchar(4) NOT NULL DEFAULT '' COMMENT '', `bd` date NOT NULL DEFAULT '0001-01-01' COMMENT '', + `reason` text COMMENT '', + `self` boolean NOT NULL DEFAULT '0' COMMENT '1 if the contact is the user him/her self', + `remote_self` boolean NOT NULL DEFAULT '0' COMMENT '', + `rel` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'The kind of the relation between the user and the contact', + `protocol` char(4) NOT NULL DEFAULT '' COMMENT 'Protocol of the contact', + `subhub` boolean NOT NULL DEFAULT '0' COMMENT '', + `hub-verify` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `rating` tinyint NOT NULL DEFAULT 0 COMMENT 'Automatically detected feed poll frequency', + `priority` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Feed poll priority', + `attag` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `hidden` boolean NOT NULL DEFAULT '0' COMMENT '', + `pending` boolean NOT NULL DEFAULT '1' COMMENT 'Contact request is pending', + `deleted` boolean NOT NULL DEFAULT '0' COMMENT 'Contact has been deleted', + `info` mediumtext COMMENT '', `notify_new_posts` boolean NOT NULL DEFAULT '0' COMMENT '', `fetch_further_information` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', `ffi_keyword_denylist` text COMMENT '', + `photo` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo of the contact', + `thumb` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo (thumb size)', + `micro` varchar(255) DEFAULT '' COMMENT 'Link to the profile photo (micro size)', + `name-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `uri-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `avatar-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `request` varchar(255) COMMENT '', + `confirm` varchar(255) COMMENT '', + `poco` varchar(255) COMMENT '', + `writable` boolean NOT NULL DEFAULT '0' COMMENT '', + `forum` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a forum. Deprecated, use \'contact-type\' = \'community\' and \'manually-approve\' = false instead', + `prv` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a private group. Deprecated, use \'contact-type\' = \'community\' and \'manually-approve\' = true instead', + `bdyear` varchar(4) NOT NULL DEFAULT '' COMMENT '', + `site-pubkey` text COMMENT 'Deprecated', + `gender` varchar(32) NOT NULL DEFAULT '' COMMENT 'Deprecated', + `duplex` boolean NOT NULL DEFAULT '0' COMMENT 'Deprecated', + `issued-id` varchar(255) NOT NULL DEFAULT '' COMMENT 'Deprecated', + `dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT 'Deprecated', + `aes_allow` boolean NOT NULL DEFAULT '0' COMMENT 'Deprecated', + `ret-aes` boolean NOT NULL DEFAULT '0' COMMENT 'Deprecated', + `usehub` boolean NOT NULL DEFAULT '0' COMMENT 'Deprecated', + `closeness` tinyint unsigned NOT NULL DEFAULT 99 COMMENT 'Deprecated', + `profile-id` int unsigned COMMENT 'Deprecated', PRIMARY KEY(`id`), INDEX `uid_name` (`uid`,`name`(190)), INDEX `self_uid` (`self`,`uid`), @@ -1512,13 +1512,28 @@ CREATE TABLE IF NOT EXISTS `userd` ( CREATE TABLE IF NOT EXISTS `user-contact` ( `cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Contact id of the linked public contact', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id', + `uri-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the contact url', `blocked` boolean COMMENT 'Contact is completely blocked for this user', `ignored` boolean COMMENT 'Posts from this contact are ignored', `collapsed` boolean COMMENT 'Posts from this contact are collapsed', + `pending` boolean COMMENT '', + `rel` tinyint unsigned COMMENT 'The kind of the relation between the user and the contact', + `info` mediumtext COMMENT '', + `notify_new_posts` boolean COMMENT '', + `remote_self` boolean COMMENT '', + `fetch_further_information` tinyint unsigned COMMENT '', + `ffi_keyword_denylist` text COMMENT '', + `subhub` boolean COMMENT '', + `hub-verify` varchar(255) COMMENT '', + `protocol` char(4) COMMENT 'Protocol of the contact', + `rating` tinyint COMMENT 'Automatically detected feed poll frequency', + `priority` tinyint unsigned COMMENT 'Feed poll priority', PRIMARY KEY(`uid`,`cid`), INDEX `cid` (`cid`), + UNIQUE INDEX `uri-id_uid` (`uri-id`,`uid`), FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, - FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE + FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='User specific public contact data'; -- @@ -2225,7 +2240,6 @@ CREATE VIEW `owner-view` AS SELECT `contact`.`location` AS `location`, `contact`.`about` AS `about`, `contact`.`keywords` AS `keywords`, - `contact`.`gender` AS `gender`, `contact`.`xmpp` AS `xmpp`, `contact`.`matrix` AS `matrix`, `contact`.`attag` AS `attag`, @@ -2247,7 +2261,6 @@ CREATE VIEW `owner-view` AS SELECT `contact`.`poll` AS `poll`, `contact`.`confirm` AS `confirm`, `contact`.`poco` AS `poco`, - `contact`.`usehub` AS `usehub`, `contact`.`subhub` AS `subhub`, `contact`.`hub-verify` AS `hub-verify`, `contact`.`last-update` AS `last-update`, @@ -2276,9 +2289,7 @@ CREATE VIEW `owner-view` AS SELECT `contact`.`sensitive` AS `sensitive`, `contact`.`baseurl` AS `baseurl`, `contact`.`reason` AS `reason`, - `contact`.`closeness` AS `closeness`, `contact`.`info` AS `info`, - `contact`.`profile-id` AS `profile-id`, `contact`.`bdyear` AS `bdyear`, `contact`.`bd` AS `bd`, `contact`.`notify_new_posts` AS `notify_new_posts`, @@ -2452,7 +2463,7 @@ CREATE VIEW `account-user-view` AS SELECT `contact`.`network` AS `network`, `ucontact`.`protocol` AS `protocol`, `contact`.`location` AS `location`, - `contact`.`attag` AS `attag`, + `ucontact`.`attag` AS `attag`, `contact`.`pubkey` AS `pubkey`, `contact`.`prvkey` AS `prvkey`, `contact`.`subscribe` AS `subscribe`, @@ -2468,7 +2479,7 @@ CREATE VIEW `account-user-view` AS SELECT `contact`.`sensitive` AS `sensitive`, `contact`.`baseurl` AS `baseurl`, `contact`.`gsid` AS `gsid`, - `contact`.`info` AS `info`, + `ucontact`.`info` AS `info`, `contact`.`bdyear` AS `bdyear`, `contact`.`bd` AS `bd`, `contact`.`poco` AS `poco`, diff --git a/doc/database/db_contact.md b/doc/database/db_contact.md index 8eeac17ea7..ae12217589 100644 --- a/doc/database/db_contact.md +++ b/doc/database/db_contact.md @@ -6,91 +6,91 @@ contact table Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ------------------------- | ------------------------------------------------------------ | ------------------ | ---- | --- | ------------------- | -------------- | -| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | -| uid | Owner User id | mediumint unsigned | NO | | 0 | | -| created | | datetime | NO | | 0001-01-01 00:00:00 | | -| updated | Date of last contact update | datetime | YES | | 0001-01-01 00:00:00 | | -| self | 1 if the contact is the user him/her self | boolean | NO | | 0 | | -| remote_self | | boolean | NO | | 0 | | -| rel | The kind of the relation between the user and the contact | tinyint unsigned | NO | | 0 | | -| duplex | Deprecated | boolean | NO | | 0 | | -| network | Network of the contact | char(4) | NO | | | | -| protocol | Protocol of the contact | char(4) | NO | | | | -| name | Name that this contact is known by | varchar(255) | NO | | | | -| nick | Nick- and user name of the contact | varchar(255) | NO | | | | -| location | | varchar(255) | YES | | | | -| about | | text | YES | | NULL | | -| keywords | public keywords (interests) of the contact | text | YES | | NULL | | -| gender | Deprecated | varchar(32) | NO | | | | -| xmpp | XMPP address | varchar(255) | NO | | | | -| matrix | Matrix address | varchar(255) | NO | | | | -| attag | | varchar(255) | NO | | | | -| avatar | | varchar(255) | NO | | | | -| photo | Link to the profile photo of the contact | varchar(255) | YES | | | | -| thumb | Link to the profile photo (thumb size) | varchar(255) | YES | | | | -| micro | Link to the profile photo (micro size) | varchar(255) | YES | | | | -| header | Header picture | varchar(255) | YES | | NULL | | -| site-pubkey | Deprecated | text | YES | | NULL | | -| issued-id | Deprecated | varchar(255) | NO | | | | -| dfrn-id | Deprecated | varchar(255) | NO | | | | -| url | | varchar(255) | NO | | | | -| nurl | | varchar(255) | NO | | | | -| uri-id | Id of the item-uri table entry that contains the contact url | int unsigned | YES | | NULL | | -| addr | | varchar(255) | NO | | | | -| alias | | varchar(255) | NO | | | | -| pubkey | RSA public key 4096 bit | text | YES | | NULL | | -| prvkey | RSA private key 4096 bit | text | YES | | NULL | | -| batch | | varchar(255) | NO | | | | -| request | | varchar(255) | YES | | NULL | | -| notify | | varchar(255) | YES | | NULL | | -| poll | | varchar(255) | YES | | NULL | | -| confirm | | varchar(255) | YES | | NULL | | -| subscribe | | varchar(255) | YES | | NULL | | -| poco | | varchar(255) | YES | | NULL | | -| aes_allow | Deprecated | boolean | NO | | 0 | | -| ret-aes | Deprecated | boolean | NO | | 0 | | -| usehub | | boolean | NO | | 0 | | -| subhub | | boolean | NO | | 0 | | -| hub-verify | | varchar(255) | NO | | | | -| last-update | Date of the last try to update the contact info | datetime | NO | | 0001-01-01 00:00:00 | | -| success_update | Date of the last successful contact update | datetime | NO | | 0001-01-01 00:00:00 | | -| failure_update | Date of the last failed update | datetime | NO | | 0001-01-01 00:00:00 | | -| failed | Connection failed | boolean | YES | | NULL | | -| name-date | | datetime | NO | | 0001-01-01 00:00:00 | | -| uri-date | | datetime | NO | | 0001-01-01 00:00:00 | | -| avatar-date | | datetime | NO | | 0001-01-01 00:00:00 | | -| term-date | | datetime | NO | | 0001-01-01 00:00:00 | | -| last-item | date of the last post | datetime | NO | | 0001-01-01 00:00:00 | | -| last-discovery | date of the last follower discovery | datetime | NO | | 0001-01-01 00:00:00 | | -| priority | | tinyint unsigned | NO | | 0 | | -| blocked | Node-wide block status | boolean | NO | | 1 | | -| block_reason | Node-wide block reason | text | YES | | NULL | | -| readonly | posts of the contact are readonly | boolean | NO | | 0 | | -| writable | | boolean | NO | | 0 | | -| forum | contact is a forum | boolean | NO | | 0 | | -| prv | contact is a private group | boolean | NO | | 0 | | -| contact-type | | tinyint | NO | | 0 | | -| manually-approve | | boolean | YES | | NULL | | -| hidden | | boolean | NO | | 0 | | -| archive | | boolean | NO | | 0 | | -| pending | | boolean | NO | | 1 | | -| deleted | Contact has been deleted | boolean | NO | | 0 | | -| rating | | tinyint | NO | | 0 | | -| unsearchable | Contact prefers to not be searchable | boolean | NO | | 0 | | -| sensitive | Contact posts sensitive content | boolean | NO | | 0 | | -| baseurl | baseurl of the contact | varchar(255) | YES | | | | -| gsid | Global Server ID | int unsigned | YES | | NULL | | -| reason | | text | YES | | NULL | | -| closeness | | tinyint unsigned | NO | | 99 | | -| info | | mediumtext | YES | | NULL | | -| profile-id | Deprecated | int unsigned | YES | | NULL | | -| bdyear | | varchar(4) | NO | | | | -| bd | | date | NO | | 0001-01-01 | | -| notify_new_posts | | boolean | NO | | 0 | | -| fetch_further_information | | tinyint unsigned | NO | | 0 | | -| ffi_keyword_denylist | | text | YES | | NULL | | +| Field | Description | Type | Null | Key | Default | Extra | +| ------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------ | ---- | --- | ------------------- | -------------- | +| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | +| uid | Owner User id | mediumint unsigned | NO | | 0 | | +| created | | datetime | NO | | 0001-01-01 00:00:00 | | +| updated | Date of last contact update | datetime | YES | | 0001-01-01 00:00:00 | | +| network | Network of the contact | char(4) | NO | | | | +| name | Name that this contact is known by | varchar(255) | NO | | | | +| nick | Nick- and user name of the contact | varchar(255) | NO | | | | +| location | | varchar(255) | YES | | | | +| about | | text | YES | | NULL | | +| keywords | public keywords (interests) of the contact | text | YES | | NULL | | +| xmpp | XMPP address | varchar(255) | NO | | | | +| matrix | Matrix address | varchar(255) | NO | | | | +| avatar | | varchar(255) | NO | | | | +| header | Header picture | varchar(255) | YES | | NULL | | +| url | | varchar(255) | NO | | | | +| nurl | | varchar(255) | NO | | | | +| uri-id | Id of the item-uri table entry that contains the contact url | int unsigned | YES | | NULL | | +| addr | | varchar(255) | NO | | | | +| alias | | varchar(255) | NO | | | | +| pubkey | RSA public key 4096 bit | text | YES | | NULL | | +| prvkey | RSA private key 4096 bit | text | YES | | NULL | | +| batch | | varchar(255) | NO | | | | +| notify | | varchar(255) | YES | | NULL | | +| poll | | varchar(255) | YES | | NULL | | +| subscribe | | varchar(255) | YES | | NULL | | +| last-update | Date of the last try to update the contact info | datetime | NO | | 0001-01-01 00:00:00 | | +| success_update | Date of the last successful contact update | datetime | NO | | 0001-01-01 00:00:00 | | +| failure_update | Date of the last failed update | datetime | NO | | 0001-01-01 00:00:00 | | +| failed | Connection failed | boolean | YES | | NULL | | +| term-date | | datetime | NO | | 0001-01-01 00:00:00 | | +| last-item | date of the last post | datetime | NO | | 0001-01-01 00:00:00 | | +| last-discovery | date of the last follower discovery | datetime | NO | | 0001-01-01 00:00:00 | | +| blocked | Node-wide block status | boolean | NO | | 1 | | +| block_reason | Node-wide block reason | text | YES | | NULL | | +| readonly | posts of the contact are readonly | boolean | NO | | 0 | | +| contact-type | Person, organisation, news, community, relay | tinyint | NO | | 0 | | +| manually-approve | Contact requests have to be approved manually | boolean | YES | | NULL | | +| archive | | boolean | NO | | 0 | | +| unsearchable | Contact prefers to not be searchable | boolean | NO | | 0 | | +| sensitive | Contact posts sensitive content | boolean | NO | | 0 | | +| baseurl | baseurl of the contact | varchar(255) | YES | | | | +| gsid | Global Server ID | int unsigned | YES | | NULL | | +| bd | | date | NO | | 0001-01-01 | | +| reason | | text | YES | | NULL | | +| self | 1 if the contact is the user him/her self | boolean | NO | | 0 | | +| remote_self | | boolean | NO | | 0 | | +| rel | The kind of the relation between the user and the contact | tinyint unsigned | NO | | 0 | | +| protocol | Protocol of the contact | char(4) | NO | | | | +| subhub | | boolean | NO | | 0 | | +| hub-verify | | varchar(255) | NO | | | | +| rating | Automatically detected feed poll frequency | tinyint | NO | | 0 | | +| priority | Feed poll priority | tinyint unsigned | NO | | 0 | | +| attag | | varchar(255) | NO | | | | +| hidden | | boolean | NO | | 0 | | +| pending | Contact request is pending | boolean | NO | | 1 | | +| deleted | Contact has been deleted | boolean | NO | | 0 | | +| info | | mediumtext | YES | | NULL | | +| notify_new_posts | | boolean | NO | | 0 | | +| fetch_further_information | | tinyint unsigned | NO | | 0 | | +| ffi_keyword_denylist | | text | YES | | NULL | | +| photo | Link to the profile photo of the contact | varchar(255) | YES | | | | +| thumb | Link to the profile photo (thumb size) | varchar(255) | YES | | | | +| micro | Link to the profile photo (micro size) | varchar(255) | YES | | | | +| name-date | | datetime | NO | | 0001-01-01 00:00:00 | | +| uri-date | | datetime | NO | | 0001-01-01 00:00:00 | | +| avatar-date | | datetime | NO | | 0001-01-01 00:00:00 | | +| request | | varchar(255) | YES | | NULL | | +| confirm | | varchar(255) | YES | | NULL | | +| poco | | varchar(255) | YES | | NULL | | +| writable | | boolean | NO | | 0 | | +| forum | contact is a forum. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = false instead | boolean | NO | | 0 | | +| prv | contact is a private group. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = true instead | boolean | NO | | 0 | | +| bdyear | | varchar(4) | NO | | | | +| site-pubkey | Deprecated | text | YES | | NULL | | +| gender | Deprecated | varchar(32) | NO | | | | +| duplex | Deprecated | boolean | NO | | 0 | | +| issued-id | Deprecated | varchar(255) | NO | | | | +| dfrn-id | Deprecated | varchar(255) | NO | | | | +| aes_allow | Deprecated | boolean | NO | | 0 | | +| ret-aes | Deprecated | boolean | NO | | 0 | | +| usehub | Deprecated | boolean | NO | | 0 | | +| closeness | Deprecated | tinyint unsigned | NO | | 99 | | +| profile-id | Deprecated | int unsigned | YES | | NULL | | Indexes ------------ diff --git a/doc/database/db_user-contact.md b/doc/database/db_user-contact.md index 35d140cfff..5dab0c4bd6 100644 --- a/doc/database/db_user-contact.md +++ b/doc/database/db_user-contact.md @@ -6,21 +6,35 @@ User specific public contact data Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| --------- | ------------------------------------------- | ------------------ | ---- | --- | ------- | ----- | -| cid | Contact id of the linked public contact | int unsigned | NO | PRI | 0 | | -| uid | User id | mediumint unsigned | NO | PRI | 0 | | -| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | | -| ignored | Posts from this contact are ignored | boolean | YES | | NULL | | -| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | | +| Field | Description | Type | Null | Key | Default | Extra | +| ------------------------- | ------------------------------------------------------------ | ------------------ | ---- | --- | ------- | ----- | +| cid | Contact id of the linked public contact | int unsigned | NO | PRI | 0 | | +| uid | User id | mediumint unsigned | NO | PRI | 0 | | +| uri-id | Id of the item-uri table entry that contains the contact url | int unsigned | YES | | NULL | | +| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | | +| ignored | Posts from this contact are ignored | boolean | YES | | NULL | | +| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | | +| pending | | boolean | YES | | NULL | | +| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | | +| info | | mediumtext | YES | | NULL | | +| notify_new_posts | | boolean | YES | | NULL | | +| remote_self | | boolean | YES | | NULL | | +| fetch_further_information | | tinyint unsigned | YES | | NULL | | +| ffi_keyword_denylist | | text | YES | | NULL | | +| subhub | | boolean | YES | | NULL | | +| hub-verify | | varchar(255) | YES | | NULL | | +| protocol | Protocol of the contact | char(4) | YES | | NULL | | +| rating | Automatically detected feed poll frequency | tinyint | YES | | NULL | | +| priority | Feed poll priority | tinyint unsigned | YES | | NULL | | Indexes ------------ -| Name | Fields | -| ------- | -------- | -| PRIMARY | uid, cid | -| cid | cid | +| Name | Fields | +| ---------- | ------------------- | +| PRIMARY | uid, cid | +| cid | cid | +| uri-id_uid | UNIQUE, uri-id, uid | Foreign Keys ------------ @@ -29,5 +43,6 @@ Foreign Keys |-------|--------------|--------------| | cid | [contact](help/database/db_contact) | id | | uid | [user](help/database/db_user) | uid | +| uri-id | [item-uri](help/database/db_item-uri) | id | Return to [database documentation](help/database) diff --git a/include/api.php b/include/api.php index eb917cce5b..7656f5029c 100644 --- a/include/api.php +++ b/include/api.php @@ -3840,7 +3840,7 @@ function api_friendships_destroy($type) if ($dissolve) { Contact::remove($contact['id']); } else { - DBA::update('contact', ['rel' => Contact::FOLLOWER], ['id' => $contact['id']]); + Contact::update(['rel' => Contact::FOLLOWER], ['id' => $contact['id']]); } // "uid" and "self" are only needed for some internal stuff, so remove it from here @@ -4496,14 +4496,14 @@ function api_account_update_profile($type) if (!empty($_POST['name'])) { DBA::update('profile', ['name' => $_POST['name']], ['uid' => $local_user]); DBA::update('user', ['username' => $_POST['name']], ['uid' => $local_user]); - DBA::update('contact', ['name' => $_POST['name']], ['uid' => $local_user, 'self' => 1]); - DBA::update('contact', ['name' => $_POST['name']], ['id' => $api_user['id']]); + Contact::update(['name' => $_POST['name']], ['uid' => $local_user, 'self' => 1]); + Contact::update(['name' => $_POST['name']], ['id' => $api_user['id']]); } if (isset($_POST['description'])) { DBA::update('profile', ['about' => $_POST['description']], ['uid' => $local_user]); - DBA::update('contact', ['about' => $_POST['description']], ['uid' => $local_user, 'self' => 1]); - DBA::update('contact', ['about' => $_POST['description']], ['id' => $api_user['id']]); + Contact::update(['about' => $_POST['description']], ['uid' => $local_user, 'self' => 1]); + Contact::update(['about' => $_POST['description']], ['id' => $api_user['id']]); } Profile::publishUpdate($local_user); diff --git a/mod/pubsub.php b/mod/pubsub.php index 9b73ff85e2..1dfbd0b3dc 100644 --- a/mod/pubsub.php +++ b/mod/pubsub.php @@ -96,7 +96,7 @@ function pubsub_init(App $a) } if (!empty($hub_mode)) { - DBA::update('contact', ['subhub' => $subscribe], ['id' => $contact['id']]); + Contact::update(['subhub' => $subscribe], ['id' => $contact['id']]); Logger::log($hub_mode . ' success for contact ' . $contact_id . '.'); } hub_return(true, $hub_challenge); diff --git a/mod/unfollow.php b/mod/unfollow.php index 6ee45b17d8..2f92640886 100644 --- a/mod/unfollow.php +++ b/mod/unfollow.php @@ -149,7 +149,7 @@ function unfollow_process(string $url) Contact::remove($contact['id']); $return_path = $base_return_path; } else { - DBA::update('contact', ['rel' => Contact::FOLLOWER], ['id' => $contact['id']]); + Contact::update(['rel' => Contact::FOLLOWER], ['id' => $contact['id']]); $return_path = $base_return_path . '/' . $contact['id']; } diff --git a/src/Console/ArchiveContact.php b/src/Console/ArchiveContact.php index 24251bcce5..e3ccc48119 100644 --- a/src/Console/ArchiveContact.php +++ b/src/Console/ArchiveContact.php @@ -24,6 +24,7 @@ namespace Friendica\Console; use Friendica\App; use Friendica\Database\Database; use Friendica\DI; +use Friendica\Model\Contact; use Friendica\Util\Strings; use RuntimeException; @@ -104,7 +105,7 @@ HELP; if (!$this->dba->exists('contact', ['nurl' => $nurl, 'archive' => false])) { throw new RuntimeException(DI::l10n()->t('Could not find any unarchived contact entry for this URL (%s)', $nurl)); } - if ($this->dba->update('contact', ['archive' => true], ['nurl' => $nurl])) { + if (Contact::update(['archive' => true], ['nurl' => $nurl])) { $this->out($this->l10n->t('The contact entries have been archived')); } else { throw new RuntimeException('The contact archival failed.'); diff --git a/src/Console/GlobalCommunitySilence.php b/src/Console/GlobalCommunitySilence.php index d74892b340..2e65109e8b 100644 --- a/src/Console/GlobalCommunitySilence.php +++ b/src/Console/GlobalCommunitySilence.php @@ -98,7 +98,7 @@ HELP; $contact_id = Contact::getIdForURL($this->getArgument(0)); if ($contact_id) { - $this->dba->update('contact', ['hidden' => true], ['id' => $contact_id]); + Contact::update(['hidden' => true], ['id' => $contact_id]); $this->out('The account has been successfully silenced from the global community page.'); } else { throw new RuntimeException('Could not find any public contact entry for this URL (' . $this->getArgument(0) . ')'); diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 1375a8b3ef..18e498b97a 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -133,6 +133,7 @@ class Contact const FOLLOWER = 1; const SHARING = 2; const FRIEND = 3; + const SELF = 4; /** * @} */ @@ -175,7 +176,7 @@ class Contact * @param array $fields field array * @param int $duplicate_mode Do an update on a duplicate entry * - * @return boolean was the insert successful? + * @return int id of the created contact * @throws \Exception */ public static function insert(array $fields, int $duplicate_mode = Database::INSERT_DEFAULT) @@ -190,15 +191,40 @@ class Contact $fields['created'] = DateTimeFormat::utcNow(); } - $ret = DBA::insert('contact', $fields, $duplicate_mode); - $contact = DBA::selectFirst('contact', ['nurl', 'uid'], ['id' => DBA::lastInsertId()]); + DBA::insert('contact', $fields, $duplicate_mode); + $contact = DBA::selectFirst('contact', [], ['id' => DBA::lastInsertId()]); if (!DBA::isResult($contact)) { // Shouldn't happen - return $ret; + Logger::warning('Created contact could not be found', ['fields' => $fields]); + return 0; } + Contact\User::insertForContactArray($contact); + // Search for duplicated contacts and get rid of them - self::removeDuplicates($contact['nurl'], $contact['uid']); + if (!$contact['self']) { + self::removeDuplicates($contact['nurl'], $contact['uid']); + } + + return $contact['id']; + } + + /** + * Updates rows in the contact 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) + * + * @return boolean was the update successfull? + * @throws \Exception + */ + public static function update(array $fields, array $condition, $old_fields = []) + { + $ret = DBA::update('contact', $fields, $condition, $old_fields); + + // Apply changes to the "user-contact" table on dedicated fields + Contact\User::updateByContactUpdate($fields, $condition); return $ret; } @@ -650,7 +676,7 @@ class Contact // Only create the entry if it doesn't exist yet if (!DBA::exists('contact', ['uid' => $uid, 'self' => true])) { - $return = DBA::insert('contact', $contact); + $return = (bool)self::insert($contact); } // Create the public contact @@ -659,7 +685,7 @@ class Contact $contact['uid'] = 0; $contact['prvkey'] = null; - DBA::insert('contact', $contact, Database::INSERT_IGNORE); + self::insert($contact, Database::INSERT_IGNORE); } return $return; @@ -760,12 +786,12 @@ class Contact $fields['name-date'] = DateTimeFormat::utcNow(); } $fields['updated'] = DateTimeFormat::utcNow(); - DBA::update('contact', $fields, ['id' => $self['id']]); + self::update($fields, ['id' => $self['id']]); // Update the public contact as well $fields['prvkey'] = null; $fields['self'] = false; - DBA::update('contact', $fields, ['uid' => 0, 'nurl' => $self['nurl']]); + self::update($fields, ['uid' => 0, 'nurl' => $self['nurl']]); // Update the profile $fields = [ @@ -795,7 +821,7 @@ class Contact } // Archive the contact - DBA::update('contact', ['archive' => true, 'network' => Protocol::PHANTOM, 'deleted' => true], ['id' => $id]); + self::update(['archive' => true, 'network' => Protocol::PHANTOM, 'deleted' => true], ['id' => $id]); // Delete it in the background Worker::add(PRIORITY_MEDIUM, 'RemoveContact', $id); @@ -887,8 +913,8 @@ class Contact } if ($contact['term-date'] <= DBA::NULL_DATETIME) { - DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); - DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', Strings::normaliseLink($contact['url']), DBA::NULL_DATETIME]); + self::update(['term-date' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); + self::update(['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', Strings::normaliseLink($contact['url']), DBA::NULL_DATETIME]); } else { /* @todo * We really should send a notification to the owner after 2-3 weeks @@ -905,8 +931,8 @@ class Contact * delete, though if the owner tries to unarchive them we'll start * the whole process over again. */ - DBA::update('contact', ['archive' => true], ['id' => $contact['id']]); - DBA::update('contact', ['archive' => true], ['nurl' => Strings::normaliseLink($contact['url']), 'self' => false]); + self::update(['archive' => true], ['id' => $contact['id']]); + self::update(['archive' => true], ['nurl' => Strings::normaliseLink($contact['url']), 'self' => false]); } } } @@ -927,7 +953,7 @@ class Contact $fields = ['failed' => false, 'term-date' => DBA::NULL_DATETIME, 'archive' => false]; $condition = ['uid' => 0, 'network' => Protocol::FEDERATED, 'batch' => $contact['batch'], 'contact-type' => self::TYPE_RELAY]; if (!DBA::exists('contact', array_merge($condition, $fields))) { - DBA::update('contact', $fields, $condition); + self::update($fields, $condition); } } @@ -951,8 +977,8 @@ class Contact // It's a miracle. Our dead contact has inexplicably come back to life. $fields = ['failed' => false, 'term-date' => DBA::NULL_DATETIME, 'archive' => false]; - DBA::update('contact', $fields, ['id' => $contact['id']]); - DBA::update('contact', $fields, ['nurl' => Strings::normaliseLink($contact['url']), 'self' => false]); + self::update($fields, ['id' => $contact['id']]); + self::update($fields, ['nurl' => Strings::normaliseLink($contact['url']), 'self' => false]); } /** @@ -1218,8 +1244,7 @@ class Contact $contact_id = $contact['id']; Logger::notice('Contact had been created (shortly) before', ['id' => $contact_id, 'url' => $url, 'uid' => $uid]); } else { - DBA::insert('contact', $fields); - $contact_id = DBA::lastInsertId(); + $contact_id = self::insert($fields); if ($contact_id) { Logger::info('Contact inserted', ['id' => $contact_id, 'url' => $url, 'uid' => $uid]); } @@ -1501,7 +1526,7 @@ class Contact */ public static function block($cid, $reason = null) { - $return = DBA::update('contact', ['blocked' => true, 'block_reason' => $reason], ['id' => $cid]); + $return = self::update(['blocked' => true, 'block_reason' => $reason], ['id' => $cid]); return $return; } @@ -1515,7 +1540,7 @@ class Contact */ public static function unblock($cid) { - $return = DBA::update('contact', ['blocked' => false, 'block_reason' => null], ['id' => $cid]); + $return = self::update(['blocked' => false, 'block_reason' => null], ['id' => $cid]); return $return; } @@ -1814,7 +1839,7 @@ class Contact // Only update the cached photo links of public contacts when they already are cached if (($uid == 0) && !$force && empty($contact['thumb']) && empty($contact['micro']) && !$create_cache) { if ($contact['avatar'] != $avatar) { - DBA::update('contact', ['avatar' => $avatar], ['id' => $cid]); + self::update(['avatar' => $avatar], ['id' => $cid]); Logger::info('Only update the avatar', ['id' => $cid, 'avatar' => $avatar, 'contact' => $contact]); } return; @@ -1911,7 +1936,7 @@ class Contact $cids[] = $cid; $uids[] = $uid; Logger::info('Updating cached contact avatars', ['cid' => $cids, 'uid' => $uids, 'fields' => $fields]); - DBA::update('contact', $fields, ['id' => $cids]); + self::update($fields, ['id' => $cids]); } public static function deleteContactByUrl(string $url) @@ -1938,7 +1963,7 @@ class Contact */ private static function updateContact(int $id, int $uid, string $old_url, string $new_url, array $fields) { - if (!DBA::update('contact', $fields, ['id' => $id])) { + if (!self::update($fields, ['id' => $id])) { Logger::info('Couldn\'t update contact.', ['id' => $id, 'fields' => $fields]); return; } @@ -1971,7 +1996,7 @@ class Contact $condition = ['self' => false, 'nurl' => Strings::normaliseLink($old_url)]; $condition['network'] = [Protocol::DFRN, Protocol::DIASPORA, Protocol::ACTIVITYPUB]; - DBA::update('contact', $fields, $condition); + self::update($fields, $condition); // We mustn't set the update fields for OStatus contacts since they are updated in OnePoll $condition['network'] = Protocol::OSTATUS; @@ -1987,7 +2012,7 @@ class Contact return; } - DBA::update('contact', $fields, $condition); + self::update($fields, $condition); } /** @@ -2000,7 +2025,7 @@ class Contact */ public static function removeDuplicates(string $nurl, int $uid) { - $condition = ['nurl' => $nurl, 'uid' => $uid, 'deleted' => false, 'network' => Protocol::FEDERATED]; + $condition = ['nurl' => $nurl, 'uid' => $uid, 'self' => false, 'deleted' => false, 'network' => Protocol::FEDERATED]; $count = DBA::count('contact', $condition); if ($count <= 1) { return false; @@ -2261,7 +2286,7 @@ class Contact } } if (!empty($fields)) { - DBA::update('contact', $fields, ['id' => $id, 'self' => false]); + self::update($fields, ['id' => $id, 'self' => false]); Logger::info('Updating local contact', ['id' => $id]); } } @@ -2439,7 +2464,7 @@ class Contact $new_relation = (($contact['rel'] == self::FOLLOWER) ? self::FRIEND : self::SHARING); $fields = ['rel' => $new_relation, 'subhub' => $subhub, 'readonly' => false]; - DBA::update('contact', $fields, ['id' => $contact['id']]); + self::update($fields, ['id' => $contact['id']]); } else { $new_relation = (in_array($protocol, [Protocol::MAIL]) ? self::FRIEND : self::SHARING); @@ -2572,7 +2597,7 @@ class Contact $fields = ['url' => $contact['url'], 'request' => $contact['request'], 'notify' => $contact['notify'], 'poll' => $contact['poll'], 'confirm' => $contact['confirm'], 'poco' => $contact['poco']]; - DBA::update('contact', $fields, ['id' => $contact['id']]); + self::update($fields, ['id' => $contact['id']]); } return $contact; @@ -2675,7 +2700,7 @@ class Contact if (($contact['rel'] == self::SHARING) || ($sharing && $contact['rel'] == self::FOLLOWER)) { - DBA::update('contact', ['rel' => self::FRIEND, 'writable' => true, 'pending' => false], + self::update(['rel' => self::FRIEND, 'writable' => true, 'pending' => false], ['id' => $contact['id'], 'uid' => $importer['uid']]); } @@ -2693,7 +2718,7 @@ class Contact } // create contact record - DBA::insert('contact', [ + $contact_id = self::insert([ 'uid' => $importer['uid'], 'created' => DateTimeFormat::utcNow(), 'url' => $url, @@ -2708,8 +2733,6 @@ class Contact 'writable' => 1, ]); - $contact_id = DBA::lastInsertId(); - // Ensure to always have the correct network type, independent from the connection request method self::updateFromProbe($contact_id); @@ -2757,7 +2780,7 @@ class Contact $fields['rel'] = self::FRIEND; } - DBA::update('contact', $fields, $condition); + self::update($fields, $condition); return true; } @@ -2780,7 +2803,7 @@ class Contact public static function removeSharer($importer, $contact) { if (($contact['rel'] == self::FRIEND) || ($contact['rel'] == self::FOLLOWER)) { - DBA::update('contact', ['rel' => self::FOLLOWER], ['id' => $contact['id']]); + self::update(['rel' => self::FOLLOWER], ['id' => $contact['id']]); } else { self::remove($contact['id']); } diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index b9d38790db..565d076a7f 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -114,7 +114,7 @@ class Relation } if (empty($followers) && empty($followings)) { - DBA::update('contact', ['last-discovery' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); + Contact::update(['last-discovery' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); Logger::info('The contact does not offer discoverable data', ['id' => $contact['id'], 'url' => $url, 'network' => $contact['network']]); return; } @@ -162,7 +162,7 @@ class Relation DBA::delete('contact-relation', ['cid' => $target, 'follows' => false, 'last-interaction' => DBA::NULL_DATETIME]); } - DBA::update('contact', ['last-discovery' => DateTimeFormat::utcNow()], ['id' => $target]); + Contact::update(['last-discovery' => DateTimeFormat::utcNow()], ['id' => $target]); Logger::info('Contacts discovery finished', ['id' => $target, 'url' => $url, 'follower' => $follower_counter, 'following' => $following_counter]); return; } diff --git a/src/Model/Contact/User.php b/src/Model/Contact/User.php index 26fd96303f..eb0b5af096 100644 --- a/src/Model/Contact/User.php +++ b/src/Model/Contact/User.php @@ -21,14 +21,115 @@ namespace Friendica\Model\Contact; +use Exception; +use Friendica\Core\Logger; +use Friendica\Core\System; +use Friendica\Database\Database; use Friendica\Database\DBA; +use Friendica\Database\DBStructure; use Friendica\Model\Contact; +use Friendica\Model\ItemURI; +use PDOException; /** * This class provides information about user related contacts based on the "user-contact" table. */ class User { + /** + * Insert a user-contact for a given contact array + * + * @param array $contact + * @return void + */ + public static function insertForContactArray(array $contact) + { + if (empty($contact['uid'])) { + // We don't create entries for the public user - by now + return false; + } + + if (empty($contact['uri-id']) && empty($contact['url'])) { + Logger::info('Missing contact details', ['contact' => $contact, 'callstack' => System::callstack(20)]); + return false; + } + + if (empty($contact['uri-id'])) { + $contact['uri-id'] = ItemURI::getIdByURI($contact['url']); + } + + $pcontact = Contact::selectFirst(['id'], ['uri-id' => $contact['uri-id'], 'uid' => 0]); + if (!empty($contact['uri-id']) && DBA::isResult($pcontact)) { + $pcid = $pcontact['id']; + } elseif (empty($contact['url']) || !($pcid = Contact::getIdForURL($contact['url'], 0, false))) { + Logger::info('Public contact for user not found', ['uri-id' => $contact['uri-id'], 'uid' => $contact['uid']]); + return false; + } + + $fields = self::preparedFields($contact); + $fields['cid'] = $pcid; + $fields['uid'] = $contact['uid']; + $fields['uri-id'] = $contact['uri-id']; + + $ret = DBA::insert('user-contact', $fields, Database::INSERT_UPDATE); + + Logger::info('Inserted user contact', ['uid' => $contact['uid'], 'cid' => $pcid, 'uri-id' => $contact['uri-id'], 'ret' => $ret]); + + return $ret; + } + + /** + * Apply changes from contact update data to user-contact table + * + * @param array $fields + * @param array $condition + * @return void + * @throws PDOException + * @throws Exception + */ + public static function updateByContactUpdate(array $fields, array $condition) + { + DBA::transaction(); + + $update_fields = self::preparedFields($fields); + if (!empty($update_fields)) { + $contacts = DBA::select('contact', ['uri-id', 'uid'], $condition); + while ($row = DBA::fetch($contacts)) { + if (empty($row['uri-id']) || empty($contact['uid'])) { + continue; + } + $ret = DBA::update('user-contact', $update_fields, ['uri-id' => $row['uri-id'], 'uid' => $row['uid']]); + Logger::info('Updated user contact', ['uid' => $row['uid'], 'uri-id' => $row['uri-id'], 'ret' => $ret]); + } + + DBA::close($contacts); + } + DBA::commit(); + } + + /** + * Prepare field data for update/insert + * + * @param array $fields + * @return array prepared fields + */ + private static function preparedFields(array $fields): array + { + unset($fields['uid']); + unset($fields['cid']); + unset($fields['uri-id']); + + if (isset($fields['readonly'])) { + $fields['ignored'] = $fields['readonly']; + } + + if (!empty($fields['self'])) { + $fields['rel'] = Contact::SELF; + } + + return DBStructure::getFieldsForTable('user-contact', $fields); + } + /** * Block contact id for user id * diff --git a/src/Model/Introduction.php b/src/Model/Introduction.php index 849cad78b8..aa71891214 100644 --- a/src/Model/Introduction.php +++ b/src/Model/Introduction.php @@ -110,7 +110,7 @@ class Introduction extends BaseModel 'hidden' => $hidden ?? $contact['hidden'], 'rel' => $newRelation, ]; - $this->dba->update('contact', $fields, ['id' => $contact['id']]); + Contact::update($fields, ['id' => $contact['id']]); array_merge($contact, $fields); @@ -159,7 +159,7 @@ class Introduction extends BaseModel if ($this->dba->exists('contact', $condition)) { Contact::remove($this->{'contact-id'}); } else { - $this->dba->update('contact', ['pending' => false], ['id' => $this->{'contact-id'}]); + Contact::update(['pending' => false], ['id' => $this->{'contact-id'}]); } } diff --git a/src/Model/Item.php b/src/Model/Item.php index 8327252abc..fbbd2eb673 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1766,15 +1766,15 @@ class Item } else { $condition = ['id' => $arr['contact-id'], 'self' => false]; } - DBA::update('contact', ['failed' => false, 'success_update' => $arr['received'], 'last-item' => $arr['received']], $condition); + Contact::update(['failed' => false, 'success_update' => $arr['received'], 'last-item' => $arr['received']], $condition); } // Now do the same for the system wide contacts with uid=0 if ($arr['private'] != self::PRIVATE) { - DBA::update('contact', ['failed' => false, 'success_update' => $arr['received'], 'last-item' => $arr['received']], + Contact::update(['failed' => false, 'success_update' => $arr['received'], 'last-item' => $arr['received']], ['id' => $arr['owner-id']]); if ($arr['owner-id'] != $arr['author-id']) { - DBA::update('contact', ['failed' => false, 'success_update' => $arr['received'], 'last-item' => $arr['received']], + Contact::update(['failed' => false, 'success_update' => $arr['received'], 'last-item' => $arr['received']], ['id' => $arr['author-id']]); } } diff --git a/src/Model/User.php b/src/Model/User.php index ccdca6288a..f3f837eb2e 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -234,7 +234,7 @@ class User $system['closeness'] = 0; $system['baseurl'] = DI::baseUrl(); $system['gsid'] = GServer::getID($system['baseurl']); - DBA::insert('contact', $system); + Contact::insert($system); } /** diff --git a/src/Module/Api/Mastodon/Accounts/Note.php b/src/Module/Api/Mastodon/Accounts/Note.php index bb5778a0f7..e631922024 100644 --- a/src/Module/Api/Mastodon/Accounts/Note.php +++ b/src/Module/Api/Mastodon/Accounts/Note.php @@ -50,7 +50,7 @@ class Note extends BaseApi DI::mstdnError()->RecordNotFound(); } - DBA::update('contact', ['info' => $request['comment']], ['id' => $cdata['user']]); + Contact::update(['info' => $request['comment']], ['id' => $cdata['user']]); System::jsonExit(DI::mstdnRelationship()->createFromContactId($parameters['id'], $uid)->toArray()); } diff --git a/src/Module/Contact.php b/src/Module/Contact.php index ca895c5f4b..bf0e3bfaf2 100644 --- a/src/Module/Contact.php +++ b/src/Module/Contact.php @@ -143,7 +143,7 @@ class Contact extends BaseModule $info = Strings::escapeHtml(trim($_POST['info'] ?? '')); - $r = DBA::update('contact', [ + $r = Model\Contact::update([ 'priority' => $priority, 'info' => $info, 'hidden' => $hidden, @@ -179,7 +179,7 @@ class Contact extends BaseModule $result = Model\Contact::createFromProbeForUser($contact['uid'], $contact['url'], $contact['network']); if ($result['success']) { - DBA::update('contact', ['subhub' => 1], ['id' => $contact_id]); + Model\Contact::update(['subhub' => 1], ['id' => $contact_id]); } // pull feed and consume it, which should subscribe to the hub. diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 1fe527f407..41af3db3fa 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -912,7 +912,7 @@ class Processor $cid = Contact::getIdForURL($activity['actor'], $uid); if (!empty($cid)) { self::switchContact($cid); - DBA::update('contact', ['hub-verify' => $activity['id'], 'protocol' => Protocol::ACTIVITYPUB], ['id' => $cid]); + Contact::update(['hub-verify' => $activity['id'], 'protocol' => Protocol::ACTIVITYPUB], ['id' => $cid]); } $item = ['author-id' => Contact::getIdForURL($activity['actor']), @@ -932,7 +932,7 @@ class Processor } if (empty($contact)) { - DBA::update('contact', ['hub-verify' => $activity['id'], 'protocol' => Protocol::ACTIVITYPUB], ['id' => $cid]); + Contact::update(['hub-verify' => $activity['id'], 'protocol' => Protocol::ACTIVITYPUB], ['id' => $cid]); } Logger::notice('Follow user ' . $uid . ' from contact ' . $cid . ' with id ' . $activity['id']); @@ -1011,7 +1011,7 @@ class Processor } $condition = ['id' => $cid]; - DBA::update('contact', $fields, $condition); + Contact::update($fields, $condition); Logger::info('Accept contact request', ['contact' => $cid, 'user' => $uid]); } diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index e7bb20893b..d9b6eddb6a 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -115,7 +115,7 @@ class Transmitter $activity_id = ActivityPub\Transmitter::activityIDFromContact($contact['id']); $success = ActivityPub\Transmitter::sendActivity('Follow', $url, 0, $activity_id); if ($success) { - DBA::update('contact', ['rel' => Contact::FRIEND], ['id' => $contact['id']]); + Contact::update(['rel' => Contact::FRIEND], ['id' => $contact['id']]); } return $success; @@ -137,7 +137,7 @@ class Transmitter $success = self::sendContactUndo($url, $contact['id'], 0); if ($success || $force) { - DBA::update('contact', ['rel' => Contact::NOTHING], ['id' => $contact['id']]); + Contact::update(['rel' => Contact::NOTHING], ['id' => $contact['id']]); } return $success; diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 4977b89aff..2c2309ba4d 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1215,12 +1215,12 @@ class DFRN 'xmpp' => $contact['xmpp'], 'name-date' => DateTimeFormat::utc($contact['name-date']), 'unsearchable' => $contact['hidden'], 'uri-date' => DateTimeFormat::utc($contact['uri-date'])]; - DBA::update('contact', $fields, ['id' => $contact['id'], 'network' => $contact['network']], $contact_old); + Contact::update($fields, ['id' => $contact['id'], 'network' => $contact['network']], $contact_old); // Update the public contact. Don't set the "hidden" value, this is used differently for public contacts unset($fields['hidden']); $condition = ['uid' => 0, 'nurl' => Strings::normaliseLink($contact_old['url'])]; - DBA::update('contact', $fields, $condition, true); + Contact::update($fields, $condition, true); Contact::updateAvatar($contact['id'], $author['avatar']); @@ -1400,7 +1400,7 @@ class DFRN 'poll' => $relocate["poll"], 'site-pubkey' => $relocate["sitepubkey"]]; $condition = ["(`id` = ?) OR (`nurl` = ?)", $importer["id"], Strings::normaliseLink($old["url"])]; - DBA::update('contact', $fields, $condition); + Contact::update($fields, $condition); Contact::updateAvatar($importer["id"], $relocate["avatar"], true); @@ -2200,36 +2200,36 @@ class DFRN $accounttype = intval(XML::getFirstNodeValue($xpath, "/atom:feed/dfrn:account_type/text()")); if ($accounttype != $importer["contact-type"]) { - DBA::update('contact', ['contact-type' => $accounttype], ['id' => $importer['id']]); + Contact::update(['contact-type' => $accounttype], ['id' => $importer['id']]); // Updating the public contact as well - DBA::update('contact', ['contact-type' => $accounttype], ['uid' => 0, 'nurl' => $importer['nurl']]); + Contact::update(['contact-type' => $accounttype], ['uid' => 0, 'nurl' => $importer['nurl']]); } // A forum contact can either have set "forum" or "prv" - but not both if ($accounttype == User::ACCOUNT_TYPE_COMMUNITY) { // It's a forum, so either set the public or private forum flag $condition = ['(`forum` != ? OR `prv` != ?) AND `id` = ?', $forum, !$forum, $importer['id']]; - DBA::update('contact', ['forum' => $forum, 'prv' => !$forum], $condition); + Contact::update(['forum' => $forum, 'prv' => !$forum], $condition); // Updating the public contact as well $condition = ['(`forum` != ? OR `prv` != ?) AND `uid` = 0 AND `nurl` = ?', $forum, !$forum, $importer['nurl']]; - DBA::update('contact', ['forum' => $forum, 'prv' => !$forum], $condition); + Contact::update(['forum' => $forum, 'prv' => !$forum], $condition); } else { // It's not a forum, so remove the flags $condition = ['(`forum` OR `prv`) AND `id` = ?', $importer['id']]; - DBA::update('contact', ['forum' => false, 'prv' => false], $condition); + Contact::update(['forum' => false, 'prv' => false], $condition); // Updating the public contact as well $condition = ['(`forum` OR `prv`) AND `uid` = 0 AND `nurl` = ?', $importer['nurl']]; - DBA::update('contact', ['forum' => false, 'prv' => false], $condition); + Contact::update(['forum' => false, 'prv' => false], $condition); } } elseif ($forum != $importer["forum"]) { // Deprecated since 3.5.1 $condition = ['`forum` != ? AND `id` = ?', $forum, $importer["id"]]; - DBA::update('contact', ['forum' => $forum], $condition); + Contact::update(['forum' => $forum], $condition); // Updating the public contact as well $condition = ['`forum` != ? AND `uid` = 0 AND `nurl` = ?', $forum, $importer['nurl']]; - DBA::update('contact', ['forum' => $forum], $condition); + Contact::update(['forum' => $forum], $condition); } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 8ab89d950f..b08fa23c2b 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -1367,7 +1367,7 @@ class Diaspora 'notify' => $data['notify'], 'poll' => $data['poll'], 'network' => $data['network']]; - DBA::update('contact', $fields, ['addr' => $old_handle]); + Contact::update($fields, ['addr' => $old_handle]); Logger::log('Contacts are updated.'); @@ -2129,7 +2129,7 @@ class Diaspora $fields['bd'] = $birthday; } - DBA::update('contact', $fields, ['id' => $contact['id']]); + Contact::update($fields, ['id' => $contact['id']]); Logger::log("Profile of contact ".$contact["id"]." stored for user ".$importer["uid"], Logger::DEBUG); diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index a32b460d5a..680e8803bd 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -732,7 +732,7 @@ class Feed if ($contact['rating'] != $priority) { Logger::notice('Adjusting priority', ['old' => $contact['rating'], 'new' => $priority, 'id' => $contact['id'], 'uid' => $contact['uid'], 'url' => $contact['url']]); - DBA::update('contact', ['rating' => $priority], ['id' => $contact['id']]); + Contact::update(['rating' => $priority], ['id' => $contact['id']]); } } diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 5b1f758b2e..4155fb084b 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -209,7 +209,7 @@ class OStatus $contact['name-date'] = DateTimeFormat::utcNow(); - DBA::update('contact', $contact, ['id' => $contact["id"]], $current); + Contact::update($contact, ['id' => $contact["id"]], $current); if (!empty($author["author-avatar"]) && ($author["author-avatar"] != $current['avatar'])) { Logger::log("Update profile picture for contact ".$contact["id"], Logger::DEBUG); @@ -230,7 +230,7 @@ class OStatus 'about' => $contact["about"], 'location' => $contact["location"], 'success_update' => DateTimeFormat::utcNow(), 'last-update' => DateTimeFormat::utcNow()]; - DBA::update('contact', $fields, ['id' => $cid], $old_contact); + Contact::update($fields, ['id' => $cid], $old_contact); // Update the avatar if (!empty($author["author-avatar"])) { diff --git a/src/Protocol/Relay.php b/src/Protocol/Relay.php index f89dc39999..b604f5ab37 100644 --- a/src/Protocol/Relay.php +++ b/src/Protocol/Relay.php @@ -166,7 +166,7 @@ class Relay $fields['updated'] = DateTimeFormat::utcNow(); Logger::info('Update relay contact', ['server' => $gserver['url'], 'id' => $old['id'], 'fields' => $fields]); - DBA::update('contact', $fields, ['id' => $old['id']], $old); + Contact::update($fields, ['id' => $old['id']], $old); } else { $default = ['created' => DateTimeFormat::utcNow(), 'name' => 'relay', 'nick' => 'relay', 'url' => $gserver['url'], diff --git a/src/Worker/ExpirePosts.php b/src/Worker/ExpirePosts.php index bd1addf11a..8d7b8c6eea 100644 --- a/src/Worker/ExpirePosts.php +++ b/src/Worker/ExpirePosts.php @@ -184,6 +184,7 @@ class ExpirePosts AND NOT EXISTS(SELECT `external-id` FROM `post-user` WHERE `external-id` = `item-uri`.`id`) AND NOT EXISTS(SELECT `uri-id` FROM `mail` WHERE `uri-id` = `item-uri`.`id`) AND NOT EXISTS(SELECT `uri-id` FROM `event` WHERE `uri-id` = `item-uri`.`id`) + 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`) diff --git a/src/Worker/OnePoll.php b/src/Worker/OnePoll.php index e1f0f61080..99d5054ca3 100644 --- a/src/Worker/OnePoll.php +++ b/src/Worker/OnePoll.php @@ -82,7 +82,7 @@ class OnePoll Logger::warning('No self contact for user', ['uid' => $importer_uid]); // set the last-update so we don't keep polling - DBA::update('contact', ['last-update' => $updated], ['id' => $contact['id']]); + Contact::update(['last-update' => $updated], ['id' => $contact['id']]); return; } @@ -122,16 +122,16 @@ class OnePoll { if (in_array($contact['network'], [Protocol::FEED, Protocol::MAIL, Protocol::OSTATUS])) { // Update the user's contact - DBA::update('contact', $fields, ['id' => $contact['id']]); + Contact::update($fields, ['id' => $contact['id']]); // Update the public contact - DBA::update('contact', $fields, ['uid' => 0, 'nurl' => $contact['nurl']]); + Contact::update($fields, ['uid' => 0, 'nurl' => $contact['nurl']]); // Update the rest of the contacts that aren't polled - DBA::update('contact', $fields, ['rel' => Contact::FOLLOWER, 'nurl' => $contact['nurl']]); + Contact::update($fields, ['rel' => Contact::FOLLOWER, 'nurl' => $contact['nurl']]); } else { // Update all contacts - DBA::update('contact', $fields, ['nurl' => $contact['nurl']]); + Contact::update($fields, ['nurl' => $contact['nurl']]); } } @@ -456,7 +456,7 @@ class OnePoll Logger::info('Hub subscription start', ['mode' => $hubmode, 'name' => $contact['name'], 'hub' => $url, 'endpoint' => $push_url, 'verifier' => $verify_token]); if (!strlen($contact['hub-verify']) || ($contact['hub-verify'] != $verify_token)) { - DBA::update('contact', ['hub-verify' => $verify_token], ['id' => $contact['id']]); + Contact::update(['hub-verify' => $verify_token], ['id' => $contact['id']]); } $postResult = DI::httpClient()->post($url, $params); diff --git a/src/Worker/RemoveUnusedAvatars.php b/src/Worker/RemoveUnusedAvatars.php index 58670c8735..7fdbeb7ecc 100644 --- a/src/Worker/RemoveUnusedAvatars.php +++ b/src/Worker/RemoveUnusedAvatars.php @@ -44,7 +44,7 @@ class RemoveUnusedAvatars $count = 0; $contacts = DBA::select('contact', ['id'], $condition); while ($contact = DBA::fetch($contacts)) { - DBA::update('contact', ['photo' => '', 'thumb' => '', 'micro' => ''], ['id' => $contact['id']]); + Contact::update(['photo' => '', 'thumb' => '', 'micro' => ''], ['id' => $contact['id']]); Photo::delete(['contact-id' => $contact['id'], 'album' => Photo::CONTACT_PHOTOS]); if ((++$count % 1000) == 0) { if (!Worker::isInMaintenanceWindow()) { diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 6f455d14e9..ef97c54f60 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1434); + define('DB_UPDATE_VERSION', 1435); } return [ @@ -172,29 +172,16 @@ return [ "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner User id"], "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], "updated" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => "Date of last contact update"], - "self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 if the contact is the user him/her self"], - "remote_self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], - "rel" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "The kind of the relation between the user and the contact"], - "duplex" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Deprecated"], "network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network of the contact"], - "protocol" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Protocol of the contact"], "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name that this contact is known by"], "nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Nick- and user name of the contact"], "location" => ["type" => "varchar(255)", "default" => "", "comment" => ""], "about" => ["type" => "text", "comment" => ""], "keywords" => ["type" => "text", "comment" => "public keywords (interests) of the contact"], - "gender" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => "Deprecated"], "xmpp" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "XMPP address"], "matrix" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Matrix address"], - "attag" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "avatar" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], - "photo" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo of the contact"], - "thumb" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo (thumb size)"], - "micro" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo (micro size)"], "header" => ["type" => "varchar(255)", "comment" => "Header picture"], - "site-pubkey" => ["type" => "text", "comment" => "Deprecated"], - "issued-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Deprecated"], - "dfrn-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Deprecated"], "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "nurl" => ["type" => "varchar(255)", "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 contact url"], @@ -203,54 +190,70 @@ return [ "pubkey" => ["type" => "text", "comment" => "RSA public key 4096 bit"], "prvkey" => ["type" => "text", "comment" => "RSA private key 4096 bit"], "batch" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], - "request" => ["type" => "varchar(255)", "comment" => ""], "notify" => ["type" => "varchar(255)", "comment" => ""], "poll" => ["type" => "varchar(255)", "comment" => ""], - "confirm" => ["type" => "varchar(255)", "comment" => ""], "subscribe" => ["type" => "varchar(255)", "comment" => ""], - "poco" => ["type" => "varchar(255)", "comment" => ""], - "aes_allow" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Deprecated"], - "ret-aes" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Deprecated"], - "usehub" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], - "subhub" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], - "hub-verify" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "last-update" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last try to update the contact info"], "success_update" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last successful contact update"], "failure_update" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last failed update"], "failed" => ["type" => "boolean", "comment" => "Connection failed"], - "name-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], - "uri-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], - "avatar-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], "term-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], "last-item" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "date of the last post"], "last-discovery" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "date of the last follower discovery"], - "priority" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], "blocked" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "Node-wide block status"], "block_reason" => ["type" => "text", "comment" => "Node-wide block reason"], "readonly" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "posts of the contact are readonly"], - "writable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], - "forum" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a forum"], - "prv" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a private group"], - "contact-type" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => ""], - "manually-approve" => ["type" => "boolean", "comment" => ""], - "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "contact-type" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => "Person, organisation, news, community, relay"], + "manually-approve" => ["type" => "boolean", "comment" => "Contact requests have to be approved manually"], "archive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], - "pending" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""], - "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact has been deleted"], - "rating" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => ""], "unsearchable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact prefers to not be searchable"], "sensitive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact posts sensitive content"], "baseurl" => ["type" => "varchar(255)", "default" => "", "comment" => "baseurl of the contact"], "gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID"], - "reason" => ["type" => "text", "comment" => ""], - "closeness" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "99", "comment" => ""], - "info" => ["type" => "mediumtext", "comment" => ""], - "profile-id" => ["type" => "int unsigned", "comment" => "Deprecated"], - "bdyear" => ["type" => "varchar(4)", "not null" => "1", "default" => "", "comment" => ""], "bd" => ["type" => "date", "not null" => "1", "default" => DBA::NULL_DATE, "comment" => ""], + // User depending fields + "reason" => ["type" => "text", "comment" => ""], + "self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 if the contact is the user him/her self"], + "remote_self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "rel" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "The kind of the relation between the user and the contact"], + "protocol" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Protocol of the contact"], + "subhub" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "hub-verify" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "rating" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => "Automatically detected feed poll frequency"], + "priority" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Feed poll priority"], + "attag" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "hidden" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "pending" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "Contact request is pending"], + "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact has been deleted"], + "info" => ["type" => "mediumtext", "comment" => ""], "notify_new_posts" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "fetch_further_information" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], "ffi_keyword_denylist" => ["type" => "text", "comment" => ""], + // Deprecated, but still in use + "photo" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo of the contact"], + "thumb" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo (thumb size)"], + "micro" => ["type" => "varchar(255)", "default" => "", "comment" => "Link to the profile photo (micro size)"], + "name-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "uri-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "avatar-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "request" => ["type" => "varchar(255)", "comment" => ""], + "confirm" => ["type" => "varchar(255)", "comment" => ""], + "poco" => ["type" => "varchar(255)", "comment" => ""], + "writable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "forum" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a forum. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = false instead"], + "prv" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a private group. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = true instead"], + "bdyear" => ["type" => "varchar(4)", "not null" => "1", "default" => "", "comment" => ""], + // Deprecated fields that aren't in use anymore + "site-pubkey" => ["type" => "text", "comment" => "Deprecated"], + "gender" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => "Deprecated"], + "duplex" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Deprecated"], + "issued-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Deprecated"], + "dfrn-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Deprecated"], + "aes_allow" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Deprecated"], + "ret-aes" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Deprecated"], + "usehub" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Deprecated"], + "closeness" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "99", "comment" => "Deprecated"], + "profile-id" => ["type" => "int unsigned", "comment" => "Deprecated"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -1531,13 +1534,27 @@ return [ "fields" => [ "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "primary" => "1", "foreign" => ["contact" => "id"], "comment" => "Contact id of the linked public contact"], "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "primary" => "1", "foreign" => ["user" => "uid"], "comment" => "User id"], + "uri-id" => ["type" => "int unsigned", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the contact url"], "blocked" => ["type" => "boolean", "comment" => "Contact is completely blocked for this user"], "ignored" => ["type" => "boolean", "comment" => "Posts from this contact are ignored"], - "collapsed" => ["type" => "boolean", "comment" => "Posts from this contact are collapsed"] + "collapsed" => ["type" => "boolean", "comment" => "Posts from this contact are collapsed"], + "pending" => ["type" => "boolean", "comment" => ""], + "rel" => ["type" => "tinyint unsigned", "comment" => "The kind of the relation between the user and the contact"], + "info" => ["type" => "mediumtext", "comment" => ""], + "notify_new_posts" => ["type" => "boolean", "comment" => ""], + "remote_self" => ["type" => "boolean", "comment" => ""], + "fetch_further_information" => ["type" => "tinyint unsigned", "comment" => ""], + "ffi_keyword_denylist" => ["type" => "text", "comment" => ""], + "subhub" => ["type" => "boolean", "comment" => ""], + "hub-verify" => ["type" => "varchar(255)", "comment" => ""], + "protocol" => ["type" => "char(4)", "comment" => "Protocol of the contact"], + "rating" => ["type" => "tinyint", "comment" => "Automatically detected feed poll frequency"], + "priority" => ["type" => "tinyint unsigned", "comment" => "Feed poll priority"], ], "indexes" => [ "PRIMARY" => ["uid", "cid"], "cid" => ["cid"], + "uri-id_uid" => ["UNIQUE", "uri-id", "uid"], ] ], "worker-ipc" => [ diff --git a/static/dbview.config.php b/static/dbview.config.php index c9acd55ba9..5b3e8b5826 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -711,7 +711,6 @@ "location" => ["contact", "location"], "about" => ["contact", "about"], "keywords" => ["contact", "keywords"], - "gender" => ["contact", "gender"], "xmpp" => ["contact", "xmpp"], "matrix" => ["contact", "matrix"], "attag" => ["contact", "attag"], @@ -733,7 +732,6 @@ "poll" => ["contact", "poll"], "confirm" => ["contact", "confirm"], "poco" => ["contact", "poco"], - "usehub" => ["contact", "usehub"], "subhub" => ["contact", "subhub"], "hub-verify" => ["contact", "hub-verify"], "last-update" => ["contact", "last-update"], @@ -762,9 +760,7 @@ "sensitive" => ["contact", "sensitive"], "baseurl" => ["contact", "baseurl"], "reason" => ["contact", "reason"], - "closeness" => ["contact", "closeness"], "info" => ["contact", "info"], - "profile-id" => ["contact", "profile-id"], "bdyear" => ["contact", "bdyear"], "bd" => ["contact", "bd"], "notify_new_posts" => ["contact", "notify_new_posts"], @@ -934,7 +930,7 @@ "network" => ["contact", "network"], "protocol" => ["ucontact", "protocol"], "location" => ["contact", "location"], - "attag" => ["contact", "attag"], + "attag" => ["ucontact", "attag"], "pubkey" => ["contact", "pubkey"], "prvkey" => ["contact", "prvkey"], "subscribe" => ["contact", "subscribe"], @@ -950,7 +946,7 @@ "sensitive" => ["contact", "sensitive"], "baseurl" => ["contact", "baseurl"], "gsid" => ["contact", "gsid"], - "info" => ["contact", "info"], + "info" => ["ucontact", "info"], "bdyear" => ["contact", "bdyear"], "bd" => ["contact", "bd"], "poco" => ["contact", "poco"], diff --git a/update.php b/update.php index 536610a00e..49287cd0b2 100644 --- a/update.php +++ b/update.php @@ -998,3 +998,11 @@ function update_1434() return Update::SUCCESS; } + +function update_1435() +{ + $contacts = DBA::select('contact', [], ["`uid` != ?", 0]); + while ($contact = DBA::fetch($contacts)) { + Contact\User::insertForContactArray($contact); + } +} \ No newline at end of file diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 59799c01ec..46d072b32e 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2021.12-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-01 16:40+0200\n" +"POT-Creation-Date: 2021-10-02 11:56+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -37,7 +37,7 @@ msgstr[1] "" msgid "Monthly posting limit of %d post reached. The post was rejected." msgstr "" -#: include/api.php:4437 mod/photos.php:89 mod/photos.php:198 mod/photos.php:626 +#: include/api.php:4429 mod/photos.php:89 mod/photos.php:198 mod/photos.php:626 #: mod/photos.php:1035 mod/photos.php:1052 mod/photos.php:1599 #: src/Model/User.php:1169 src/Model/User.php:1177 src/Model/User.php:1185 #: src/Module/Settings/Profile/Photo/Crop.php:101 @@ -559,7 +559,7 @@ msgstr "" #: mod/editpost.php:134 src/Content/Conversation.php:380 #: src/Content/Widget/VCard.php:107 src/Model/Profile.php:459 -#: src/Module/Admin/Logs/View.php:93 +#: src/Module/Admin/Logs/View.php:92 msgid "Message" msgstr "" @@ -589,7 +589,7 @@ msgstr "" msgid "Create New Event" msgstr "" -#: mod/events.php:536 src/Module/Admin/Logs/View.php:97 +#: mod/events.php:536 src/Module/Admin/Logs/View.php:96 msgid "Event details" msgstr "" @@ -718,7 +718,7 @@ msgid "OStatus support is disabled. Contact can't be added." msgstr "" #: mod/follow.php:138 src/Content/Item.php:463 src/Content/Widget.php:76 -#: src/Model/Contact.php:1051 src/Model/Contact.php:1064 +#: src/Model/Contact.php:1077 src/Model/Contact.php:1090 #: view/theme/vier/theme.php:172 msgid "Connect/Follow" msgstr "" @@ -2424,12 +2424,12 @@ msgstr "" msgid "Addon already disabled" msgstr "" -#: src/Console/ArchiveContact.php:105 +#: src/Console/ArchiveContact.php:106 #, php-format msgid "Could not find any unarchived contact entry for this URL (%s)" msgstr "" -#: src/Console/ArchiveContact.php:108 +#: src/Console/ArchiveContact.php:109 msgid "The contact entries have been archived" msgstr "" @@ -3002,31 +3002,31 @@ msgstr "" msgid "Follow Thread" msgstr "" -#: src/Content/Item.php:443 src/Model/Contact.php:1056 +#: src/Content/Item.php:443 src/Model/Contact.php:1082 msgid "View Status" msgstr "" -#: src/Content/Item.php:444 src/Content/Item.php:466 src/Model/Contact.php:982 -#: src/Model/Contact.php:1048 src/Model/Contact.php:1057 +#: src/Content/Item.php:444 src/Content/Item.php:466 src/Model/Contact.php:1008 +#: src/Model/Contact.php:1074 src/Model/Contact.php:1083 #: src/Module/Directory.php:160 src/Module/Settings/Profile/Index.php:223 msgid "View Profile" msgstr "" -#: src/Content/Item.php:445 src/Model/Contact.php:1058 +#: src/Content/Item.php:445 src/Model/Contact.php:1084 msgid "View Photos" msgstr "" -#: src/Content/Item.php:446 src/Model/Contact.php:1049 -#: src/Model/Contact.php:1059 +#: src/Content/Item.php:446 src/Model/Contact.php:1075 +#: src/Model/Contact.php:1085 msgid "Network Posts" msgstr "" -#: src/Content/Item.php:447 src/Model/Contact.php:1050 -#: src/Model/Contact.php:1060 +#: src/Content/Item.php:447 src/Model/Contact.php:1076 +#: src/Model/Contact.php:1086 msgid "View Contact" msgstr "" -#: src/Content/Item.php:448 src/Model/Contact.php:1062 +#: src/Content/Item.php:448 src/Model/Contact.php:1088 msgid "Send PM" msgstr "" @@ -3049,7 +3049,7 @@ msgstr "" msgid "Languages" msgstr "" -#: src/Content/Item.php:458 src/Model/Contact.php:1063 +#: src/Content/Item.php:458 src/Model/Contact.php:1089 msgid "Poke" msgstr "" @@ -3166,7 +3166,7 @@ msgid "Addon applications, utilities, games" msgstr "" #: src/Content/Nav.php:230 src/Content/Text/HTML.php:891 -#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:99 +#: src/Module/Admin/Logs/View.php:86 src/Module/Search/Index.php:99 msgid "Search" msgstr "" @@ -3499,7 +3499,7 @@ msgstr "" msgid "Organisations" msgstr "" -#: src/Content/Widget.php:529 src/Model/Contact.php:1480 +#: src/Content/Widget.php:529 src/Model/Contact.php:1505 msgid "News" msgstr "" @@ -4363,85 +4363,85 @@ msgstr "" msgid "Legacy module file not found: %s" msgstr "" -#: src/Model/Contact.php:1052 src/Model/Contact.php:1065 +#: src/Model/Contact.php:1078 src/Model/Contact.php:1091 msgid "UnFollow" msgstr "" -#: src/Model/Contact.php:1061 +#: src/Model/Contact.php:1087 msgid "Drop Contact" msgstr "" -#: src/Model/Contact.php:1071 src/Module/Admin/Users/Pending.php:107 +#: src/Model/Contact.php:1097 src/Module/Admin/Users/Pending.php:107 #: src/Module/Notifications/Introductions.php:111 #: src/Module/Notifications/Introductions.php:183 msgid "Approve" msgstr "" -#: src/Model/Contact.php:1476 +#: src/Model/Contact.php:1501 msgid "Organisation" msgstr "" -#: src/Model/Contact.php:1484 +#: src/Model/Contact.php:1509 msgid "Forum" msgstr "" -#: src/Model/Contact.php:2340 +#: src/Model/Contact.php:2365 msgid "Disallowed profile URL." msgstr "" -#: src/Model/Contact.php:2345 src/Module/Friendica.php:81 +#: src/Model/Contact.php:2370 src/Module/Friendica.php:81 msgid "Blocked domain" msgstr "" -#: src/Model/Contact.php:2350 +#: src/Model/Contact.php:2375 msgid "Connect URL missing." msgstr "" -#: src/Model/Contact.php:2359 +#: src/Model/Contact.php:2384 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "" -#: src/Model/Contact.php:2396 +#: src/Model/Contact.php:2421 msgid "The profile address specified does not provide adequate information." msgstr "" -#: src/Model/Contact.php:2398 +#: src/Model/Contact.php:2423 msgid "No compatible communication protocols or feeds were discovered." msgstr "" -#: src/Model/Contact.php:2401 +#: src/Model/Contact.php:2426 msgid "An author or name was not found." msgstr "" -#: src/Model/Contact.php:2404 +#: src/Model/Contact.php:2429 msgid "No browser URL could be matched to this address." msgstr "" -#: src/Model/Contact.php:2407 +#: src/Model/Contact.php:2432 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "" -#: src/Model/Contact.php:2408 +#: src/Model/Contact.php:2433 msgid "Use mailto: in front of address to force email check." msgstr "" -#: src/Model/Contact.php:2414 +#: src/Model/Contact.php:2439 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "" -#: src/Model/Contact.php:2419 +#: src/Model/Contact.php:2444 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "" -#: src/Model/Contact.php:2478 +#: src/Model/Contact.php:2503 msgid "Unable to retrieve contact information." msgstr "" @@ -5049,7 +5049,7 @@ msgstr "" #: src/Module/Admin/Blocklist/Contact.php:78 #: src/Module/Admin/Blocklist/Server.php:88 src/Module/Admin/Federation.php:159 #: src/Module/Admin/Item/Delete.php:65 src/Module/Admin/Logs/Settings.php:80 -#: src/Module/Admin/Logs/View.php:84 src/Module/Admin/Queue.php:72 +#: src/Module/Admin/Logs/View.php:83 src/Module/Admin/Queue.php:72 #: src/Module/Admin/Site.php:497 src/Module/Admin/Storage.php:131 #: src/Module/Admin/Summary.php:233 src/Module/Admin/Themes/Details.php:90 #: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:58 @@ -5484,7 +5484,7 @@ msgstr "" msgid "Implicit Mention" msgstr "" -#: src/Module/Admin/Item/Source.php:73 src/Module/Admin/Logs/View.php:99 +#: src/Module/Admin/Item/Source.php:73 src/Module/Admin/Logs/View.php:98 #: src/Module/Debug/ActivityPubConversion.php:62 msgid "Source" msgstr "" @@ -5542,82 +5542,82 @@ msgid "" "'display_errors' is to enable these options, set to '0' to disable them." msgstr "" -#: src/Module/Admin/Logs/View.php:71 +#: src/Module/Admin/Logs/View.php:70 #, php-format msgid "" "Error trying to open %1$s log file.
Check to see if " "file %1$s exist and is readable." msgstr "" -#: src/Module/Admin/Logs/View.php:80 +#: src/Module/Admin/Logs/View.php:79 #, php-format msgid "" "Couldn't open %1$s log file.
Check to see if file %1$s " "is readable." msgstr "" -#: src/Module/Admin/Logs/View.php:85 src/Module/BaseAdmin.php:110 +#: src/Module/Admin/Logs/View.php:84 src/Module/BaseAdmin.php:110 msgid "View Logs" msgstr "" -#: src/Module/Admin/Logs/View.php:88 +#: src/Module/Admin/Logs/View.php:87 msgid "Search in logs" msgstr "" -#: src/Module/Admin/Logs/View.php:89 +#: src/Module/Admin/Logs/View.php:88 #: src/Module/Notifications/Notifications.php:138 msgid "Show all" msgstr "" -#: src/Module/Admin/Logs/View.php:90 +#: src/Module/Admin/Logs/View.php:89 msgid "Date" msgstr "" -#: src/Module/Admin/Logs/View.php:91 +#: src/Module/Admin/Logs/View.php:90 msgid "Level" msgstr "" -#: src/Module/Admin/Logs/View.php:92 +#: src/Module/Admin/Logs/View.php:91 msgid "Context" msgstr "" -#: src/Module/Admin/Logs/View.php:94 +#: src/Module/Admin/Logs/View.php:93 msgid "ALL" msgstr "" -#: src/Module/Admin/Logs/View.php:95 +#: src/Module/Admin/Logs/View.php:94 msgid "View details" msgstr "" -#: src/Module/Admin/Logs/View.php:96 +#: src/Module/Admin/Logs/View.php:95 msgid "Click to view details" msgstr "" -#: src/Module/Admin/Logs/View.php:98 +#: src/Module/Admin/Logs/View.php:97 msgid "Data" msgstr "" -#: src/Module/Admin/Logs/View.php:100 +#: src/Module/Admin/Logs/View.php:99 msgid "File" msgstr "" -#: src/Module/Admin/Logs/View.php:101 +#: src/Module/Admin/Logs/View.php:100 msgid "Line" msgstr "" -#: src/Module/Admin/Logs/View.php:102 +#: src/Module/Admin/Logs/View.php:101 msgid "Function" msgstr "" -#: src/Module/Admin/Logs/View.php:103 +#: src/Module/Admin/Logs/View.php:102 msgid "UID" msgstr "" -#: src/Module/Admin/Logs/View.php:104 +#: src/Module/Admin/Logs/View.php:103 msgid "Process ID" msgstr "" -#: src/Module/Admin/Logs/View.php:105 +#: src/Module/Admin/Logs/View.php:104 msgid "Close" msgstr ""