Compare commits

..

75 commits

Author SHA1 Message Date
Michael Vogel
85e36abb5f
Merge pull request #10486 from nupplaphil/feat/remove_test_data
Remove outdated friendica_test_data.sql
2021-07-11 14:38:34 +02:00
a676060eea
Remove outdated friendica_test_data.sql 2021-07-11 14:27:52 +02:00
780d9f1793
Merge pull request #10483 from annando/account
New view that combines all contact tables
2021-07-11 01:14:39 -04:00
58b84ca01d Public id added 2021-07-11 03:06:46 +00:00
f1e4d30898 New view chat combines all contact tables 2021-07-10 21:55:03 +00:00
f6df07ec86
Merge pull request #10482 from annando/converturiid
Some more "convertForUriId" replacements
2021-07-10 17:45:34 -04:00
b46b88cc10 Fix fatal error 2021-07-10 21:08:55 +00:00
49c59fed2c Fix tests 2021-07-10 14:04:27 +00:00
e5e3143293 Fix tests 2021-07-10 14:02:03 +00:00
07d2dfcd60 Some more "convertForUriId" replacements 2021-07-10 12:58:48 +00:00
c151376596
Merge pull request #10480 from annando/postupdate
Post update: Set "uri-id" in the contact tables
2021-07-09 22:19:39 -04:00
Michael Vogel
c41aaf8a17
Merge pull request #10479 from MrPetovan/task/9378-merge-share-template
Merge frio-specific share block template into the base template
2021-07-10 04:01:51 +02:00
161fa4a795 Post update: Set "uri-id" in the contact tables 2021-07-10 01:41:26 +00:00
f3f890702c
Merge pull request #10478 from annando/notice
Fix notice "undefined index: uri"
2021-07-09 19:31:30 -04:00
540dc90ce1 Merge frio-specific share block template into the base template
- Add BIDI support for share blocks
- Remove redundant share block styles
2021-07-09 19:23:01 -04:00
de39091a79 Revert some test changes 2021-07-09 19:32:06 +00:00
90897f36ca Fix notices because of unknown Hubzilla activity type 2021-07-09 19:30:41 +00:00
d6c1e1fd1c Fix "Undefined index: reply-to-id" 2021-07-09 18:10:48 +00:00
e0fdde3287 Fix the tests, hopefully 2021-07-09 17:13:54 +00:00
04580ad4fb Don't update automatically to make tests happy 2021-07-09 16:20:22 +00:00
0735a22cdd Fix notice "undefined index: uri" 2021-07-09 14:52:22 +00:00
6354d7c81d
Merge pull request #10472 from annando/proxy
Simplified proxy, item cache related stuff removed
2021-07-09 08:35:48 -04:00
9ac284ec3a Update on empty uri-id 2021-07-09 08:46:42 +00:00
b50a92cf7a Contact tables added to expire function 2021-07-09 08:08:48 +00:00
6e79da0b0c The uri-id is now in all contact tables 2021-07-09 07:09:33 +00:00
c63d3f4604 Fix tests 2021-07-09 06:37:45 +00:00
d8974c9a2a Function renamed to better reflect the functionality 2021-07-09 06:29:24 +00:00
17ae9b71af Avoid error on empty content 2021-07-09 04:42:01 +00:00
88f147c6a7 Always update on missing uri-id, check for uri-id in contact before removal 2021-07-09 04:38:36 +00:00
377bb78cc2 Set "convertForItem" at more places 2021-07-08 20:01:52 +00:00
dfe1d53342 Moved database structure 2021-07-08 19:16:23 +00:00
901c3f4855 we now have got an uri-id field for the contact table 2021-07-08 18:59:58 +00:00
178bc543e3 New founction to count threads 2021-07-08 17:32:41 +00:00
c972cce740 Avoid notice 2021-07-08 16:38:02 +00:00
e72e74f7db Fixed function name 2021-07-08 15:44:55 +00:00
165c6ddc63 "convert" changed to "convertForItem" 2021-07-08 15:41:46 +00:00
f29bd23ea8 New function to convert BBCode for a given ID 2021-07-08 13:47:46 +00:00
f3452d86c4 Improved logging, improved link check 2021-07-06 17:40:40 +00:00
ecf0b67d9d Just look at HTTP links 2021-07-06 16:10:10 +00:00
234bdff7ab Improved link check 2021-07-06 15:06:15 +00:00
37a76e70ef Providing the uri-id to "convert" when possible 2021-07-06 12:34:48 +00:00
098cd543ea Cleaned code for contact avatars 2021-07-06 10:36:00 +00:00
1b6f9e6225 Parameter documentation 2021-07-06 10:00:53 +00:00
d0136222e7 Further simplification 2021-07-06 09:24:25 +00:00
12173df4d3 Replace proxy function 2021-07-06 09:22:41 +00:00
8bfa15cf23 Simplify the attachment handling 2021-07-06 08:57:49 +00:00
b7a4ef0ec1 Modfy links for attachments 2021-07-06 08:40:59 +00:00
59a77ceac8 Updated messages.po 2021-07-06 07:16:46 +00:00
93309a3728 Quit on empty uri-id 2021-07-06 06:45:53 +00:00
dac27ead7a Proxy settings removed 2021-07-06 06:44:18 +00:00
21cc2d28a3 Proxy removed in API 2021-07-06 06:38:15 +00:00
cdc18387fd Use the uri-id directly in the bbcode converter 2021-07-06 05:25:30 +00:00
f8ce59b411 Use the post uri-id for false reshares 2021-07-06 04:36:45 +00:00
3deb384c54 Replace the proxify function 2021-07-05 21:35:57 +00:00
db90e3bf25 Remove attachment on plaintext conversion 2021-07-05 20:20:39 +00:00
c06331e690 Changelog updated 2021-07-05 19:44:08 +00:00
903c646a62 Style 2021-07-05 19:42:17 +00:00
aed5e4cc96 New struture for post related links 2021-07-05 18:45:49 +00:00
90588ddb8e Avoid proxyfying images that are removed or replaced later 2021-07-05 07:00:35 +00:00
a5176cb841 Unused constant removed 2021-07-05 05:41:05 +00:00
31bf8d3ea0 Updated messages.po 2021-07-05 05:15:35 +00:00
fccb725651 Unneeded workaround removed 2021-07-05 05:11:35 +00:00
a06d699480 Item cache related functionality removed 2021-07-05 04:57:50 +00:00
844727dc19 Simplyfying code 2021-07-05 04:16:02 +00:00
7188ed745c Merge remote-tracking branch 'upstream/develop' into proxy 2021-07-05 03:44:15 +00:00
fcfbd3edf9
Merge pull request #10471 from annando/notice
Fix notice "Undefined index: account-type"
2021-07-04 23:33:27 -04:00
b09f555f4f Merge remote-tracking branch 'upstream/develop' into notice 2021-07-05 03:03:41 +00:00
9126c2c454
Merge pull request #10470 from annando/local-publish-search
Allow search for only locally published contacts
2021-07-04 19:42:55 -04:00
1b6d0f8b1f Fix notice "Undefined index: account-type" 2021-07-04 21:26:08 +00:00
e519b782fd Simplified proxy handling 2021-07-04 21:24:49 +00:00
dfc1b1e7a5 Allow search for only locally published contacts 2021-07-04 19:58:02 +00:00
968122337d pump version to :wq2021.09-dev 2021-07-04 20:54:24 +02:00
2b95a7e7cd Merge branch 'stable' into develop 2021-07-04 20:52:22 +02:00
Michael Vogel
90a9cefd9a
Merge pull request #10399 from elrido/photo-md5
Reduce batch size for photo processing to reduce memory usage
2021-06-12 21:35:02 +02:00
Simon Rupf
8b841ccc51 Reduce batch size for photo processing to reduce memory usage 2021-06-12 20:40:17 +02:00
80 changed files with 2075 additions and 3975 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

View file

@ -1,3 +1,7 @@
Version 2021.09 (unreleased)
Friendica Core
Simplified the proxy mechanism. The proxy cache directory (/proxy) can now be removed [annando]
Version 2021.07 (2021-07-04) Version 2021.07 (2021-07-04)
Friendica Core Friendica Core
Updates to the translation DE, EN-GB, HU, IT, JA [translation teams] Updates to the translation DE, EN-GB, HU, IT, JA [translation teams]

View file

@ -1 +1 @@
2021.07 2021.09-dev

View file

@ -107,8 +107,6 @@ cp /vagrant/.htaccess-dist /vagrant/.htaccess
# create the friendica database # create the friendica database
echo "create database friendica DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" | $MYSQL -u root -proot echo "create database friendica DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" | $MYSQL -u root -proot
# import test database (disabled because too old)
#$MYSQL -uroot -proot friendica < /vagrant/friendica_test_data.sql
# install friendica # install friendica
bin/console autoinstall -f /vagrant/mods/local.config.vagrant.php bin/console autoinstall -f /vagrant/mods/local.config.vagrant.php

View file

@ -38,7 +38,7 @@ use Friendica\Util\DateTimeFormat;
define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Siberian Iris'); define('FRIENDICA_CODENAME', 'Siberian Iris');
define('FRIENDICA_VERSION', '2021.07'); define('FRIENDICA_VERSION', '2021.09-dev');
define('DFRN_PROTOCOL_VERSION', '2.23'); define('DFRN_PROTOCOL_VERSION', '2.23');
define('NEW_TABLE_STRUCTURE_VERSION', 1288); define('NEW_TABLE_STRUCTURE_VERSION', 1288);
@ -444,93 +444,6 @@ function get_temppath()
return ''; return '';
} }
function get_cachefile($file, $writemode = true)
{
$cache = get_itemcachepath();
if ((!$cache) || (!is_dir($cache))) {
return "";
}
$subfolder = $cache . "/" . substr($file, 0, 2);
$cachepath = $subfolder . "/" . $file;
if ($writemode) {
if (!is_dir($subfolder)) {
mkdir($subfolder);
chmod($subfolder, 0777);
}
}
return $cachepath;
}
function clear_cache($basepath = "", $path = "")
{
if ($path == "") {
$basepath = get_itemcachepath();
$path = $basepath;
}
if (($path == "") || (!is_dir($path))) {
return;
}
if (substr(realpath($path), 0, strlen($basepath)) != $basepath) {
return;
}
$cachetime = (int) DI::config()->get('system', 'itemcache_duration');
if ($cachetime == 0) {
$cachetime = 86400;
}
if (is_writable($path)) {
if ($dh = opendir($path)) {
while (($file = readdir($dh)) !== false) {
$fullpath = $path . "/" . $file;
if ((filetype($fullpath) == "dir") && ($file != ".") && ($file != "..")) {
clear_cache($basepath, $fullpath);
}
if ((filetype($fullpath) == "file") && (filectime($fullpath) < (time() - $cachetime))) {
unlink($fullpath);
}
}
closedir($dh);
}
}
}
function get_itemcachepath()
{
// Checking, if the cache is deactivated
$cachetime = (int) DI::config()->get('system', 'itemcache_duration');
if ($cachetime < 0) {
return "";
}
$itemcache = DI::config()->get('system', 'itemcache');
if (($itemcache != "") && System::isDirectoryUsable($itemcache)) {
return BasePath::getRealPath($itemcache);
}
$temppath = get_temppath();
if ($temppath != "") {
$itemcache = $temppath . "/itemcache";
if (!file_exists($itemcache) && !is_dir($itemcache)) {
mkdir($itemcache);
}
if (System::isDirectoryUsable($itemcache)) {
DI::config()->set("system", "itemcache", $itemcache);
return $itemcache;
}
}
return "";
}
/** /**
* Returns the path where spool files are stored * Returns the path where spool files are stored
* *

View file

@ -1,6 +1,6 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 2021.06-rc (Siberian Iris) -- Friendica 2021.09-dev (Siberian Iris)
-- DB_UPDATE_VERSION 1424 -- DB_UPDATE_VERSION 1428
-- ------------------------------------------ -- ------------------------------------------
@ -94,6 +94,18 @@ CREATE TABLE IF NOT EXISTS `user` (
FOREIGN KEY (`parent-uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE FOREIGN KEY (`parent-uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='The local users'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='The local users';
--
-- TABLE item-uri
--
CREATE TABLE IF NOT EXISTS `item-uri` (
`id` int unsigned NOT NULL auto_increment,
`uri` varbinary(255) NOT NULL COMMENT 'URI of an item',
`guid` varbinary(255) COMMENT 'A unique identifier for an item',
PRIMARY KEY(`id`),
UNIQUE INDEX `uri` (`uri`),
INDEX `guid` (`guid`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='URI and GUID for items';
-- --
-- TABLE contact -- TABLE contact
-- --
@ -126,6 +138,7 @@ CREATE TABLE IF NOT EXISTS `contact` (
`dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT '', `dfrn-id` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '', `url` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`nurl` 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',
`addr` varchar(255) NOT NULL DEFAULT '' COMMENT '', `addr` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`alias` varchar(255) NOT NULL DEFAULT '' COMMENT '', `alias` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`pubkey` text COMMENT 'RSA public key 4096 bit', `pubkey` text COMMENT 'RSA public key 4096 bit',
@ -202,22 +215,12 @@ CREATE TABLE IF NOT EXISTS `contact` (
INDEX `uid_self_contact-type` (`uid`,`self`,`contact-type`), INDEX `uid_self_contact-type` (`uid`,`self`,`contact-type`),
INDEX `self_network_uid` (`self`,`network`,`uid`), INDEX `self_network_uid` (`self`,`network`,`uid`),
INDEX `gsid` (`gsid`), INDEX `gsid` (`gsid`),
INDEX `uri-id` (`uri-id`),
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,
FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='contact table'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='contact table';
--
-- TABLE item-uri
--
CREATE TABLE IF NOT EXISTS `item-uri` (
`id` int unsigned NOT NULL auto_increment,
`uri` varbinary(255) NOT NULL COMMENT 'URI of an item',
`guid` varbinary(255) COMMENT 'A unique identifier for an item',
PRIMARY KEY(`id`),
UNIQUE INDEX `uri` (`uri`),
INDEX `guid` (`guid`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='URI and GUID for items';
-- --
-- TABLE tag -- TABLE tag
-- --
@ -332,6 +335,7 @@ CREATE TABLE IF NOT EXISTS `addon` (
-- --
CREATE TABLE IF NOT EXISTS `apcontact` ( CREATE TABLE IF NOT EXISTS `apcontact` (
`url` varbinary(255) NOT NULL COMMENT 'URL of the contact', `url` varbinary(255) NOT NULL COMMENT 'URL of the contact',
`uri-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the apcontact url',
`uuid` varchar(255) COMMENT '', `uuid` varchar(255) COMMENT '',
`type` varchar(20) NOT NULL COMMENT '', `type` varchar(20) NOT NULL COMMENT '',
`following` varchar(255) COMMENT '', `following` varchar(255) COMMENT '',
@ -364,6 +368,8 @@ CREATE TABLE IF NOT EXISTS `apcontact` (
INDEX `baseurl` (`baseurl`(190)), INDEX `baseurl` (`baseurl`(190)),
INDEX `sharedinbox` (`sharedinbox`(190)), INDEX `sharedinbox` (`sharedinbox`(190)),
INDEX `gsid` (`gsid`), INDEX `gsid` (`gsid`),
UNIQUE INDEX `uri-id` (`uri-id`),
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 FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='ActivityPub compatible contacts - used in the ActivityPub implementation'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='ActivityPub compatible contacts - used in the ActivityPub implementation';
@ -563,6 +569,7 @@ CREATE TABLE IF NOT EXISTS `event` (
`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id',
`cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact_id (ID of the contact in contact table)', `cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact_id (ID of the contact in contact table)',
`uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', `uri` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`uri-id` int unsigned COMMENT 'Id of the item-uri table entry that contains the event uri',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time',
`edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'last edit time', `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'last edit time',
`start` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'event start time', `start` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'event start time',
@ -581,8 +588,10 @@ CREATE TABLE IF NOT EXISTS `event` (
PRIMARY KEY(`id`), PRIMARY KEY(`id`),
INDEX `uid_start` (`uid`,`start`), INDEX `uid_start` (`uid`,`start`),
INDEX `cid` (`cid`), INDEX `cid` (`cid`),
INDEX `uri-id` (`uri-id`),
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 (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) 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='Events'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Events';
-- --
@ -592,6 +601,7 @@ CREATE TABLE IF NOT EXISTS `fcontact` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'unique id', `guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'unique id',
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '', `url` varchar(255) 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 '', `name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`photo` varchar(255) NOT NULL DEFAULT '' COMMENT '', `photo` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`request` varchar(255) NOT NULL DEFAULT '' COMMENT '', `request` varchar(255) NOT NULL DEFAULT '' COMMENT '',
@ -608,7 +618,9 @@ CREATE TABLE IF NOT EXISTS `fcontact` (
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
PRIMARY KEY(`id`), PRIMARY KEY(`id`),
INDEX `addr` (`addr`(32)), INDEX `addr` (`addr`(32)),
UNIQUE INDEX `url` (`url`(190)) 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'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Diaspora compatible contacts - used in the Diaspora implementation';
-- --
@ -1103,6 +1115,19 @@ CREATE TABLE IF NOT EXISTS `post-delivery-data` (
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) 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='Delivery data for items'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Delivery data for items';
--
-- TABLE post-link
--
CREATE TABLE IF NOT EXISTS `post-link` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri',
`url` varbinary(511) NOT NULL COMMENT 'External URL',
`mimetype` varchar(60) COMMENT '',
PRIMARY KEY(`id`),
UNIQUE INDEX `uri-id-url` (`uri-id`,`url`),
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Post related external links';
-- --
-- TABLE post-media -- TABLE post-media
-- --
@ -1278,6 +1303,7 @@ CREATE TABLE IF NOT EXISTS `post-thread-user` (
INDEX `post-user-id` (`post-user-id`), INDEX `post-user-id` (`post-user-id`),
INDEX `commented` (`commented`), INDEX `commented` (`commented`),
INDEX `uid_received` (`uid`,`received`), INDEX `uid_received` (`uid`,`received`),
INDEX `uid_wall_received` (`uid`,`wall`,`received`),
INDEX `uid_pinned` (`uid`,`pinned`), INDEX `uid_pinned` (`uid`,`pinned`),
INDEX `uid_commented` (`uid`,`commented`), INDEX `uid_commented` (`uid`,`commented`),
INDEX `uid_starred` (`uid`,`starred`), INDEX `uid_starred` (`uid`,`starred`),
@ -2265,6 +2291,7 @@ CREATE VIEW `owner-view` AS SELECT
`contact`.`dfrn-id` AS `dfrn-id`, `contact`.`dfrn-id` AS `dfrn-id`,
`contact`.`url` AS `url`, `contact`.`url` AS `url`,
`contact`.`nurl` AS `nurl`, `contact`.`nurl` AS `nurl`,
`contact`.`uri-id` AS `uri-id`,
`contact`.`addr` AS `addr`, `contact`.`addr` AS `addr`,
`contact`.`alias` AS `alias`, `contact`.`alias` AS `alias`,
`contact`.`pubkey` AS `pubkey`, `contact`.`pubkey` AS `pubkey`,
@ -2368,6 +2395,189 @@ CREATE VIEW `owner-view` AS SELECT
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self` INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`; INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`;
--
-- VIEW account-view
--
DROP VIEW IF EXISTS `account-view`;
CREATE VIEW `account-view` AS SELECT
`contact`.`id` AS `id`,
`contact`.`url` AS `url`,
`contact`.`nurl` AS `nurl`,
`contact`.`uri-id` AS `uri-id`,
`contact`.`addr` AS `addr`,
`contact`.`alias` AS `alias`,
`contact`.`name` AS `name`,
`contact`.`nick` AS `nick`,
`contact`.`about` AS `about`,
`contact`.`keywords` AS `keywords`,
`contact`.`xmpp` AS `xmpp`,
`contact`.`avatar` AS `avatar`,
`contact`.`photo` AS `photo`,
`contact`.`thumb` AS `thumb`,
`contact`.`micro` AS `micro`,
`contact`.`header` AS `header`,
`contact`.`created` AS `created`,
`contact`.`updated` AS `updated`,
`contact`.`network` AS `network`,
`contact`.`protocol` AS `protocol`,
`contact`.`location` AS `location`,
`contact`.`attag` AS `attag`,
`contact`.`pubkey` AS `pubkey`,
`contact`.`prvkey` AS `prvkey`,
`contact`.`subscribe` AS `subscribe`,
`contact`.`last-update` AS `last-update`,
`contact`.`success_update` AS `success_update`,
`contact`.`failure_update` AS `failure_update`,
`contact`.`failed` AS `failed`,
`contact`.`last-item` AS `last-item`,
`contact`.`last-discovery` AS `last-discovery`,
`contact`.`contact-type` AS `contact-type`,
`contact`.`manually-approve` AS `manually-approve`,
`contact`.`unsearchable` AS `unsearchable`,
`contact`.`sensitive` AS `sensitive`,
`contact`.`baseurl` AS `baseurl`,
`contact`.`gsid` AS `gsid`,
`contact`.`info` AS `info`,
`contact`.`bdyear` AS `bdyear`,
`contact`.`bd` AS `bd`,
`contact`.`poco` AS `poco`,
`contact`.`name-date` AS `name-date`,
`contact`.`uri-date` AS `uri-date`,
`contact`.`avatar-date` AS `avatar-date`,
`contact`.`term-date` AS `term-date`,
`contact`.`hidden` AS `global-ignored`,
`contact`.`blocked` AS `global-blocked`,
`contact`.`hidden` AS `hidden`,
`contact`.`archive` AS `archive`,
`contact`.`deleted` AS `deleted`,
`contact`.`blocked` AS `blocked`,
`contact`.`request` AS `dfrn-request`,
`contact`.`notify` AS `dfrn-notify`,
`contact`.`poll` AS `dfrn-poll`,
`contact`.`confirm` AS `dfrn-confirm`,
`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`,
`apcontact`.`uuid` AS `ap-uuid`,
`apcontact`.`type` AS `ap-type`,
`apcontact`.`following` AS `ap-following`,
`apcontact`.`followers` AS `ap-followers`,
`apcontact`.`inbox` AS `ap-inbox`,
`apcontact`.`outbox` AS `ap-outbox`,
`apcontact`.`sharedinbox` AS `ap-sharedinbox`,
`apcontact`.`generator` AS `ap-generator`,
`apcontact`.`following_count` AS `ap-following_count`,
`apcontact`.`followers_count` AS `ap-followers_count`,
`apcontact`.`statuses_count` AS `ap-statuses_count`
FROM `contact`
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `contact`.`uri-id`
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = contact.`uri-id`
WHERE `contact`.`uid` = 0;
--
-- VIEW account-user-view
--
DROP VIEW IF EXISTS `account-user-view`;
CREATE VIEW `account-user-view` AS SELECT
`ucontact`.`id` AS `id`,
`contact`.`id` AS `pid`,
`ucontact`.`uid` AS `uid`,
`contact`.`url` AS `url`,
`contact`.`nurl` AS `nurl`,
`contact`.`uri-id` AS `uri-id`,
`contact`.`addr` AS `addr`,
`contact`.`alias` AS `alias`,
`contact`.`name` AS `name`,
`contact`.`nick` AS `nick`,
`contact`.`about` AS `about`,
`contact`.`keywords` AS `keywords`,
`contact`.`xmpp` AS `xmpp`,
`contact`.`avatar` AS `avatar`,
`contact`.`photo` AS `photo`,
`contact`.`thumb` AS `thumb`,
`contact`.`micro` AS `micro`,
`contact`.`header` AS `header`,
`contact`.`created` AS `created`,
`contact`.`updated` AS `updated`,
`ucontact`.`self` AS `self`,
`ucontact`.`remote_self` AS `remote_self`,
`ucontact`.`rel` AS `rel`,
`contact`.`network` AS `network`,
`ucontact`.`protocol` AS `protocol`,
`contact`.`location` AS `location`,
`contact`.`attag` AS `attag`,
`contact`.`pubkey` AS `pubkey`,
`contact`.`prvkey` AS `prvkey`,
`contact`.`subscribe` AS `subscribe`,
`contact`.`last-update` AS `last-update`,
`contact`.`success_update` AS `success_update`,
`contact`.`failure_update` AS `failure_update`,
`contact`.`failed` AS `failed`,
`contact`.`last-item` AS `last-item`,
`contact`.`last-discovery` AS `last-discovery`,
`contact`.`contact-type` AS `contact-type`,
`contact`.`manually-approve` AS `manually-approve`,
`contact`.`unsearchable` AS `unsearchable`,
`contact`.`sensitive` AS `sensitive`,
`contact`.`baseurl` AS `baseurl`,
`contact`.`gsid` AS `gsid`,
`contact`.`info` AS `info`,
`contact`.`bdyear` AS `bdyear`,
`contact`.`bd` AS `bd`,
`contact`.`poco` AS `poco`,
`contact`.`name-date` AS `name-date`,
`contact`.`uri-date` AS `uri-date`,
`contact`.`avatar-date` AS `avatar-date`,
`contact`.`term-date` AS `term-date`,
`contact`.`hidden` AS `global-ignored`,
`contact`.`blocked` AS `global-blocked`,
`ucontact`.`hidden` AS `hidden`,
`ucontact`.`archive` AS `archive`,
`ucontact`.`pending` AS `pending`,
`ucontact`.`deleted` AS `deleted`,
`ucontact`.`notify_new_posts` AS `notify_new_posts`,
`ucontact`.`fetch_further_information` AS `fetch_further_information`,
`ucontact`.`ffi_keyword_denylist` AS `ffi_keyword_denylist`,
`ucontact`.`rating` AS `rating`,
`ucontact`.`readonly` AS `readonly`,
`ucontact`.`blocked` AS `blocked`,
`ucontact`.`block_reason` AS `block_reason`,
`ucontact`.`subhub` AS `subhub`,
`ucontact`.`hub-verify` AS `hub-verify`,
`ucontact`.`reason` AS `reason`,
`ucontact`.`duplex` AS `dfrn-duplex`,
`ucontact`.`ret-aes` AS `dfrn-ret-aes`,
`ucontact`.`site-pubkey` AS `dfrn-site-pubkey`,
`ucontact`.`issued-id` AS `dfrn-issued-id`,
`ucontact`.`dfrn-id` AS `dfrn-id`,
`ucontact`.`aes_allow` AS `dfrn-aes_allow`,
`contact`.`request` AS `dfrn-request`,
`contact`.`notify` AS `dfrn-notify`,
`contact`.`poll` AS `dfrn-poll`,
`contact`.`confirm` AS `dfrn-confirm`,
`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`,
`apcontact`.`uuid` AS `ap-uuid`,
`apcontact`.`type` AS `ap-type`,
`apcontact`.`following` AS `ap-following`,
`apcontact`.`followers` AS `ap-followers`,
`apcontact`.`inbox` AS `ap-inbox`,
`apcontact`.`outbox` AS `ap-outbox`,
`apcontact`.`sharedinbox` AS `ap-sharedinbox`,
`apcontact`.`generator` AS `ap-generator`,
`apcontact`.`following_count` AS `ap-following_count`,
`apcontact`.`followers_count` AS `ap-followers_count`,
`apcontact`.`statuses_count` AS `ap-statuses_count`
FROM `contact` AS `ucontact`
INNER JOIN `contact` ON `contact`.`uri-id` = `ucontact`.`uri-id` AND `contact`.`uid` = 0
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `ucontact`.`uri-id`
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = `ucontact`.`uri-id` AND `fcontact`.`network` = 'dspr';
-- --
-- VIEW pending-view -- VIEW pending-view
-- --

View file

@ -53,6 +53,7 @@ Database Tables
| [post-category](help/database/db_post-category) | post relation to categories | | [post-category](help/database/db_post-category) | post relation to categories |
| [post-content](help/database/db_post-content) | Content for all posts | | [post-content](help/database/db_post-content) | Content for all posts |
| [post-delivery-data](help/database/db_post-delivery-data) | Delivery data for items | | [post-delivery-data](help/database/db_post-delivery-data) | Delivery data for items |
| [post-link](help/database/db_post-link) | Post related external links |
| [post-media](help/database/db_post-media) | Attached media | | [post-media](help/database/db_post-media) | Attached media |
| [post-tag](help/database/db_post-tag) | post relation to tags | | [post-tag](help/database/db_post-tag) | post relation to tags |
| [post-thread](help/database/db_post-thread) | Thread related data | | [post-thread](help/database/db_post-thread) | Thread related data |

View file

@ -9,6 +9,7 @@ Fields
| Field | Description | Type | Null | Key | Default | Extra | | Field | Description | Type | Null | Key | Default | Extra |
| ---------------- | ------------------------------------------------------------------- | -------------- | ---- | --- | ------------------- | ----- | | ---------------- | ------------------------------------------------------------------- | -------------- | ---- | --- | ------------------- | ----- |
| url | URL of the contact | varbinary(255) | NO | PRI | NULL | | | url | URL of the contact | varbinary(255) | NO | PRI | NULL | |
| uri-id | Id of the item-uri table entry that contains the apcontact url | int unsigned | YES | | NULL | |
| uuid | | varchar(255) | YES | | NULL | | | uuid | | varchar(255) | YES | | NULL | |
| type | | varchar(20) | NO | | NULL | | | type | | varchar(20) | NO | | NULL | |
| following | | varchar(255) | YES | | NULL | | | following | | varchar(255) | YES | | NULL | |
@ -47,12 +48,14 @@ Indexes
| baseurl | baseurl(190) | | baseurl | baseurl(190) |
| sharedinbox | sharedinbox(190) | | sharedinbox | sharedinbox(190) |
| gsid | gsid | | gsid | gsid |
| uri-id | UNIQUE, uri-id |
Foreign Keys Foreign Keys
------------ ------------
| Field | Target Table | Target Field | | Field | Target Table | Target Field |
|-------|--------------|--------------| |-------|--------------|--------------|
| uri-id | [item-uri](help/database/db_item-uri) | id |
| gsid | [gserver](help/database/db_gserver) | id | | gsid | [gserver](help/database/db_gserver) | id |
Return to [database documentation](help/database) Return to [database documentation](help/database)

View file

@ -7,7 +7,7 @@ Fields
------ ------
| Field | Description | Type | Null | Key | Default | Extra | | Field | Description | Type | Null | Key | Default | Extra |
| ------------------------- | --------------------------------------------------------- | ------------------ | ---- | --- | ------------------- | -------------- | | ------------------------- | ------------------------------------------------------------ | ------------------ | ---- | --- | ------------------- | -------------- |
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | | id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
| uid | Owner User id | mediumint unsigned | NO | | 0 | | | uid | Owner User id | mediumint unsigned | NO | | 0 | |
| created | | datetime | NO | | 0001-01-01 00:00:00 | | | created | | datetime | NO | | 0001-01-01 00:00:00 | |
@ -36,6 +36,7 @@ Fields
| dfrn-id | | varchar(255) | NO | | | | | dfrn-id | | varchar(255) | NO | | | |
| url | | varchar(255) | NO | | | | | url | | varchar(255) | NO | | | |
| nurl | | 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 | | | | | addr | | varchar(255) | NO | | | |
| alias | | varchar(255) | NO | | | | | alias | | varchar(255) | NO | | | |
| pubkey | RSA public key 4096 bit | text | YES | | NULL | | | pubkey | RSA public key 4096 bit | text | YES | | NULL | |
@ -118,6 +119,7 @@ Indexes
| uid_self_contact-type | uid, self, contact-type | | uid_self_contact-type | uid, self, contact-type |
| self_network_uid | self, network, uid | | self_network_uid | self, network, uid |
| gsid | gsid | | gsid | gsid |
| uri-id | uri-id |
Foreign Keys Foreign Keys
------------ ------------
@ -125,6 +127,7 @@ Foreign Keys
| Field | Target Table | Target Field | | Field | Target Table | Target Field |
|-------|--------------|--------------| |-------|--------------|--------------|
| uid | [user](help/database/db_user) | uid | | uid | [user](help/database/db_user) | uid |
| uri-id | [item-uri](help/database/db_item-uri) | id |
| gsid | [gserver](help/database/db_gserver) | id | | gsid | [gserver](help/database/db_gserver) | id |
Return to [database documentation](help/database) Return to [database documentation](help/database)

View file

@ -7,12 +7,13 @@ Fields
------ ------
| Field | Description | Type | Null | Key | Default | Extra | | Field | Description | Type | Null | Key | Default | Extra |
| --------- | ------------------------------------------------------ | ------------------ | ---- | --- | ------------------- | -------------- | | --------- | ---------------------------------------------------------- | ------------------ | ---- | --- | ------------------- | -------------- |
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | | id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
| guid | | varchar(255) | NO | | | | | guid | | varchar(255) | NO | | | |
| uid | Owner User id | mediumint unsigned | NO | | 0 | | | uid | Owner User id | mediumint unsigned | NO | | 0 | |
| cid | contact_id (ID of the contact in contact table) | int unsigned | NO | | 0 | | | cid | contact_id (ID of the contact in contact table) | int unsigned | NO | | 0 | |
| uri | | varchar(255) | NO | | | | | uri | | varchar(255) | NO | | | |
| uri-id | Id of the item-uri table entry that contains the event uri | int unsigned | YES | | NULL | |
| created | creation time | datetime | NO | | 0001-01-01 00:00:00 | | | created | creation time | datetime | NO | | 0001-01-01 00:00:00 | |
| edited | last edit time | datetime | NO | | 0001-01-01 00:00:00 | | | edited | last edit time | datetime | NO | | 0001-01-01 00:00:00 | |
| start | event start time | datetime | NO | | 0001-01-01 00:00:00 | | | start | event start time | datetime | NO | | 0001-01-01 00:00:00 | |
@ -37,6 +38,7 @@ Indexes
| PRIMARY | id | | PRIMARY | id |
| uid_start | uid, start | | uid_start | uid, start |
| cid | cid | | cid | cid |
| uri-id | uri-id |
Foreign Keys Foreign Keys
------------ ------------
@ -45,5 +47,6 @@ Foreign Keys
|-------|--------------|--------------| |-------|--------------|--------------|
| uid | [user](help/database/db_user) | uid | | uid | [user](help/database/db_user) | uid |
| cid | [contact](help/database/db_contact) | id | | cid | [contact](help/database/db_contact) | id |
| uri-id | [item-uri](help/database/db_item-uri) | id |
Return to [database documentation](help/database) Return to [database documentation](help/database)

View file

@ -7,10 +7,11 @@ Fields
------ ------
| Field | Description | Type | Null | Key | Default | Extra | | Field | Description | Type | Null | Key | Default | Extra |
| -------- | ------------- | ---------------- | ---- | --- | ------------------- | -------------- | | -------- | ------------------------------------------------------------- | ---------------- | ---- | --- | ------------------- | -------------- |
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | | id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
| guid | unique id | varchar(255) | NO | | | | | guid | unique id | varchar(255) | NO | | | |
| url | | varchar(255) | NO | | | | | url | | varchar(255) | NO | | | |
| uri-id | Id of the item-uri table entry that contains the fcontact url | int unsigned | YES | | NULL | |
| name | | varchar(255) | NO | | | | | name | | varchar(255) | NO | | | |
| photo | | varchar(255) | NO | | | | | photo | | varchar(255) | NO | | | |
| request | | varchar(255) | NO | | | | | request | | varchar(255) | NO | | | |
@ -34,6 +35,13 @@ Indexes
| PRIMARY | id | | PRIMARY | id |
| addr | addr(32) | | addr | addr(32) |
| url | UNIQUE, url(190) | | 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) Return to [database documentation](help/database)

View file

@ -0,0 +1,31 @@
Table post-link
===========
Post related external links
Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| -------- | --------------------------------------------------------- | -------------- | ---- | --- | ------- | -------------- |
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
| uri-id | Id of the item-uri table entry that contains the item uri | int unsigned | NO | | NULL | |
| url | External URL | varbinary(511) | NO | | NULL | |
| mimetype | | varchar(60) | YES | | NULL | |
Indexes
------------
| Name | Fields |
| ---------- | ------------------- |
| PRIMARY | id |
| uri-id-url | UNIQUE, uri-id, url |
Foreign Keys
------------
| Field | Target Table | Target Field |
|-------|--------------|--------------|
| uri-id | [item-uri](help/database/db_item-uri) | id |
Return to [database documentation](help/database)

View file

@ -36,7 +36,7 @@ Indexes
------------ ------------
| Name | Fields | | Name | Fields |
| ------------- | -------------- | | ----------------- | ------------------- |
| PRIMARY | uid, uri-id | | PRIMARY | uid, uri-id |
| uri-id | uri-id | | uri-id | uri-id |
| owner-id | owner-id | | owner-id | owner-id |
@ -48,6 +48,7 @@ Indexes
| post-user-id | post-user-id | | post-user-id | post-user-id |
| commented | commented | | commented | commented |
| uid_received | uid, received | | uid_received | uid, received |
| uid_wall_received | uid, wall, received |
| uid_pinned | uid, pinned | | uid_pinned | uid, pinned |
| uid_commented | uid, commented | | uid_commented | uid, commented |
| uid_starred | uid, starred | | uid_starred | uid, starred |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

View file

@ -64,7 +64,6 @@ use Friendica\Security\OAuth1\OAuthUtil;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Images; use Friendica\Util\Images;
use Friendica\Util\Network; use Friendica\Util\Network;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Friendica\Util\XML; use Friendica\Util\XML;
@ -2526,12 +2525,12 @@ function api_format_messages($item, $recipient, $sender)
if (!empty($_GET['getText'])) { if (!empty($_GET['getText'])) {
$ret['title'] = $item['title']; $ret['title'] = $item['title'];
if ($_GET['getText'] == 'html') { if ($_GET['getText'] == 'html') {
$ret['text'] = BBCode::convert($item['body'], false); $ret['text'] = BBCode::convertForUriId($item['uri-id'], $item['body'], BBCode::API);
} elseif ($_GET['getText'] == 'plain') { } elseif ($_GET['getText'] == 'plain') {
$ret['text'] = trim(HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, BBCode::API, true), 0)); $ret['text'] = trim(HTML::toPlaintext(BBCode::convertForUriId($item['uri-id'], api_clean_plain_items($item['body']), BBCode::API), 0));
} }
} else { } else {
$ret['text'] = $item['title'] . "\n" . HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, BBCode::API, true), 0); $ret['text'] = $item['title'] . "\n" . HTML::toPlaintext(BBCode::convertForUriId($item['uri-id'], api_clean_plain_items($item['body']), BBCode::API), 0);
} }
if (!empty($_GET['getUserObjects']) && $_GET['getUserObjects'] == 'false') { if (!empty($_GET['getUserObjects']) && $_GET['getUserObjects'] == 'false') {
unset($ret['sender']); unset($ret['sender']);
@ -2552,13 +2551,13 @@ function api_convert_item($item)
{ {
$body = api_add_attachments_to_body($item); $body = api_add_attachments_to_body($item);
$entities = api_get_entitities($statustext, $body); $entities = api_get_entitities($statustext, $body, $item['uri-id']);
// Add pictures to the attachment array and remove them from the body // Add pictures to the attachment array and remove them from the body
$attachments = api_get_attachments($body); $attachments = api_get_attachments($body, $item['uri-id']);
// Workaround for ostatus messages where the title is identically to the body // Workaround for ostatus messages where the title is identically to the body
$html = BBCode::convert(api_clean_plain_items($body), false, BBCode::API, true); $html = BBCode::convertForUriId($item['uri-id'], api_clean_plain_items($body), BBCode::API);
$statusbody = trim(HTML::toPlaintext($html, 0)); $statusbody = trim(HTML::toPlaintext($html, 0));
// handle data: images // handle data: images
@ -2576,7 +2575,7 @@ function api_convert_item($item)
$statustext = mb_substr($statustext, 0, 1000) . "... \n" . ($item['plink'] ?? ''); $statustext = mb_substr($statustext, 0, 1000) . "... \n" . ($item['plink'] ?? '');
} }
$statushtml = BBCode::convert(BBCode::removeAttachment($body), false, BBCode::API, true); $statushtml = BBCode::convertForUriId($item['uri-id'], BBCode::removeAttachment($body), BBCode::API);
// Workaround for clients with limited HTML parser functionality // Workaround for clients with limited HTML parser functionality
$search = ["<br>", "<blockquote>", "</blockquote>", $search = ["<br>", "<blockquote>", "</blockquote>",
@ -2590,7 +2589,7 @@ function api_convert_item($item)
$statushtml = str_replace($search, $replace, $statushtml); $statushtml = str_replace($search, $replace, $statushtml);
if ($item['title'] != "") { if ($item['title'] != "") {
$statushtml = "<br><h4>" . BBCode::convert($item['title']) . "</h4><br>" . $statushtml; $statushtml = "<br><h4>" . BBCode::convertForUriId($item['uri-id'], $item['title']) . "</h4><br>" . $statushtml;
} }
do { do {
@ -2608,7 +2607,7 @@ function api_convert_item($item)
// feeds without body should contain the link // feeds without body should contain the link
if ((($item['network'] ?? Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) { if ((($item['network'] ?? Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) {
$statushtml .= BBCode::convert($item['plink']); $statushtml .= BBCode::convertForUriId($item['uri-id'], $item['plink']);
} }
return [ return [
@ -2650,11 +2649,12 @@ function api_add_attachments_to_body(array $item)
/** /**
* *
* @param string $body * @param string $body
* @param int $uriid
* *
* @return array * @return array
* @throws InternalServerErrorException * @throws InternalServerErrorException
*/ */
function api_get_attachments(&$body) function api_get_attachments(&$body, $uriid)
{ {
$body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
$body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body); $body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body);
@ -2675,11 +2675,7 @@ function api_get_attachments(&$body)
$imagedata = Images::getInfoFromURLCached($image); $imagedata = Images::getInfoFromURLCached($image);
if ($imagedata) { if ($imagedata) {
if (DI::config()->get("system", "proxy_disabled")) { $attachments[] = ["url" => Post\Link::getByLink($uriid, $image), "mimetype" => $imagedata["mime"], "size" => $imagedata["size"]];
$attachments[] = ["url" => $image, "mimetype" => $imagedata["mime"], "size" => $imagedata["size"]];
} else {
$attachments[] = ["url" => ProxyUtils::proxifyUrl($image, false), "mimetype" => $imagedata["mime"], "size" => $imagedata["size"]];
}
} }
} }
@ -2695,7 +2691,7 @@ function api_get_attachments(&$body)
* @throws InternalServerErrorException * @throws InternalServerErrorException
* @todo Links at the first character of the post * @todo Links at the first character of the post
*/ */
function api_get_entitities(&$text, $bbcode) function api_get_entitities(&$text, $bbcode, $uriid)
{ {
$include_entities = strtolower($_REQUEST['include_entities'] ?? 'false'); $include_entities = strtolower($_REQUEST['include_entities'] ?? 'false');
@ -2703,7 +2699,7 @@ function api_get_entitities(&$text, $bbcode)
preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images); preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images);
foreach ($images[1] as $image) { foreach ($images[1] as $image) {
$replace = ProxyUtils::proxifyUrl($image, false); $replace = Post\Link::getByLink($uriid, $image);
$text = str_replace($image, $replace, $text); $text = str_replace($image, $replace, $text);
} }
return []; return [];
@ -2815,31 +2811,8 @@ function api_get_entitities(&$text, $bbcode)
if (!($start === false)) { if (!($start === false)) {
$image = Images::getInfoFromURLCached($url); $image = Images::getInfoFromURLCached($url);
if ($image) { if ($image) {
// If image cache is activated, then use the following sizes: $media_url = Post\Link::getByLink($uriid, $url);
// thumb (150), small (340), medium (600) and large (1024)
if (!DI::config()->get("system", "proxy_disabled")) {
$media_url = ProxyUtils::proxifyUrl($url, false);
$sizes = [];
$scale = Images::getScalingDimensions($image[0], $image[1], 150);
$sizes["thumb"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
if (($image[0] > 150) || ($image[1] > 150)) {
$scale = Images::getScalingDimensions($image[0], $image[1], 340);
$sizes["small"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
}
$scale = Images::getScalingDimensions($image[0], $image[1], 600);
$sizes["medium"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
if (($image[0] > 600) || ($image[1] > 600)) {
$scale = Images::getScalingDimensions($image[0], $image[1], 1024);
$sizes["large"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"];
}
} else {
$media_url = $url;
$sizes["medium"] = ["w" => $image[0], "h" => $image[1], "resize" => "fit"]; $sizes["medium"] = ["w" => $image[0], "h" => $image[1], "resize" => "fit"];
}
$entities["media"][] = [ $entities["media"][] = [
"id" => $start+1, "id" => $start+1,
@ -3081,7 +3054,7 @@ function api_format_item($item, $type = "json", $status_user = null, $author_use
'external_url' => DI::baseUrl() . "/display/" . $item['guid'], 'external_url' => DI::baseUrl() . "/display/" . $item['guid'],
'friendica_activities' => api_format_items_activities($item, $type), 'friendica_activities' => api_format_items_activities($item, $type),
'friendica_title' => $item['title'], 'friendica_title' => $item['title'],
'friendica_html' => BBCode::convert($item['body'], false) 'friendica_html' => BBCode::convertForUriId($item['uri-id'], $item['body'], BBCode::EXTERNAL)
]; ];
if (count($converted["attachments"]) > 0) { if (count($converted["attachments"]) > 0) {

View file

@ -47,91 +47,6 @@ use Friendica\Util\Strings;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
use Friendica\Util\XML; use Friendica\Util\XML;
function item_extract_images($body) {
$saved_image = [];
$orig_body = $body;
$new_body = '';
$cnt = 0;
$img_start = strpos($orig_body, '[img');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
$img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
while (($img_st_close !== false) && ($img_end !== false)) {
$img_st_close++; // make it point to AFTER the closing bracket
$img_end += $img_start;
if (!strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) {
// This is an embedded image
$saved_image[$cnt] = substr($orig_body, $img_start + $img_st_close, $img_end - ($img_start + $img_st_close));
$new_body = $new_body . substr($orig_body, 0, $img_start) . '[!#saved_image' . $cnt . '#!]';
$cnt++;
} else {
$new_body = $new_body . substr($orig_body, 0, $img_end + strlen('[/img]'));
}
$orig_body = substr($orig_body, $img_end + strlen('[/img]'));
if ($orig_body === false) {
// in case the body ends on a closing image tag
$orig_body = '';
}
$img_start = strpos($orig_body, '[img');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
$img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
}
$new_body = $new_body . $orig_body;
return ['body' => $new_body, 'images' => $saved_image];
}
function item_redir_and_replace_images($body, $images, $cid) {
$origbody = $body;
$newbody = '';
$cnt = 1;
$pos = BBCode::getTagPosition($origbody, 'url', 0);
while ($pos !== false && $cnt < 1000) {
$search = '/\[url\=(.*?)\]\[!#saved_image([0-9]*)#!\]\[\/url\]' . '/is';
$replace = '[url=' . DI::baseUrl() . '/redir/' . $cid
. '?url=' . '$1' . '][!#saved_image' . '$2' .'#!][/url]';
$newbody .= substr($origbody, 0, $pos['start']['open']);
$subject = substr($origbody, $pos['start']['open'], $pos['end']['close'] - $pos['start']['open']);
$origbody = substr($origbody, $pos['end']['close']);
if ($origbody === false) {
$origbody = '';
}
$subject = preg_replace($search, $replace, $subject);
$newbody .= $subject;
$cnt++;
// Isn't this supposed to use $cnt value for $occurrences? - @MrPetovan
$pos = BBCode::getTagPosition($origbody, 'url', 0);
}
$newbody .= $origbody;
$cnt = 0;
foreach ($images as $image) {
/*
* We're depending on the property of 'foreach' (specified on the PHP website) that
* it loops over the array starting from the first element and going sequentially
* to the last element.
*/
$newbody = str_replace('[!#saved_image' . $cnt . '#!]', '[img]' . $image . '[/img]', $newbody);
$cnt++;
}
return $newbody;
}
/** /**
* Render actions localized * Render actions localized
* *
@ -141,11 +56,6 @@ function item_redir_and_replace_images($body, $images, $cid) {
*/ */
function localize_item(&$item) function localize_item(&$item)
{ {
$extracted = item_extract_images($item['body']);
if ($extracted['images']) {
$item['body'] = item_redir_and_replace_images($extracted['body'], $extracted['images'], $item['contact-id']);
}
/// @todo The following functionality needs to be cleaned up. /// @todo The following functionality needs to be cleaned up.
if (!empty($item['verb'])) { if (!empty($item['verb'])) {
$activity = DI::activity(); $activity = DI::activity();
@ -260,13 +170,6 @@ function localize_item(&$item)
} }
} }
// add zrl's to public images
$photo_pattern = "/\[url=(.*?)\/photos\/(.*?)\/image\/(.*?)\]\[img(.*?)\]h(.*?)\[\/img\]\[\/url\]/is";
if (preg_match($photo_pattern, $item['body'])) {
$photo_replace = '[url=' . Profile::zrl('$1' . '/photos/' . '$2' . '/image/' . '$3' , true) . '][img' . '$4' . ']h' . '$5' . '[/img][/url]';
$item['body'] = BBCode::pregReplaceInTag($photo_pattern, $photo_replace, 'url', $item['body']);
}
// add sparkle links to appropriate permalinks // add sparkle links to appropriate permalinks
// Only create a redirection to a magic link when logged in // Only create a redirection to a magic link when logged in
if (!empty($item['plink']) && Session::isAuthenticated()) { if (!empty($item['plink']) && Session::isAuthenticated()) {

View file

@ -474,7 +474,7 @@ function notification($params)
if ($show_in_notification_page) { if ($show_in_notification_page) {
$fields = [ $fields = [
'name' => $params['source_name'] ?? '', 'name' => $params['source_name'] ?? '',
'name_cache' => substr(strip_tags(BBCode::convert($params['source_name'])), 0, 255), 'name_cache' => substr(strip_tags(BBCode::convertForUriId($uri_id, $params['source_name'])), 0, 255),
'url' => $params['source_link'] ?? '', 'url' => $params['source_link'] ?? '',
'photo' => $params['source_photo'] ?? '', 'photo' => $params['source_photo'] ?? '',
'link' => $itemlink ?? '', 'link' => $itemlink ?? '',

View file

@ -334,8 +334,8 @@ function display_content(App $a, $update = false, $update_uid = 0)
$o .= conversation($a, [$item], 'display', $update_uid, false, 'commented', $item_uid); $o .= conversation($a, [$item], 'display', $update_uid, false, 'commented', $item_uid);
// Preparing the meta header // Preparing the meta header
$description = trim(HTML::toPlaintext(BBCode::convert($item["body"], false), 0, true)); $description = trim(BBCode::toPlaintext($item["body"]));
$title = trim(HTML::toPlaintext(BBCode::convert($item["title"], false), 0, true)); $title = trim(BBCode::toPlaintext($item["title"]));
$author_name = $item["author-name"]; $author_name = $item["author-name"];
$image = DI::baseUrl()->remove($item["author-avatar"]); $image = DI::baseUrl()->remove($item["author-avatar"]);

View file

@ -314,18 +314,13 @@ function message_content(App $a)
$sparkle = ' sparkle'; $sparkle = ' sparkle';
} }
$extracted = item_extract_images($message['body']);
if ($extracted['images']) {
$message['body'] = item_redir_and_replace_images($extracted['body'], $extracted['images'], $message['contact-id']);
}
$from_name_e = $message['from-name']; $from_name_e = $message['from-name'];
$subject_e = $message['title']; $subject_e = $message['title'];
$body_e = BBCode::convert($message['body']); $body_e = BBCode::convertForUriId($message['uri-id'], $message['body']);
$to_name_e = $message['name']; $to_name_e = $message['name'];
$contact = Contact::getByURL($message['from-url'], false, ['thumb', 'addr', 'id', 'avatar']); $contact = Contact::getByURL($message['from-url'], false, ['thumb', 'addr', 'id', 'avatar']);
$from_photo = Contact::getThumb($contact, $message['from-photo']); $from_photo = Contact::getThumb($contact);
$mails[] = [ $mails[] = [
'id' => $message['id'], 'id' => $message['id'],
@ -457,7 +452,7 @@ function render_messages(array $msg, $t)
} }
$contact = Contact::getByURL($rr['url'], false, ['thumb', 'addr', 'id', 'avatar']); $contact = Contact::getByURL($rr['url'], false, ['thumb', 'addr', 'id', 'avatar']);
$from_photo = Contact::getThumb($contact, $rr['thumb'] ?: $rr['from-photo']); $from_photo = Contact::getThumb($contact);
$rslt .= Renderer::replaceMacros($tpl, [ $rslt .= Renderer::replaceMacros($tpl, [
'$id' => $rr['id'], '$id' => $rr['id'],

View file

@ -37,6 +37,7 @@ use Friendica\DI;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Event; use Friendica\Model\Event;
use Friendica\Model\Photo; use Friendica\Model\Photo;
use Friendica\Model\Post;
use Friendica\Model\Tag; use Friendica\Model\Tag;
use Friendica\Object\Image; use Friendica\Object\Image;
use Friendica\Protocol\Activity; use Friendica\Protocol\Activity;
@ -251,7 +252,7 @@ class BBCode
$post = self::getAttachmentData($body); $post = self::getAttachmentData($body);
// Get all linked images with alternative image description // Get all linked images with alternative image description
if (preg_match_all("/\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { if (preg_match_all("/\[img=(http[^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) {
foreach ($pictures as $picture) { foreach ($pictures as $picture) {
if (Photo::isLocal($picture[1])) { if (Photo::isLocal($picture[1])) {
$post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2]]; $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2]];
@ -433,18 +434,27 @@ class BBCode
*/ */
public static function toPlaintext($text, $keep_urls = true) public static function toPlaintext($text, $keep_urls = true)
{ {
// Remove pictures in advance to avoid unneeded proxy calls
$text = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", ' $2 ', $text);
$text = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $text);
// Remove attachment
$text = self::removeAttachment($text);
$naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls); $naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls);
return $naked_text; return $naked_text;
} }
private static function proxyUrl($image, $simplehtml = self::INTERNAL) private static function proxyUrl($image, $simplehtml = self::INTERNAL, $uriid = 0, $size = '')
{ {
// Only send proxied pictures to API and for internal display // Only send proxied pictures to API and for internal display
if (in_array($simplehtml, [self::INTERNAL, self::API])) { if (!in_array($simplehtml, [self::INTERNAL, self::API])) {
return ProxyUtils::proxifyUrl($image);
} else {
return $image; return $image;
} elseif ($uriid) {
return Post\Link::getByLink($uriid, $image, $size);
} else {
return ProxyUtils::proxifyUrl($image, $size);
} }
} }
@ -608,10 +618,11 @@ class BBCode
* @param integer $simplehtml * @param integer $simplehtml
* @param bool $tryoembed * @param bool $tryoembed
* @param array $data * @param array $data
* @param int $uriid
* @return string * @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function convertAttachment($text, $simplehtml = self::INTERNAL, $tryoembed = true, array $data = []) public static function convertAttachment($text, $simplehtml = self::INTERNAL, $tryoembed = true, array $data = [], $uriid = 0)
{ {
$data = $data ?: self::getAttachmentData($text); $data = $data ?: self::getAttachmentData($text);
if (empty($data) || empty($data['url'])) { if (empty($data) || empty($data['url'])) {
@ -648,12 +659,12 @@ class BBCode
if (!empty($data['title']) && !empty($data['url'])) { if (!empty($data['title']) && !empty($data['url'])) {
if (!empty($data['image']) && empty($data['text']) && ($data['type'] == 'photo')) { if (!empty($data['image']) && empty($data['text']) && ($data['type'] == 'photo')) {
$return .= sprintf('<a href="%s" target="_blank" rel="noopener noreferrer"><img src="%s" alt="" title="%s" class="attachment-image" /></a>', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']); $return .= sprintf('<a href="%s" target="_blank" rel="noopener noreferrer"><img src="%s" alt="" title="%s" class="attachment-image" /></a>', $data['url'], self::proxyUrl($data['image'], $simplehtml, $uriid), $data['title']);
} else { } else {
if (!empty($data['image'])) { if (!empty($data['image'])) {
$return .= sprintf('<a href="%s" target="_blank" rel="noopener noreferrer"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br>', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']); $return .= sprintf('<a href="%s" target="_blank" rel="noopener noreferrer"><img src="%s" alt="" title="%s" class="attachment-image" /></a><br>', $data['url'], self::proxyUrl($data['image'], $simplehtml, $uriid), $data['title']);
} elseif (!empty($data['preview'])) { } elseif (!empty($data['preview'])) {
$return .= sprintf('<a href="%s" target="_blank" rel="noopener noreferrer"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br>', $data['url'], self::proxyUrl($data['preview'], $simplehtml), $data['title']); $return .= sprintf('<a href="%s" target="_blank" rel="noopener noreferrer"><img src="%s" alt="" title="%s" class="attachment-preview" /></a><br>', $data['url'], self::proxyUrl($data['preview'], $simplehtml, $uriid), $data['title']);
} }
$return .= sprintf('<h4><a href="%s">%s</a></h4>', $data['url'], $data['title']); $return .= sprintf('<h4><a href="%s">%s</a></h4>', $data['url'], $data['title']);
} }
@ -929,7 +940,7 @@ class BBCode
return ['body' => $new_body, 'images' => $saved_image]; return ['body' => $new_body, 'images' => $saved_image];
} }
private static function interpolateSavedImagesIntoItemBody($body, array $images) private static function interpolateSavedImagesIntoItemBody($uriid, $body, array $images)
{ {
$newbody = $body; $newbody = $body;
@ -939,7 +950,7 @@ class BBCode
// it loops over the array starting from the first element and going sequentially // it loops over the array starting from the first element and going sequentially
// to the last element // to the last element
$newbody = str_replace('[$#saved_image' . $cnt . '#$]', $newbody = str_replace('[$#saved_image' . $cnt . '#$]',
'<img src="' . self::proxyUrl($image) . '" alt="' . DI::l10n()->t('Image/photo') . '" />', $newbody); '<img src="' . self::proxyUrl($image, self::INTERNAL, $uriid) . '" alt="' . DI::l10n()->t('Image/photo') . '" />', $newbody);
$cnt++; $cnt++;
} }
@ -989,11 +1000,11 @@ class BBCode
* @param callable $callback * @param callable $callback
* @return string The BBCode string with all [share] blocks replaced * @return string The BBCode string with all [share] blocks replaced
*/ */
public static function convertShare($text, callable $callback) public static function convertShare($text, callable $callback, int $uriid = 0)
{ {
$return = preg_replace_callback( $return = preg_replace_callback(
"/(.*?)\[share(.*?)\](.*)\[\/share\]/ism", "/(.*?)\[share(.*?)\](.*)\[\/share\]/ism",
function ($match) use ($callback) { function ($match) use ($callback, $uriid) {
$attribute_string = $match[2]; $attribute_string = $match[2];
$attributes = []; $attributes = [];
foreach (['author', 'profile', 'avatar', 'link', 'posted', 'guid'] as $field) { foreach (['author', 'profile', 'avatar', 'link', 'posted', 'guid'] as $field) {
@ -1012,7 +1023,7 @@ class BBCode
if (!empty($author_contact['id'])) { if (!empty($author_contact['id'])) {
$attributes['avatar'] = Contact::getAvatarUrlForId($author_contact['id'], ProxyUtils::SIZE_THUMB); $attributes['avatar'] = Contact::getAvatarUrlForId($author_contact['id'], ProxyUtils::SIZE_THUMB);
} elseif ($attributes['avatar']) { } elseif ($attributes['avatar']) {
$attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], false, ProxyUtils::SIZE_THUMB); $attributes['avatar'] = self::proxyUrl($attributes['avatar'], self::INTERNAL, $uriid, ProxyUtils::SIZE_THUMB);
} }
$content = preg_replace(Strings::autoLinkRegEx(), '<a href="$1">$1</a>', $match[3]); $content = preg_replace(Strings::autoLinkRegEx(), '<a href="$1">$1</a>', $match[3]);
@ -1252,6 +1263,37 @@ class BBCode
return $bbcode; return $bbcode;
} }
/**
* Converts a BBCode message for a given URI-ID to a HTML message
*
* BBcode 2 HTML was written by WAY2WEB.net
* extended to work with Mistpark/Friendica - Mike Macgirvin
*
* Simple HTML values meaning:
* - 0: Friendica display
* - 1: Unused
* - 2: Used for Windows Phone push, Friendica API
* - 3: Used before converting to Markdown in bb2diaspora.php
* - 4: Used for WordPress, Libertree (before Markdown), pump.io and tumblr
* - 5: Unused
* - 6: Unused
* - 7: Used for dfrn, OStatus
* - 8: Used for Twitter, WP backlink text setting
* - 9: ActivityPub
*
* @param int $uriid
* @param string $text
* @param int $simple_html
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public static function convertForUriId(int $uriid = 0, string $text = null, int $simple_html = self::INTERNAL)
{
$try_oembed = ($simple_html == self::INTERNAL);
return self::convert($text, $try_oembed, $simple_html, false, $uriid);
}
/** /**
* Converts a BBCode message to HTML message * Converts a BBCode message to HTML message
* *
@ -1274,10 +1316,11 @@ class BBCode
* @param bool $try_oembed * @param bool $try_oembed
* @param int $simple_html * @param int $simple_html
* @param bool $for_plaintext * @param bool $for_plaintext
* @param int $uriid
* @return string * @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function convert(string $text = null, $try_oembed = true, $simple_html = self::INTERNAL, $for_plaintext = false) public static function convert(string $text = null, $try_oembed = true, $simple_html = self::INTERNAL, $for_plaintext = false, $uriid = 0)
{ {
// Accounting for null default column values // Accounting for null default column values
if (is_null($text) || $text === '') { if (is_null($text) || $text === '') {
@ -1288,8 +1331,8 @@ class BBCode
$a = DI::app(); $a = DI::app();
$text = self::performWithEscapedTags($text, ['code'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $a) { $text = self::performWithEscapedTags($text, ['code'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $a, $uriid) {
$text = self::performWithEscapedTags($text, ['noparse', 'nobb', 'pre'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $a) { $text = self::performWithEscapedTags($text, ['noparse', 'nobb', 'pre'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $a, $uriid) {
/* /*
* preg_match_callback function to replace potential Oembed tags with Oembed content * preg_match_callback function to replace potential Oembed tags with Oembed content
* *
@ -1398,7 +1441,7 @@ class BBCode
} elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) { } elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) {
$text = self::removeAttachment($text, true); $text = self::removeAttachment($text, true);
} else { } else {
$text = self::convertAttachment($text, $simple_html, $try_oembed); $text = self::convertAttachment($text, $simple_html, $try_oembed, [], $uriid);
} }
$nosmile = strpos($text, '[nosmile]') !== false; $nosmile = strpos($text, '[nosmile]') !== false;
@ -1573,12 +1616,12 @@ class BBCode
// [img=widthxheight]image source[/img] // [img=widthxheight]image source[/img]
$text = preg_replace_callback( $text = preg_replace_callback(
"/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", "/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism",
function ($matches) use ($simple_html) { function ($matches) use ($simple_html, $uriid) {
if (strpos($matches[3], "data:image/") === 0) { if (strpos($matches[3], "data:image/") === 0) {
return $matches[0]; return $matches[0];
} }
$matches[3] = self::proxyUrl($matches[3], $simple_html); $matches[3] = self::proxyUrl($matches[3], $simple_html, $uriid);
return "[img=" . $matches[1] . "x" . $matches[2] . "]" . $matches[3] . "[/img]"; return "[img=" . $matches[1] . "x" . $matches[2] . "]" . $matches[3] . "[/img]";
}, },
$text $text
@ -1588,8 +1631,8 @@ class BBCode
$text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: $1px;" >', $text); $text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '<img class="zrl" src="$3" style="width: $1px;" >', $text);
$text = preg_replace_callback("/\[img\=(.*?)\](.*?)\[\/img\]/ism", $text = preg_replace_callback("/\[img\=(.*?)\](.*?)\[\/img\]/ism",
function ($matches) use ($simple_html) { function ($matches) use ($simple_html, $uriid) {
$matches[1] = self::proxyUrl($matches[1], $simple_html); $matches[1] = self::proxyUrl($matches[1], $simple_html, $uriid);
$matches[2] = htmlspecialchars($matches[2], ENT_COMPAT); $matches[2] = htmlspecialchars($matches[2], ENT_COMPAT);
return '<img src="' . $matches[1] . '" alt="' . $matches[2] . '" title="' . $matches[2] . '">'; return '<img src="' . $matches[1] . '" alt="' . $matches[2] . '" title="' . $matches[2] . '">';
}, },
@ -1599,12 +1642,12 @@ class BBCode
// [img]pathtoimage[/img] // [img]pathtoimage[/img]
$text = preg_replace_callback( $text = preg_replace_callback(
"/\[img\](.*?)\[\/img\]/ism", "/\[img\](.*?)\[\/img\]/ism",
function ($matches) use ($simple_html) { function ($matches) use ($simple_html, $uriid) {
if (strpos($matches[1], "data:image/") === 0) { if (strpos($matches[1], "data:image/") === 0) {
return $matches[0]; return $matches[0];
} }
$matches[1] = self::proxyUrl($matches[1], $simple_html); $matches[1] = self::proxyUrl($matches[1], $simple_html, $uriid);
return "[img]" . $matches[1] . "[/img]"; return "[img]" . $matches[1] . "[/img]";
}, },
$text $text
@ -1686,7 +1729,7 @@ class BBCode
// start which is always required). Allow desc with a missing summary for compatibility. // start which is always required). Allow desc with a missing summary for compatibility.
if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) { if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
$sub = Event::getHTML($ev, $simple_html); $sub = Event::getHTML($ev, $simple_html, $uriid);
$text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text); $text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text);
$text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text); $text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text);
@ -1849,10 +1892,10 @@ class BBCode
$text, $text,
function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) { function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) {
return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html); return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html);
} }, $uriid
); );
$text = self::interpolateSavedImagesIntoItemBody($text, $saved_image); $text = self::interpolateSavedImagesIntoItemBody($uriid, $text, $saved_image);
return $text; return $text;
}); // Escaped noparse, nobb, pre }); // Escaped noparse, nobb, pre

View file

@ -329,8 +329,6 @@ class System
function info($s) function info($s)
function is_site_admin() function is_site_admin()
function get_temppath() function get_temppath()
function get_cachefile($file, $writemode = true)
function get_itemcachepath()
function get_spoolpath() function get_spoolpath()
*/ */
} }

View file

@ -91,6 +91,18 @@ class PostUpdate
if (!self::update1400()) { if (!self::update1400()) {
return false; return false;
} }
if (!self::update1424()) {
return false;
}
if (!self::update1425()) {
return false;
}
if (!self::update1426()) {
return false;
}
if (!self::update1427()) {
return false;
}
return true; return true;
} }
@ -740,7 +752,7 @@ class PostUpdate
Logger::info('Start', ['rest' => DBA::count('photo', $condition)]); Logger::info('Start', ['rest' => DBA::count('photo', $condition)]);
$rows = 0; $rows = 0;
$photos = DBA::select('photo', [], $condition, ['limit' => 10000]); $photos = DBA::select('photo', [], $condition, ['limit' => 100]);
if (DBA::errorNo() != 0) { if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]); Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
@ -771,7 +783,7 @@ class PostUpdate
} }
/** /**
* update the "hash" field in the photo table * update the "external-id" field in the post table
* *
* @return bool "true" when the job is done * @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
@ -816,4 +828,187 @@ class PostUpdate
return false; return false;
} }
/**
* update the "uri-id" field in the contact table
*
* @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function update1424()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1424) {
return true;
}
$condition = ["`uri-id` IS NULL"];
Logger::info('Start', ['rest' => DBA::count('contact', $condition)]);
$rows = 0;
$contacts = DBA::select('contact', ['id', 'url'], $condition, ['limit' => 1000]);
if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
return false;
}
while ($contact = DBA::fetch($contacts)) {
DBA::update('contact', ['uri-id' => ItemURI::getIdByURI($contact['url'])], ['id' => $contact['id']]);
++$rows;
}
DBA::close($contacts);
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1424);
Logger::info('Done');
return true;
}
return false;
}
/**
* update the "uri-id" field in the fcontact table
*
* @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function update1425()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1425) {
return true;
}
$condition = ["`uri-id` IS NULL"];
Logger::info('Start', ['rest' => DBA::count('fcontact', $condition)]);
$rows = 0;
$fcontacts = DBA::select('fcontact', ['id', 'url', 'guid'], $condition, ['limit' => 1000]);
if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
return false;
}
while ($fcontact = DBA::fetch($fcontacts)) {
if (!empty($fcontact['guid'])) {
$uriid = ItemURI::insert(['uri' => $fcontact['url'], 'guid' => $fcontact['guid']]);
} else {
$uriid = ItemURI::getIdByURI($fcontact['url']);
}
DBA::update('fcontact', ['uri-id' => $uriid], ['id' => $fcontact['id']]);
++$rows;
}
DBA::close($fcontacts);
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1425);
Logger::info('Done');
return true;
}
return false;
}
/**
* update the "uri-id" field in the apcontact table
*
* @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function update1426()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1426) {
return true;
}
$condition = ["`uri-id` IS NULL"];
Logger::info('Start', ['rest' => DBA::count('apcontact', $condition)]);
$rows = 0;
$apcontacts = DBA::select('apcontact', ['url', 'uuid'], $condition, ['limit' => 1000]);
if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
return false;
}
while ($apcontact = DBA::fetch($apcontacts)) {
if (!empty($apcontact['uuid'])) {
$uriid = ItemURI::insert(['uri' => $apcontact['url'], 'guid' => $apcontact['uuid']]);
} else {
$uriid = ItemURI::getIdByURI($apcontact['url']);
}
DBA::update('apcontact', ['uri-id' => $uriid], ['url' => $apcontact['url']]);
++$rows;
}
DBA::close($apcontacts);
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1426);
Logger::info('Done');
return true;
}
return false;
}
/**
* update the "uri-id" field in the event table
*
* @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function update1427()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1427) {
return true;
}
$condition = ["`uri-id` IS NULL"];
Logger::info('Start', ['rest' => DBA::count('event', $condition)]);
$rows = 0;
$events = DBA::select('event', ['id', 'uri', 'guid'], $condition, ['limit' => 1000]);
if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
return false;
}
while ($event = DBA::fetch($events)) {
if (!empty($event['guid'])) {
$uriid = ItemURI::insert(['uri' => $event['uri'], 'guid' => $event['guid']]);
} else {
$uriid = ItemURI::getIdByURI($event['uri']);
}
DBA::update('event', ['uri-id' => $uriid], ['id' => $event['id']]);
++$rows;
}
DBA::close($events);
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set("system", "post_update_version", 1427);
Logger::info('Done');
return true;
}
return false;
}
} }

View file

@ -124,7 +124,7 @@ class APContact
$apcontact = DBA::selectFirst('apcontact', [], ['addr' => $url]); $apcontact = DBA::selectFirst('apcontact', [], ['addr' => $url]);
} }
if (DBA::isResult($apcontact) && ($apcontact['updated'] > $ref_update) && !empty($apcontact['pubkey'])) { if (DBA::isResult($apcontact) && ($apcontact['updated'] > $ref_update) && !empty($apcontact['pubkey']) && !empty($apcontact['uri-id'])) {
return $apcontact; return $apcontact;
} }
@ -349,6 +349,12 @@ class APContact
$apcontact['alias'] = null; $apcontact['alias'] = null;
} }
if (empty($apcontact['uuid'])) {
$apcontact['uri-id'] = ItemURI::getIdByURI($apcontact['url']);
} else {
$apcontact['uri-id'] = ItemURI::insert(['uri' => $apcontact['url'], 'guid' => $apcontact['uuid']]);
}
$apcontact['updated'] = DateTimeFormat::utcNow(); $apcontact['updated'] = DateTimeFormat::utcNow();
// We delete the old entry when the URL is changed // We delete the old entry when the URL is changed

View file

@ -185,6 +185,8 @@ class Contact
$fields['gsid'] = GServer::getID($fields['baseurl'], true); $fields['gsid'] = GServer::getID($fields['baseurl'], true);
} }
$fields['uri-id'] = ItemURI::getIdByURI($fields['url']);
if (empty($fields['created'])) { if (empty($fields['created'])) {
$fields['created'] = DateTimeFormat::utcNow(); $fields['created'] = DateTimeFormat::utcNow();
} }
@ -1070,12 +1072,12 @@ class Contact
return 0; return 0;
} }
$contact = self::getByURL($url, false, ['id', 'network'], $uid); $contact = self::getByURL($url, false, ['id', 'network', 'uri-id'], $uid);
if (!empty($contact)) { if (!empty($contact)) {
$contact_id = $contact["id"]; $contact_id = $contact["id"];
if (empty($update)) { if (empty($update) && (!empty($contact['uri-id']) || is_bool($update))) {
Logger::debug('Contact found', ['url' => $url, 'uid' => $uid, 'update' => $update, 'cid' => $contact_id]); Logger::debug('Contact found', ['url' => $url, 'uid' => $uid, 'update' => $update, 'cid' => $contact_id]);
return $contact_id; return $contact_id;
} }
@ -1497,67 +1499,46 @@ class Contact
* @param bool $no_update Don't perfom an update if no cached avatar was found * @param bool $no_update Don't perfom an update if no cached avatar was found
* @return string photo path * @return string photo path
*/ */
private static function getAvatarPath(array $contact, string $field, string $size, string $avatar, $no_update = false) private static function getAvatarPath(array $contact, string $size, $no_update = false)
{ {
if (!empty($contact)) {
$contact = self::checkAvatarCacheByArray($contact, $no_update); $contact = self::checkAvatarCacheByArray($contact, $no_update);
if (!empty($contact['id'])) {
return self::getAvatarUrlForId($contact['id'], $size, $contact['updated'] ?? ''); return self::getAvatarUrlForId($contact['id'], $size, $contact['updated'] ?? '');
} elseif (!empty($contact[$field])) {
return $contact[$field];
} elseif (!empty($contact['avatar'])) {
$avatar = $contact['avatar'];
}
}
if (empty($avatar)) {
$avatar = self::getDefaultAvatar([], $size);
}
if (Proxy::isLocalImage($avatar)) {
return $avatar;
} else {
return Proxy::proxifyUrl($avatar, false, $size);
}
} }
/** /**
* Return the photo path for a given contact array * Return the photo path for a given contact array
* *
* @param array $contact Contact array * @param array $contact Contact array
* @param string $avatar Avatar path that is displayed when no photo had been found
* @param bool $no_update Don't perfom an update if no cached avatar was found * @param bool $no_update Don't perfom an update if no cached avatar was found
* @return string photo path * @return string photo path
*/ */
public static function getPhoto(array $contact, string $avatar = '', bool $no_update = false) public static function getPhoto(array $contact, bool $no_update = false)
{ {
return self::getAvatarPath($contact, 'photo', Proxy::SIZE_SMALL, $avatar, $no_update); return self::getAvatarPath($contact, Proxy::SIZE_SMALL, $no_update);
} }
/** /**
* Return the photo path (thumb size) for a given contact array * Return the photo path (thumb size) for a given contact array
* *
* @param array $contact Contact array * @param array $contact Contact array
* @param string $avatar Avatar path that is displayed when no photo had been found
* @param bool $no_update Don't perfom an update if no cached avatar was found * @param bool $no_update Don't perfom an update if no cached avatar was found
* @return string photo path * @return string photo path
*/ */
public static function getThumb(array $contact, string $avatar = '', bool $no_update = false) public static function getThumb(array $contact, bool $no_update = false)
{ {
return self::getAvatarPath($contact, 'thumb', Proxy::SIZE_THUMB, $avatar, $no_update); return self::getAvatarPath($contact, Proxy::SIZE_THUMB, $no_update);
} }
/** /**
* Return the photo path (micro size) for a given contact array * Return the photo path (micro size) for a given contact array
* *
* @param array $contact Contact array * @param array $contact Contact array
* @param string $avatar Avatar path that is displayed when no photo had been found
* @param bool $no_update Don't perfom an update if no cached avatar was found * @param bool $no_update Don't perfom an update if no cached avatar was found
* @return string photo path * @return string photo path
*/ */
public static function getMicro(array $contact, string $avatar = '', bool $no_update = false) public static function getMicro(array $contact, bool $no_update = false)
{ {
return self::getAvatarPath($contact, 'micro', Proxy::SIZE_MICRO, $avatar, $no_update); return self::getAvatarPath($contact, Proxy::SIZE_MICRO, $no_update);
} }
/** /**
@ -1907,7 +1888,7 @@ class Contact
{ {
if (Strings::normaliseLink($new_url) != Strings::normaliseLink($old_url)) { if (Strings::normaliseLink($new_url) != Strings::normaliseLink($old_url)) {
Logger::notice('New URL differs from old URL', ['old' => $old_url, 'new' => $new_url]); Logger::notice('New URL differs from old URL', ['old' => $old_url, 'new' => $new_url]);
// @todo It is to decide what to do when the URL is changed return;
} }
if (!DBA::update('contact', $fields, ['id' => $id])) { if (!DBA::update('contact', $fields, ['id' => $id])) {
@ -2042,7 +2023,7 @@ class Contact
// These fields aren't updated by this routine: // These fields aren't updated by this routine:
// 'xmpp', 'sensitive' // 'xmpp', 'sensitive'
$fields = ['uid', 'avatar', 'header', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe', $fields = ['uid', 'uri-id', 'avatar', 'header', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe',
'manually-approve', 'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'manually-approve', 'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco',
'network', 'alias', 'baseurl', 'gsid', 'forum', 'prv', 'contact-type', 'pubkey', 'last-item']; 'network', 'alias', 'baseurl', 'gsid', 'forum', 'prv', 'contact-type', 'pubkey', 'last-item'];
$contact = DBA::selectFirst('contact', $fields, ['id' => $id]); $contact = DBA::selectFirst('contact', $fields, ['id' => $id]);
@ -2071,6 +2052,9 @@ class Contact
$uid = $contact['uid']; $uid = $contact['uid'];
unset($contact['uid']); unset($contact['uid']);
$uriid = $contact['uri-id'];
unset($contact['uri-id']);
$pubkey = $contact['pubkey']; $pubkey = $contact['pubkey'];
unset($contact['pubkey']); unset($contact['pubkey']);
@ -2094,6 +2078,14 @@ class Contact
return false; return false;
} }
if (Strings::normaliseLink($ret['url']) != Strings::normaliseLink($contact['url'])) {
$cid = self::getIdForURL($ret['url']);
if (!empty($cid) && ($cid != $id)) {
Logger::notice('URL of contact changed.', ['id' => $id, 'new_id' => $cid, 'old' => $contact['url'], 'new' => $ret['url']]);
return self::updateFromProbeArray($cid, $ret);
}
}
if (isset($ret['hide']) && is_bool($ret['hide'])) { if (isset($ret['hide']) && is_bool($ret['hide'])) {
$ret['unsearchable'] = $ret['hide']; $ret['unsearchable'] = $ret['hide'];
} }
@ -2116,6 +2108,7 @@ class Contact
} }
$update = false; $update = false;
$guid = $ret['guid'] ?? '';
// make sure to not overwrite existing values with blank entries except some technical fields // make sure to not overwrite existing values with blank entries except some technical fields
$keep = ['batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'baseurl']; $keep = ['batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'baseurl'];
@ -2135,6 +2128,10 @@ class Contact
unset($ret['last-item']); unset($ret['last-item']);
} }
if (empty($uriid)) {
$update = true;
}
if (!empty($ret['photo']) && ($ret['network'] != Protocol::FEED)) { if (!empty($ret['photo']) && ($ret['network'] != Protocol::FEED)) {
self::updateAvatar($id, $ret['photo'], $update); self::updateAvatar($id, $ret['photo'], $update);
} }
@ -2157,6 +2154,12 @@ class Contact
return true; return true;
} }
if (empty($guid)) {
$ret['uri-id'] = ItemURI::getIdByURI($ret['url']);
} else {
$ret['uri-id'] = ItemURI::insert(['uri' => $ret['url'], 'guid' => $guid]);
}
$ret['nurl'] = Strings::normaliseLink($ret['url']); $ret['nurl'] = Strings::normaliseLink($ret['url']);
$ret['updated'] = $updated; $ret['updated'] = $updated;
$ret['failed'] = false; $ret['failed'] = false;
@ -2989,7 +2992,8 @@ class Contact
$search .= '%'; $search .= '%';
$results = DBA::p("SELECT * FROM `contact` $results = DBA::p("SELECT * FROM `contact`
WHERE NOT `unsearchable` AND `network` IN (?, ?, ?, ?) AND WHERE (NOT `unsearchable` OR `nurl` IN (SELECT `nurl` FROM `owner-view` where `publish` OR `net-publish`))
AND `network` IN (?, ?, ?, ?) AND
NOT `failed` AND `uid` = ? AND NOT `failed` AND `uid` = ? AND
(`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?) $extra_sql (`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?) $extra_sql
ORDER BY `nurl` DESC LIMIT 1000", ORDER BY `nurl` DESC LIMIT 1000",

View file

@ -41,12 +41,14 @@ use Friendica\Util\XML;
class Event class Event
{ {
public static function getHTML(array $event, $simple = false) public static function getHTML(array $event, $simple = false, $uriid = 0)
{ {
if (empty($event)) { if (empty($event)) {
return ''; return '';
} }
$uriid = $event['uri-id'] ?? $uriid;
$bd_format = DI::l10n()->t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8 AM. $bd_format = DI::l10n()->t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8 AM.
$event_start = DI::l10n()->getDay( $event_start = DI::l10n()->getDay(
@ -67,11 +69,11 @@ class Event
$o = ''; $o = '';
if (!empty($event['summary'])) { if (!empty($event['summary'])) {
$o .= "<h3>" . BBCode::convert(Strings::escapeHtml($event['summary']), false, $simple) . "</h3>"; $o .= "<h3>" . BBCode::convertForUriId($uriid, Strings::escapeHtml($event['summary']), $simple) . "</h3>";
} }
if (!empty($event['desc'])) { if (!empty($event['desc'])) {
$o .= "<div>" . BBCode::convert(Strings::escapeHtml($event['desc']), false, $simple) . "</div>"; $o .= "<div>" . BBCode::convertForUriId($uriid, Strings::escapeHtml($event['desc']), $simple) . "</div>";
} }
$o .= "<h4>" . DI::l10n()->t('Starts:') . "</h4><p>" . $event_start . "</p>"; $o .= "<h4>" . DI::l10n()->t('Starts:') . "</h4><p>" . $event_start . "</p>";
@ -81,7 +83,7 @@ class Event
} }
if (!empty($event['location'])) { if (!empty($event['location'])) {
$o .= "<h4>" . DI::l10n()->t('Location:') . "</h4><p>" . BBCode::convert(Strings::escapeHtml($event['location']), false, $simple) . "</p>"; $o .= "<h4>" . DI::l10n()->t('Location:') . "</h4><p>" . BBCode::convertForUriId($uriid, Strings::escapeHtml($event['location']), $simple) . "</p>";
} }
return $o; return $o;
@ -89,7 +91,7 @@ class Event
$o = '<div class="vevent">' . "\r\n"; $o = '<div class="vevent">' . "\r\n";
$o .= '<div class="summary event-summary">' . BBCode::convert(Strings::escapeHtml($event['summary']), false, $simple) . '</div>' . "\r\n"; $o .= '<div class="summary event-summary">' . BBCode::convertForUriId($uriid, Strings::escapeHtml($event['summary']), $simple) . '</div>' . "\r\n";
$o .= '<div class="event-start"><span class="event-label">' . DI::l10n()->t('Starts:') . '</span>&nbsp;<span class="dtstart" title="' $o .= '<div class="event-start"><span class="event-label">' . DI::l10n()->t('Starts:') . '</span>&nbsp;<span class="dtstart" title="'
. DateTimeFormat::utc($event['start'], (!empty($event['adjust']) ? DateTimeFormat::ATOM : 'Y-m-d\TH:i:s')) . DateTimeFormat::utc($event['start'], (!empty($event['adjust']) ? DateTimeFormat::ATOM : 'Y-m-d\TH:i:s'))
@ -104,12 +106,12 @@ class Event
} }
if (!empty($event['desc'])) { if (!empty($event['desc'])) {
$o .= '<div class="description event-description">' . BBCode::convert(Strings::escapeHtml($event['desc']), false, $simple) . '</div>' . "\r\n"; $o .= '<div class="description event-description">' . BBCode::convertForUriId($uriid, Strings::escapeHtml($event['desc']), $simple) . '</div>' . "\r\n";
} }
if (!empty($event['location'])) { if (!empty($event['location'])) {
$o .= '<div class="event-location"><span class="event-label">' . DI::l10n()->t('Location:') . '</span>&nbsp;<span class="location">' $o .= '<div class="event-location"><span class="event-label">' . DI::l10n()->t('Location:') . '</span>&nbsp;<span class="location">'
. BBCode::convert(Strings::escapeHtml($event['location']), false, $simple) . BBCode::convertForUriId($uriid, Strings::escapeHtml($event['location']), $simple)
. '</span></div>' . "\r\n"; . '</span></div>' . "\r\n";
// Include a map of the location if the [map] BBCode is used. // Include a map of the location if the [map] BBCode is used.
@ -273,6 +275,7 @@ class Event
$event['cid'] = intval($arr['cid'] ?? 0); $event['cid'] = intval($arr['cid'] ?? 0);
$event['guid'] = ($arr['guid'] ?? '') ?: System::createUUID(); $event['guid'] = ($arr['guid'] ?? '') ?: System::createUUID();
$event['uri'] = ($arr['uri'] ?? '') ?: Item::newURI($event['uid'], $event['guid']); $event['uri'] = ($arr['uri'] ?? '') ?: Item::newURI($event['uid'], $event['guid']);
$event['uri-id'] = ItemURI::insert(['uri' => $event['uri'], 'guid' => $event['guid']]);
$event['type'] = ($arr['type'] ?? '') ?: 'event'; $event['type'] = ($arr['type'] ?? '') ?: 'event';
$event['summary'] = $arr['summary'] ?? ''; $event['summary'] = $arr['summary'] ?? '';
$event['desc'] = $arr['desc'] ?? ''; $event['desc'] = $arr['desc'] ?? '';
@ -586,10 +589,10 @@ class Event
$last_date = ''; $last_date = '';
$fmt = DI::l10n()->t('l, F j'); $fmt = DI::l10n()->t('l, F j');
foreach ($event_result as $event) { foreach ($event_result as $event) {
$item = Post::selectFirst(['plink', 'author-name', 'author-avatar', 'author-link', 'private'], ['id' => $event['itemid']]); $item = Post::selectFirst(['plink', 'author-name', 'author-avatar', 'author-link', 'private', 'uri-id'], ['id' => $event['itemid']]);
if (!DBA::isResult($item)) { if (!DBA::isResult($item)) {
// Using default values when no item had been found // Using default values when no item had been found
$item = ['plink' => '', 'author-name' => '', 'author-avatar' => '', 'author-link' => '', 'private' => Item::PUBLIC]; $item = ['plink' => '', 'author-name' => '', 'author-avatar' => '', 'author-link' => '', 'private' => Item::PUBLIC, 'uri-id' => ($event['uri-id'] ?? 0)];
} }
$event = array_merge($event, $item); $event = array_merge($event, $item);
@ -620,9 +623,9 @@ class Event
$drop = [DI::baseUrl() . '/events/drop/' . $event['id'] , DI::l10n()->t('Delete event') , '', '']; $drop = [DI::baseUrl() . '/events/drop/' . $event['id'] , DI::l10n()->t('Delete event') , '', ''];
} }
$title = BBCode::convert(Strings::escapeHtml($event['summary'])); $title = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['summary']));
if (!$title) { if (!$title) {
list($title, $_trash) = explode("<br", BBCode::convert(Strings::escapeHtml($event['desc'])), BBCode::API); list($title, $_trash) = explode("<br", BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['desc'])), BBCode::API);
} }
$author_link = $event['author-link']; $author_link = $event['author-link'];
@ -630,9 +633,9 @@ class Event
$event['author-link'] = Contact::magicLink($author_link); $event['author-link'] = Contact::magicLink($author_link);
$html = self::getHTML($event); $html = self::getHTML($event);
$event['summary'] = BBCode::convert(Strings::escapeHtml($event['summary'])); $event['summary'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['summary']));
$event['desc'] = BBCode::convert(Strings::escapeHtml($event['desc'])); $event['desc'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['desc']));
$event['location'] = BBCode::convert(Strings::escapeHtml($event['location'])); $event['location'] = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['location']));
$event_list[] = [ $event_list[] = [
'id' => $event['id'], 'id' => $event['id'],
'start' => $start, 'start' => $start,
@ -937,7 +940,7 @@ class Event
$tpl = Renderer::getMarkupTemplate('event_stream_item.tpl'); $tpl = Renderer::getMarkupTemplate('event_stream_item.tpl');
$return = Renderer::replaceMacros($tpl, [ $return = Renderer::replaceMacros($tpl, [
'$id' => $item['event-id'], '$id' => $item['event-id'],
'$title' => BBCode::convert($item['event-summary']), '$title' => BBCode::convertForUriId($item['uri-id'], $item['event-summary']),
'$dtstart_label' => DI::l10n()->t('Starts:'), '$dtstart_label' => DI::l10n()->t('Starts:'),
'$dtstart_title' => $dtstart_title, '$dtstart_title' => $dtstart_title,
'$dtstart_dt' => $dtstart_dt, '$dtstart_dt' => $dtstart_dt,
@ -955,7 +958,7 @@ class Event
'$author_name' => $item['author-name'], '$author_name' => $item['author-name'],
'$author_link' => $profile_link, '$author_link' => $profile_link,
'$author_avatar' => $item['author-avatar'], '$author_avatar' => $item['author-avatar'],
'$description' => BBCode::convert($item['event-desc']), '$description' => BBCode::convertForUriId($item['uri-id'], $item['event-desc']),
'$location_label' => DI::l10n()->t('Location:'), '$location_label' => DI::l10n()->t('Location:'),
'$show_map_label' => DI::l10n()->t('Show map'), '$show_map_label' => DI::l10n()->t('Show map'),
'$hide_map_label' => DI::l10n()->t('Hide map'), '$hide_map_label' => DI::l10n()->t('Hide map'),

View file

@ -60,7 +60,7 @@ class FContact
$update = true; $update = true;
} }
if ($person["guid"] == "") { if (empty($person['guid']) || empty($person['uri-id'])) {
$update = true; $update = true;
} }
} }
@ -100,6 +100,7 @@ class FContact
'batch' => $arr["batch"], 'notify' => $arr["notify"], 'batch' => $arr["batch"], 'notify' => $arr["notify"],
'poll' => $arr["poll"], 'confirm' => $arr["confirm"], 'poll' => $arr["poll"], 'confirm' => $arr["confirm"],
'alias' => $arr["alias"], 'pubkey' => $arr["pubkey"], 'alias' => $arr["alias"], 'pubkey' => $arr["pubkey"],
'uri-id' => ItemURI::insert(['uri' => $arr['url'], 'guid' => $arr['guid']]),
'updated' => DateTimeFormat::utcNow()]; 'updated' => DateTimeFormat::utcNow()];
$condition = ['url' => $arr["url"], 'network' => $arr["network"]]; $condition = ['url' => $arr["url"], 'network' => $arr["network"]];

View file

@ -1008,9 +1008,6 @@ class Item
// Check for hashtags in the body and repair or add hashtag links // Check for hashtags in the body and repair or add hashtag links
$item['body'] = self::setHashtags($item['body']); $item['body'] = self::setHashtags($item['body']);
// Fill the cache field
self::putInCache($item);
if (stristr($item['verb'], Activity::POKE)) { if (stristr($item['verb'], Activity::POKE)) {
$notify_type = Delivery::POKE; $notify_type = Delivery::POKE;
} else { } else {
@ -2643,7 +2640,7 @@ class Item
) { ) {
self::addRedirToImageTags($item); self::addRedirToImageTags($item);
$item['rendered-html'] = BBCode::convert($item['body']); $item['rendered-html'] = BBCode::convertForUriId($item['uri-id'], $item['body']);
$item['rendered-hash'] = hash('md5', BBCode::VERSION . '::' . $body); $item['rendered-hash'] = hash('md5', BBCode::VERSION . '::' . $body);
$hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']]; $hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']];
@ -2783,13 +2780,13 @@ class Item
if (!empty($shared_attachments)) { if (!empty($shared_attachments)) {
$s = self::addVisualAttachments($shared_attachments, $item, $s, true); $s = self::addVisualAttachments($shared_attachments, $item, $s, true);
$s = self::addLinkAttachment($shared_attachments, $body, $s, true, []); $s = self::addLinkAttachment($shared_uri_id ?: $item['uri-id'], $shared_attachments, $body, $s, true, []);
$s = self::addNonVisualAttachments($shared_attachments, $item, $s, true); $s = self::addNonVisualAttachments($shared_attachments, $item, $s, true);
$body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body); $body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body);
} }
$s = self::addVisualAttachments($attachments, $item, $s, false); $s = self::addVisualAttachments($attachments, $item, $s, false);
$s = self::addLinkAttachment($attachments, $body, $s, false, $shared_links); $s = self::addLinkAttachment($item['uri-id'], $attachments, $body, $s, false, $shared_links);
$s = self::addNonVisualAttachments($attachments, $item, $s, false); $s = self::addNonVisualAttachments($attachments, $item, $s, false);
// Map. // Map.
@ -2970,7 +2967,7 @@ class Item
* @param array $ignore_links A list of URLs to ignore * @param array $ignore_links A list of URLs to ignore
* @return string modified content * @return string modified content
*/ */
private static function addLinkAttachment(array $attachments, string $body, string $content, bool $shared, array $ignore_links) private static function addLinkAttachment(int $uriid, array $attachments, string $body, string $content, bool $shared, array $ignore_links)
{ {
$stamp1 = microtime(true); $stamp1 = microtime(true);
// @ToDo Check only for audio and video // @ToDo Check only for audio and video
@ -3056,7 +3053,7 @@ class Item
} }
// @todo Use a template // @todo Use a template
$rendered = BBCode::convertAttachment('', BBCode::INTERNAL, false, $data); $rendered = BBCode::convertAttachment('', BBCode::INTERNAL, false, $data, $uriid);
} elseif (!self::containsLink($content, $data['url'], Post\Media::HTML)) { } elseif (!self::containsLink($content, $data['url'], Post\Media::HTML)) {
$rendered = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/link.tpl'), [ $rendered = Renderer::replaceMacros(Renderer::getMarkupTemplate('content/link.tpl'), [
'$url' => $data['url'], '$url' => $data['url'],

View file

@ -156,6 +156,27 @@ class Post
return DBA::count('post-user-view', $condition, $params); return DBA::count('post-user-view', $condition, $params);
} }
/**
* Counts the post-thread-user-view records satisfying the provided condition
*
* @param array $condition array of fields for condition
* @param array $params Array of several parameters
*
* @return int
*
* Example:
* $condition = ["uid" => 1, "network" => 'dspr'];
* or:
* $condition = ["`uid` = ? AND `network` IN (?, ?)", 1, 'dfrn', 'dspr'];
*
* $count = Post::count($condition);
* @throws \Exception
*/
public static function countThread(array $condition = [], array $params = [])
{
return DBA::count('post-thread-user-view', $condition, $params);
}
/** /**
* Counts the post-view records satisfying the provided condition * Counts the post-view records satisfying the provided condition
* *

127
src/Model/Post/Link.php Normal file
View file

@ -0,0 +1,127 @@
<?php
/**
* @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Model\Post;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Util\Proxy;
/**
* Class Link
*
* This Model class handles post related external links
*/
class Link
{
public static function getByLink(int $uri_id, string $url, $size = '')
{
if (empty($uri_id) || empty($url) || Proxy::isLocalImage($url)) {
return $url;
}
if (!in_array(parse_url($url, PHP_URL_SCHEME), ['http', 'https'])) {
Logger::info('Bad URL, quitting', ['uri-id' => $uri_id, 'url' => $url, 'callstack' => System::callstack(20)]);
return $url;
}
$link = DBA::selectFirst('post-link', ['id'], ['uri-id' => $uri_id, 'url' => $url]);
if (!empty($link['id'])) {
$id = $link['id'];
Logger::info('Found', ['id' => $id, 'uri-id' => $uri_id, 'url' => $url]);
} else {
$mime = self::fetchMimeType($url);
DBA::insert('post-link', ['uri-id' => $uri_id, 'url' => $url, 'mimetype' => $mime]);
$id = DBA::lastInsertId();
Logger::info('Inserted', ['id' => $id, 'uri-id' => $uri_id, 'url' => $url]);
}
if (empty($id)) {
return $url;
}
$url = DI::baseUrl() . '/photo/link/';
switch ($size) {
case Proxy::SIZE_MICRO:
$url .= Proxy::PIXEL_MICRO . '/';
break;
case Proxy::SIZE_THUMB:
$url .= Proxy::PIXEL_THUMB . '/';
break;
case Proxy::SIZE_SMALL:
$url .= Proxy::PIXEL_SMALL . '/';
break;
case Proxy::SIZE_MEDIUM:
$url .= Proxy::PIXEL_MEDIUM . '/';
break;
case Proxy::SIZE_LARGE:
$url .= Proxy::PIXEL_LARGE . '/';
break;
}
return $url . $id;
}
private static function fetchMimeType(string $url)
{
$timeout = DI::config()->get('system', 'xrd_timeout');
$curlResult = DI::httpRequest()->head($url, ['timeout' => $timeout]);
if ($curlResult->isSuccess()) {
if (empty($media['mimetype'])) {
return $curlResult->getHeader('Content-Type');
}
}
return '';
}
/**
* Add external links and replace them in the body
*
* @param integer $uriid
* @param string $body
* @return string Body with replaced links
*/
public static function insertFromBody(int $uriid, string $body)
{
if (preg_match_all("/\[img\=([0-9]*)x([0-9]*)\](http.*?)\[\/img\]/ism", $body, $pictures, PREG_SET_ORDER)) {
foreach ($pictures as $picture) {
$body = str_replace($picture[3], self::getByLink($uriid, $picture[3]), $body);
}
}
if (preg_match_all("/\[img=(http[^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) {
foreach ($pictures as $picture) {
$body = str_replace($picture[1], self::getByLink($uriid, $picture[1]), $body);
}
}
if (preg_match_all("/\[img\](http[^\[\]]*)\[\/img\]/ism", $body, $pictures, PREG_SET_ORDER)) {
foreach ($pictures as $picture) {
$body = str_replace($picture[1], self::getByLink($uriid, $picture[1]), $body);
}
}
return trim($body);
}
}

View file

@ -486,11 +486,11 @@ class Profile
} }
if (isset($p['about'])) { if (isset($p['about'])) {
$p['about'] = BBCode::convert($p['about']); $p['about'] = BBCode::convertForUriId($profile['uri-id'] ?? 0, $p['about']);
} }
if (isset($p['address'])) { if (isset($p['address'])) {
$p['address'] = BBCode::convert($p['address']); $p['address'] = BBCode::convertForUriId($profile['uri-id'] ?? 0, $p['address']);
} }
$p['photo'] = Contact::getAvatarUrlForId($cid, ProxyUtils::SIZE_SMALL); $p['photo'] = Contact::getAvatarUrlForId($cid, ProxyUtils::SIZE_SMALL);
@ -670,13 +670,13 @@ class Profile
$istoday = true; $istoday = true;
} }
$title = strip_tags(html_entity_decode(BBCode::convert($rr['summary']), ENT_QUOTES, 'UTF-8')); $title = strip_tags(html_entity_decode(BBCode::convertForUriId($rr['uri-id'], $rr['summary']), ENT_QUOTES, 'UTF-8'));
if (strlen($title) > 35) { if (strlen($title) > 35) {
$title = substr($title, 0, 32) . '... '; $title = substr($title, 0, 32) . '... ';
} }
$description = substr(strip_tags(BBCode::convert($rr['desc'])), 0, 32) . '... '; $description = substr(strip_tags(BBCode::convertForUriId($rr['uri-id'], $rr['desc'])), 0, 32) . '... ';
if (!$description) { if (!$description) {
$description = DI::l10n()->t('[No description]'); $description = DI::l10n()->t('[No description]');
} }

View file

@ -146,6 +146,15 @@ class User
$system['sprvkey'] = $system['uprvkey'] = $system['prvkey']; $system['sprvkey'] = $system['uprvkey'] = $system['prvkey'];
$system['spubkey'] = $system['upubkey'] = $system['pubkey']; $system['spubkey'] = $system['upubkey'] = $system['pubkey'];
$system['nickname'] = $system['nick']; $system['nickname'] = $system['nick'];
$system['page-flags'] = User::PAGE_FLAGS_SOAPBOX;
$system['account-type'] = $system['contact-type'];
$system['guid'] = '';
$system['nickname'] = $system['nick'];
$system['pubkey'] = $system['pubkey'];
$system['locality'] = '';
$system['region'] = '';
$system['country-name'] = '';
$system['net-publish'] = false;
// Ensure that the user contains data // Ensure that the user contains data
$user = DBA::selectFirst('user', ['prvkey'], ['uid' => 0]); $user = DBA::selectFirst('user', ['prvkey'], ['uid' => 0]);

View file

@ -194,13 +194,10 @@ class Site extends BaseAdmin
$dbclean_unclaimed = (!empty($_POST['dbclean_unclaimed']) ? intval($_POST['dbclean_unclaimed']) : 0); $dbclean_unclaimed = (!empty($_POST['dbclean_unclaimed']) ? intval($_POST['dbclean_unclaimed']) : 0);
$dbclean_expire_conv = (!empty($_POST['dbclean_expire_conv']) ? intval($_POST['dbclean_expire_conv']) : 0); $dbclean_expire_conv = (!empty($_POST['dbclean_expire_conv']) ? intval($_POST['dbclean_expire_conv']) : 0);
$suppress_tags = !empty($_POST['suppress_tags']); $suppress_tags = !empty($_POST['suppress_tags']);
$itemcache = (!empty($_POST['itemcache']) ? Strings::escapeTags(trim($_POST['itemcache'])) : '');
$itemcache_duration = (!empty($_POST['itemcache_duration']) ? intval($_POST['itemcache_duration']) : 0);
$max_comments = (!empty($_POST['max_comments']) ? intval($_POST['max_comments']) : 0); $max_comments = (!empty($_POST['max_comments']) ? intval($_POST['max_comments']) : 0);
$max_display_comments = (!empty($_POST['max_display_comments']) ? intval($_POST['max_display_comments']) : 0); $max_display_comments = (!empty($_POST['max_display_comments']) ? intval($_POST['max_display_comments']) : 0);
$temppath = (!empty($_POST['temppath']) ? Strings::escapeTags(trim($_POST['temppath'])) : ''); $temppath = (!empty($_POST['temppath']) ? Strings::escapeTags(trim($_POST['temppath'])) : '');
$singleuser = (!empty($_POST['singleuser']) ? Strings::escapeTags(trim($_POST['singleuser'])) : ''); $singleuser = (!empty($_POST['singleuser']) ? Strings::escapeTags(trim($_POST['singleuser'])) : '');
$proxy_disabled = !empty($_POST['proxy_disabled']);
$only_tag_search = !empty($_POST['only_tag_search']); $only_tag_search = !empty($_POST['only_tag_search']);
$rino = (!empty($_POST['rino']) ? intval($_POST['rino']) : 0); $rino = (!empty($_POST['rino']) ? intval($_POST['rino']) : 0);
$check_new_version_url = (!empty($_POST['check_new_version_url']) ? Strings::escapeTags(trim($_POST['check_new_version_url'])) : 'none'); $check_new_version_url = (!empty($_POST['check_new_version_url']) ? Strings::escapeTags(trim($_POST['check_new_version_url'])) : 'none');
@ -395,12 +392,6 @@ class Site extends BaseAdmin
DI::config()->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed); DI::config()->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed);
if ($itemcache != '') {
$itemcache = BasePath::getRealPath($itemcache);
}
DI::config()->set('system', 'itemcache', $itemcache);
DI::config()->set('system', 'itemcache_duration', $itemcache_duration);
DI::config()->set('system', 'max_comments', $max_comments); DI::config()->set('system', 'max_comments', $max_comments);
DI::config()->set('system', 'max_display_comments', $max_display_comments); DI::config()->set('system', 'max_display_comments', $max_display_comments);
@ -410,7 +401,6 @@ class Site extends BaseAdmin
DI::config()->set('system', 'temppath', $temppath); DI::config()->set('system', 'temppath', $temppath);
DI::config()->set('system', 'proxy_disabled' , $proxy_disabled);
DI::config()->set('system', 'only_tag_search' , $only_tag_search); DI::config()->set('system', 'only_tag_search' , $only_tag_search);
DI::config()->set('system', 'worker_queues' , $worker_queues); DI::config()->set('system', 'worker_queues' , $worker_queues);
@ -506,7 +496,6 @@ class Site extends BaseAdmin
// Automatically create temporary paths // Automatically create temporary paths
get_temppath(); get_temppath();
get_itemcachepath();
/* Register policy */ /* Register policy */
$register_choices = [ $register_choices = [
@ -674,12 +663,9 @@ class Site extends BaseAdmin
'$dbclean_expire_days' => ['dbclean_expire_days', DI::l10n()->t('Lifespan of remote items'), DI::config()->get('system', 'dbclean-expire-days'), DI::l10n()->t('When the database cleanup is enabled, this defines the days after which remote items will be deleted. Own items, and marked or filed items are always kept. 0 disables this behaviour.')], '$dbclean_expire_days' => ['dbclean_expire_days', DI::l10n()->t('Lifespan of remote items'), DI::config()->get('system', 'dbclean-expire-days'), DI::l10n()->t('When the database cleanup is enabled, this defines the days after which remote items will be deleted. Own items, and marked or filed items are always kept. 0 disables this behaviour.')],
'$dbclean_unclaimed' => ['dbclean_unclaimed', DI::l10n()->t('Lifespan of unclaimed items'), DI::config()->get('system', 'dbclean-expire-unclaimed'), DI::l10n()->t('When the database cleanup is enabled, this defines the days after which unclaimed remote items (mostly content from the relay) will be deleted. Default value is 90 days. Defaults to the general lifespan value of remote items if set to 0.')], '$dbclean_unclaimed' => ['dbclean_unclaimed', DI::l10n()->t('Lifespan of unclaimed items'), DI::config()->get('system', 'dbclean-expire-unclaimed'), DI::l10n()->t('When the database cleanup is enabled, this defines the days after which unclaimed remote items (mostly content from the relay) will be deleted. Default value is 90 days. Defaults to the general lifespan value of remote items if set to 0.')],
'$dbclean_expire_conv' => ['dbclean_expire_conv', DI::l10n()->t('Lifespan of raw conversation data'), DI::config()->get('system', 'dbclean_expire_conversation'), DI::l10n()->t('The conversation data is used for ActivityPub and OStatus, as well as for debug purposes. It should be safe to remove it after 14 days, default is 90 days.')], '$dbclean_expire_conv' => ['dbclean_expire_conv', DI::l10n()->t('Lifespan of raw conversation data'), DI::config()->get('system', 'dbclean_expire_conversation'), DI::l10n()->t('The conversation data is used for ActivityPub and OStatus, as well as for debug purposes. It should be safe to remove it after 14 days, default is 90 days.')],
'$itemcache' => ['itemcache', DI::l10n()->t('Path to item cache'), DI::config()->get('system', 'itemcache'), DI::l10n()->t('The item caches buffers generated bbcode and external images.')],
'$itemcache_duration' => ['itemcache_duration', DI::l10n()->t('Cache duration in seconds'), DI::config()->get('system', 'itemcache_duration'), DI::l10n()->t('How long should the cache files be hold? Default value is 86400 seconds (One day). To disable the item cache, set the value to -1.')],
'$max_comments' => ['max_comments', DI::l10n()->t('Maximum numbers of comments per post'), DI::config()->get('system', 'max_comments'), DI::l10n()->t('How much comments should be shown for each post? Default value is 100.')], '$max_comments' => ['max_comments', DI::l10n()->t('Maximum numbers of comments per post'), DI::config()->get('system', 'max_comments'), DI::l10n()->t('How much comments should be shown for each post? Default value is 100.')],
'$max_display_comments' => ['max_display_comments', DI::l10n()->t('Maximum numbers of comments per post on the display page'), DI::config()->get('system', 'max_display_comments'), DI::l10n()->t('How many comments should be shown on the single view for each post? Default value is 1000.')], '$max_display_comments' => ['max_display_comments', DI::l10n()->t('Maximum numbers of comments per post on the display page'), DI::config()->get('system', 'max_display_comments'), DI::l10n()->t('How many comments should be shown on the single view for each post? Default value is 1000.')],
'$temppath' => ['temppath', DI::l10n()->t('Temp path'), DI::config()->get('system', 'temppath'), DI::l10n()->t('If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.')], '$temppath' => ['temppath', DI::l10n()->t('Temp path'), DI::config()->get('system', 'temppath'), DI::l10n()->t('If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.')],
'$proxy_disabled' => ['proxy_disabled', DI::l10n()->t('Disable picture proxy'), DI::config()->get('system', 'proxy_disabled'), DI::l10n()->t('The picture proxy increases performance and privacy. It shouldn\'t be used on systems with very low bandwidth.')],
'$only_tag_search' => ['only_tag_search', DI::l10n()->t('Only search in tags'), DI::config()->get('system', 'only_tag_search'), DI::l10n()->t('On large systems the text search can slow down the system extremely.')], '$only_tag_search' => ['only_tag_search', DI::l10n()->t('Only search in tags'), DI::config()->get('system', 'only_tag_search'), DI::l10n()->t('On large systems the text search can slow down the system extremely.')],
'$relocate_url' => ['relocate_url', DI::l10n()->t('New base url'), DI::baseUrl()->get(), DI::l10n()->t('Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users.')], '$relocate_url' => ['relocate_url', DI::l10n()->t('New base url'), DI::baseUrl()->get(), DI::l10n()->t('Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users.')],

View file

@ -55,7 +55,7 @@ class Index extends BaseApi
'cid' => $event['cid'], 'cid' => $event['cid'],
'uri' => $event['uri'], 'uri' => $event['uri'],
'name' => $event['summary'], 'name' => $event['summary'],
'desc' => BBCode::convert($event['desc']), 'desc' => BBCode::convertForUriId($event['uri-id'], $event['desc']),
'startTime' => $event['start'], 'startTime' => $event['start'],
'endTime' => $event['finish'], 'endTime' => $event['finish'],
'type' => $event['type'], 'type' => $event['type'],

View file

@ -140,6 +140,8 @@ class Statuses extends BaseApi
$item['gravity'] = GRAVITY_COMMENT; $item['gravity'] = GRAVITY_COMMENT;
$item['object-type'] = Activity\ObjectType::COMMENT; $item['object-type'] = Activity\ObjectType::COMMENT;
} else { } else {
self::checkThrottleLimit();
$item['gravity'] = GRAVITY_PARENT; $item['gravity'] = GRAVITY_PARENT;
$item['object-type'] = Activity\ObjectType::NOTE; $item['object-type'] = Activity\ObjectType::NOTE;
} }

View file

@ -25,9 +25,11 @@ use Friendica\BaseModule;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\DI; use Friendica\DI;
use Friendica\Model\Post;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Security\BasicAuth; use Friendica\Security\BasicAuth;
use Friendica\Security\OAuth; use Friendica\Security\OAuth;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\HTTPInputData; use Friendica\Util\HTTPInputData;
require_once __DIR__ . '/../../include/api.php'; require_once __DIR__ . '/../../include/api.php';
@ -282,6 +284,60 @@ class BaseApi extends BaseModule
} }
} }
public static function checkThrottleLimit()
{
$uid = self::getCurrentUserID();
// Check for throttling (maximum posts per day, week and month)
$throttle_day = DI::config()->get('system', 'throttle_limit_day');
if ($throttle_day > 0) {
$datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60);
$condition = ["`gravity` = ? AND `uid` = ? AND `wall` AND `received` > ?", GRAVITY_PARENT, $uid, $datefrom];
$posts_day = Post::countThread($condition);
if ($posts_day > $throttle_day) {
Logger::info('Daily posting limit reached', ['uid' => $uid, 'posts' => $posts_day, 'limit' => $throttle_day]);
$error = DI::l10n()->t('Too Many Requests');
$error_description = DI::l10n()->tt("Daily posting limit of %d post reached. The post was rejected.", "Daily posting limit of %d posts reached. The post was rejected.", $throttle_day);
$errorobj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
System::jsonError(429, $errorobj->toArray());
}
}
$throttle_week = DI::config()->get('system', 'throttle_limit_week');
if ($throttle_week > 0) {
$datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60*7);
$condition = ["`gravity` = ? AND `uid` = ? AND `wall` AND `received` > ?", GRAVITY_PARENT, $uid, $datefrom];
$posts_week = Post::countThread($condition);
if ($posts_week > $throttle_week) {
Logger::info('Weekly posting limit reached', ['uid' => $uid, 'posts' => $posts_week, 'limit' => $throttle_week]);
$error = DI::l10n()->t('Too Many Requests');
$error_description = DI::l10n()->tt("Weekly posting limit of %d post reached. The post was rejected.", "Weekly posting limit of %d posts reached. The post was rejected.", $throttle_week);
$errorobj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
System::jsonError(429, $errorobj->toArray());
}
}
$throttle_month = DI::config()->get('system', 'throttle_limit_month');
if ($throttle_month > 0) {
$datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60*30);
$condition = ["`gravity` = ? AND `uid` = ? AND `wall` AND `received` > ?", GRAVITY_PARENT, $uid, $datefrom];
$posts_month = Post::countThread($condition);
if ($posts_month > $throttle_month) {
Logger::info('Monthly posting limit reached', ['uid' => $uid, 'posts' => $posts_month, 'limit' => $throttle_month]);
$error = DI::l10n()->t('Too Many Requests');
$error_description = DI::l10n()->t("Monthly posting limit of %d post reached. The post was rejected.", "Monthly posting limit of %d posts reached. The post was rejected.", $throttle_month);
$errorobj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
System::jsonError(429, $errorobj->toArray());
}
}
}
/** /**
* Get user info array. * Get user info array.
* *

View file

@ -650,11 +650,11 @@ class Contact extends BaseModule
'$profileurllabel'=> DI::l10n()->t('Profile URL'), '$profileurllabel'=> DI::l10n()->t('Profile URL'),
'$profileurl' => $contact['url'], '$profileurl' => $contact['url'],
'$account_type' => Model\Contact::getAccountType($contact), '$account_type' => Model\Contact::getAccountType($contact),
'$location' => BBCode::convert($contact['location']), '$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']),
'$location_label' => DI::l10n()->t('Location:'), '$location_label' => DI::l10n()->t('Location:'),
'$xmpp' => BBCode::convert($contact['xmpp']), '$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']),
'$xmpp_label' => DI::l10n()->t('XMPP:'), '$xmpp_label' => DI::l10n()->t('XMPP:'),
'$about' => BBCode::convert($contact['about'], false), '$about' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'], BBCode::EXTERNAL),
'$about_label' => DI::l10n()->t('About:'), '$about_label' => DI::l10n()->t('About:'),
'$keywords' => $contact['keywords'], '$keywords' => $contact['keywords'],
'$keywords_label' => DI::l10n()->t('Tags:'), '$keywords_label' => DI::l10n()->t('Tags:'),
@ -1111,7 +1111,7 @@ class Contact extends BaseModule
'url' => $url, 'url' => $url,
'img_hover' => DI::l10n()->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']), 'img_hover' => DI::l10n()->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
'photo_menu' => Model\Contact::photoMenu($contact), 'photo_menu' => Model\Contact::photoMenu($contact),
'thumb' => Model\Contact::getThumb($contact, '', true), 'thumb' => Model\Contact::getThumb($contact, true),
'alt_text' => $alt_text, 'alt_text' => $alt_text,
'name' => $contact['name'], 'name' => $contact['name'],
'nick' => $contact['nick'], 'nick' => $contact['nick'],

View file

@ -176,7 +176,7 @@ class Photo extends BaseModule
{ {
switch($type) { switch($type) {
case "preview": case "preview":
$media = DBA::selectFirst('post-media', ['preview', 'url', 'type', 'uri-id'], ['id' => $uid]); $media = DBA::selectFirst('post-media', ['preview', 'url', 'mimetype', 'type', 'uri-id'], ['id' => $uid]);
if (empty($media)) { if (empty($media)) {
return false; return false;
} }
@ -194,9 +194,9 @@ class Photo extends BaseModule
return MPhoto::getPhoto($matches[1], $matches[2]); return MPhoto::getPhoto($matches[1], $matches[2]);
} }
return MPhoto::createPhotoForExternalResource($url, (int)local_user()); return MPhoto::createPhotoForExternalResource($url, (int)local_user(), $media['mimetype']);
case "media": case "media":
$media = DBA::selectFirst('post-media', ['url', 'uri-id'], ['id' => $uid, 'type' => Post\Media::IMAGE]); $media = DBA::selectFirst('post-media', ['url', 'mimetype', 'uri-id'], ['id' => $uid, 'type' => Post\Media::IMAGE]);
if (empty($media)) { if (empty($media)) {
return false; return false;
} }
@ -205,7 +205,14 @@ class Photo extends BaseModule
return MPhoto::getPhoto($matches[1], $matches[2]); return MPhoto::getPhoto($matches[1], $matches[2]);
} }
return MPhoto::createPhotoForExternalResource($media['url'], (int)local_user()); return MPhoto::createPhotoForExternalResource($media['url'], (int)local_user(), $media['mimetype']);
case "link":
$link = DBA::selectFirst('post-link', ['url', 'mimetype'], ['id' => $uid]);
if (empty($link)) {
return false;
}
return MPhoto::createPhotoForExternalResource($link['url'], (int)local_user(), $link['mimetype']);
case "contact": case "contact":
$contact = Contact::getById($uid, ['uid', 'url', 'avatar', 'photo', 'xmpp', 'addr']); $contact = Contact::getById($uid, ['uid', 'url', 'avatar', 'photo', 'xmpp', 'addr']);
if (empty($contact)) { if (empty($contact)) {

View file

@ -169,7 +169,7 @@ class Profile extends BaseProfile
} }
if ($a->profile['about']) { if ($a->profile['about']) {
$basic_fields += self::buildField('about', DI::l10n()->t('Description:'), BBCode::convert($a->profile['about'])); $basic_fields += self::buildField('about', DI::l10n()->t('Description:'), BBCode::convertForUriId($a->profile['uri-id'], $a->profile['about']));
} }
if ($a->profile['xmpp']) { if ($a->profile['xmpp']) {
@ -218,7 +218,7 @@ class Profile extends BaseProfile
$custom_fields += self::buildField( $custom_fields += self::buildField(
'custom_' . $profile_field->order, 'custom_' . $profile_field->order,
$profile_field->label, $profile_field->label,
BBCode::convert($profile_field->value), BBCode::convertForUriId($a->profile['uri-id'], $profile_field->value),
'aprofile custom' 'aprofile custom'
); );
}; };

View file

@ -24,10 +24,9 @@ namespace Friendica\Module;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\DI;
use Friendica\Model\Photo;
use Friendica\Object\Image; use Friendica\Object\Image;
use Friendica\Util\HTTPSignature; use Friendica\Util\HTTPSignature;
use Friendica\Util\Images;
use Friendica\Util\Proxy as ProxyUtils; use Friendica\Util\Proxy as ProxyUtils;
/** /**
@ -41,50 +40,27 @@ class Proxy extends BaseModule
{ {
/** /**
* Initializer method for this class. * Fetch remote image content
*
* Sets application instance and checks if /proxy/ path is writable.
*
*/ */
public static function rawContent(array $parameters = []) public static function rawContent(array $parameters = [])
{ {
// Set application instance here if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
$a = DI::app(); header("HTTP/1.1 304 Not Modified");
header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
/* if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) {
* Pictures are stored in one of the following ways: header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]);
* }
* 1. If a folder "proxy" exists and is writeable, then use this for caching header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT");
* 2. If a cache path is defined, use this header("Cache-Control: max-age=31536000");
* 3. If everything else failed, cache into the database if (function_exists("header_remove")) {
* header_remove("Last-Modified");
* Question: Do we really need these three methods? header_remove("Expires");
*/ header_remove("Cache-Control");
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && isset($_SERVER['HTTP_IF_NONE_MATCH'])) { }
header('HTTP/1.1 304 Not Modified'); exit;
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT');
header('Cache-Control: max-age=31536000');
if (function_exists('header_remove')) {
header_remove('Last-Modified');
header_remove('Expires');
header_remove('Cache-Control');
} }
/// @TODO Stop here? $request = self::getRequestInfo($parameters);
exit();
}
if (function_exists('header_remove')) {
header_remove('Pragma');
header_remove('pragma');
}
$direct_cache = self::setupDirectCache();
$request = self::getRequestInfo();
if (empty($request['url'])) { if (empty($request['url'])) {
throw new \Friendica\Network\HTTPException\BadRequestException(); throw new \Friendica\Network\HTTPException\BadRequestException();
@ -95,35 +71,20 @@ class Proxy extends BaseModule
System::externalRedirect($request['url']); System::externalRedirect($request['url']);
} }
// Webserver already tried direct cache...
// Try to use filecache;
$cachefile = self::responseFromCache($request);
// Try to use photo from db
self::responseFromDB($request);
//
// If script is here, the requested url has never cached before.
// Let's fetch it, scale it if required, then save it in cache.
//
// It shouldn't happen but it does - spaces in URL // It shouldn't happen but it does - spaces in URL
$request['url'] = str_replace(' ', '+', $request['url']); $request['url'] = str_replace(' ', '+', $request['url']);
// Fetch the content with the local user
$fetchResult = HTTPSignature::fetchRaw($request['url'], local_user(), ['timeout' => 10]); $fetchResult = HTTPSignature::fetchRaw($request['url'], local_user(), ['timeout' => 10]);
$img_str = $fetchResult->getBody(); $img_str = $fetchResult->getBody();
// If there is an error then return a blank image if (!$fetchResult->isSuccess() || empty($img_str)) {
if ((substr($fetchResult->getReturnCode(), 0, 1) == '4') || empty($img_str)) {
Logger::info('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]); Logger::info('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]);
self::responseError(); self::responseError();
// stop. // stop.
} }
$tempfile = tempnam(get_temppath(), 'cache'); $mime = Images::getMimeTypeByData($img_str);
file_put_contents($tempfile, $img_str);
$mime = mime_content_type($tempfile);
unlink($tempfile);
$image = new Image($img_str, $mime); $image = new Image($img_str, $mime);
if (!$image->isValid()) { if (!$image->isValid()) {
@ -132,80 +93,33 @@ class Proxy extends BaseModule
// stop. // stop.
} }
$basepath = $a->getBasePath();
$filepermission = DI::config()->get('system', 'proxy_file_chmod');
// Store original image
if ($direct_cache) {
// direct cache , store under ./proxy/
$filename = $basepath . '/proxy/' . ProxyUtils::proxifyUrl($request['url'], true);
file_put_contents($filename, $image->asString());
if (!empty($filepermission)) {
chmod($filename, $filepermission);
}
} elseif($cachefile !== '') {
// cache file
file_put_contents($cachefile, $image->asString());
} else {
// database
Photo::store($image, 0, 0, $request['urlhash'], $request['url'], '', 100);
}
// reduce quality - if it isn't a GIF // reduce quality - if it isn't a GIF
if ($image->getType() != 'image/gif') { if ($image->getType() != 'image/gif') {
$image->scaleDown($request['size']); $image->scaleDown($request['size']);
} }
// Store scaled image
if ($direct_cache && $request['sizetype'] != '') {
$filename = $basepath . '/proxy/' . ProxyUtils::proxifyUrl($request['url'], true) . $request['sizetype'];
file_put_contents($filename, $image->asString());
if (!empty($filepermission)) {
chmod($filename, $filepermission);
}
}
self::responseImageHttpCache($image); self::responseImageHttpCache($image);
// stop. // stop.
} }
/** /**
* Build info about requested image to be proxied * Build info about requested image to be proxied
* *
* @return array * @return array
* [ * [
* 'url' => requested url, * 'url' => requested url,
* 'urlhash' => sha1 has of the url prefixed with 'pic:',
* 'size' => requested image size (int) * 'size' => requested image size (int)
* 'sizetype' => requested image size (string): ':micro', ':thumb', ':small', ':medium', ':large' * 'sizetype' => requested image size (string): ':micro', ':thumb', ':small', ':medium', ':large'
* ] * ]
* @throws \Exception * @throws \Exception
*/ */
private static function getRequestInfo() private static function getRequestInfo(array $parameters)
{ {
$a = DI::app();
$size = ProxyUtils::PIXEL_LARGE; $size = ProxyUtils::PIXEL_LARGE;
$sizetype = ''; $sizetype = '';
// Look for filename in the arguments if (!empty($parameters['url']) && empty($_REQUEST['url'])) {
// @TODO: Replace with parameter from router $url = $parameters['url'];
if (($a->argc > 1) && !isset($_REQUEST['url'])) {
if (isset($a->argv[3])) {
$url = $a->argv[3];
} elseif (isset($a->argv[2])) {
$url = $a->argv[2];
} else {
$url = $a->argv[1];
}
/// @TODO: Why? And what about $url in this case?
/// @TODO: Replace with parameter from router
if (isset($a->argv[3]) && ($a->argv[3] == 'thumb')) {
$size = 200;
}
// thumb, small, medium and large. // thumb, small, medium and large.
if (substr($url, -6) == ':micro') { if (substr($url, -6) == ':micro') {
@ -238,87 +152,17 @@ class Proxy extends BaseModule
$url = str_replace(['.jpg', '.jpeg', '.gif', '.png'], ['','','',''], $url); $url = str_replace(['.jpg', '.jpeg', '.gif', '.png'], ['','','',''], $url);
$url = base64_decode(strtr($url, '-_', '+/'), true); $url = base64_decode(strtr($url, '-_', '+/'), true);
} else { } else {
$url = $_REQUEST['url'] ?? ''; $url = $_REQUEST['url'] ?? '';
} }
return [ return [
'url' => $url, 'url' => $url,
'urlhash' => 'pic:' . sha1($url),
'size' => $size, 'size' => $size,
'sizetype' => $sizetype, 'sizetype' => $sizetype,
]; ];
} }
/**
* setup ./proxy folder for direct cache
*
* @return bool False if direct cache can't be used.
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
private static function setupDirectCache()
{
$a = DI::app();
$basepath = $a->getBasePath();
// If the cache path isn't there, try to create it
if (!is_dir($basepath . '/proxy') && is_writable($basepath)) {
mkdir($basepath . '/proxy');
}
// Checking if caching into a folder in the webroot is activated and working
$direct_cache = (is_dir($basepath . '/proxy') && is_writable($basepath . '/proxy'));
// we don't use direct cache if image url is passed in args and not in querystring
$direct_cache = $direct_cache && ($a->argc > 1) && !isset($_REQUEST['url']);
return $direct_cache;
}
/**
* Try to reply with image in cachefile
*
* @param array $request Array from getRequestInfo
*
* @return string Cache file name, empty string if cache is not enabled.
*
* If cachefile exists, script ends here and this function will never returns
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function responseFromCache(&$request)
{
$cachefile = get_cachefile(hash('md5', $request['url']));
if ($cachefile != '' && file_exists($cachefile)) {
$img = new Image(file_get_contents($cachefile), mime_content_type($cachefile));
self::responseImageHttpCache($img);
// stop.
}
return $cachefile;
}
/**
* Try to reply with image in database
*
* @param array $request Array from getRequestInfo
*
* If the image exists in database, then script ends here and this function will never returns
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function responseFromDB(&$request)
{
$photo = Photo::getPhoto($request['urlhash']);
if ($photo !== false) {
$img = Photo::getImageForPhoto($photo);
self::responseImageHttpCache($img);
// stop.
}
}
/** /**
* In case of an error just stop. We don't return content to avoid caching problems * In case of an error just stop. We don't return content to avoid caching problems
* *

View file

@ -78,7 +78,7 @@ class Acl extends BaseModule
$contacts = []; $contacts = [];
foreach ($result as $contact) { foreach ($result as $contact) {
$contacts[] = [ $contacts[] = [
'photo' => Contact::getMicro($contact, '', true), 'photo' => Contact::getMicro($contact, true),
'name' => htmlspecialchars($contact['name']), 'name' => htmlspecialchars($contact['name']),
'nick' => $contact['addr'] ?: $contact['url'], 'nick' => $contact['addr'] ?: $contact['url'],
'network' => $contact['network'], 'network' => $contact['network'],

View file

@ -111,7 +111,7 @@ class Account extends BaseDataTransferObject
$created = $userContactCreated < $publicContactCreated && ($userContactCreated != DBA::NULL_DATETIME) ? $userContactCreated : $publicContactCreated; $created = $userContactCreated < $publicContactCreated && ($userContactCreated != DBA::NULL_DATETIME) ? $userContactCreated : $publicContactCreated;
$this->created_at = DateTimeFormat::utc($created, DateTimeFormat::JSON); $this->created_at = DateTimeFormat::utc($created, DateTimeFormat::JSON);
$this->note = BBCode::convert($publicContact['about'], false); $this->note = BBCode::convertForUriId($publicContact['uri-id'] ?? 0, $publicContact['about'], BBCode::EXTERNAL);
$this->url = $publicContact['url']; $this->url = $publicContact['url'];
$this->avatar = Contact::getAvatarUrlForId($userContact['id'] ?? 0 ?: $publicContact['id'], Proxy::SIZE_SMALL, $userContact['updated'] ?? '' ?: $publicContact['updated']); $this->avatar = Contact::getAvatarUrlForId($userContact['id'] ?? 0 ?: $publicContact['id'], Proxy::SIZE_SMALL, $userContact['updated'] ?? '' ?: $publicContact['updated']);
$this->avatar_static = $this->avatar; $this->avatar_static = $this->avatar;

View file

@ -131,7 +131,7 @@ class Status extends BaseDataTransferObject
$this->muted = $userAttributes->muted; $this->muted = $userAttributes->muted;
$this->bookmarked = $userAttributes->bookmarked; $this->bookmarked = $userAttributes->bookmarked;
$this->pinned = $userAttributes->pinned; $this->pinned = $userAttributes->pinned;
$this->content = BBCode::convert($item['raw-body'] ?? $item['body'], false, BBCode::API); $this->content = BBCode::convertForUriId($item['uri-id'], ($item['raw-body'] ?? $item['body']), BBCode::EXTERNAL);
$this->reblog = $reblog; $this->reblog = $reblog;
$this->application = $application->toArray(); $this->application = $application->toArray();
$this->account = $account->toArray(); $this->account = $account->toArray();

View file

@ -744,7 +744,7 @@ class Processor
$title = $matches[3]; $title = $matches[3];
} }
$title = trim(HTML::toPlaintext(BBCode::convert($title, false, BBCode::API, true), 0)); $title = trim(BBCode::toPlaintext($title));
if (strlen($title) > 20) { if (strlen($title) > 20) {
$title = substr($title, 0, 20) . '...'; $title = substr($title, 0, 20) . '...';

View file

@ -333,7 +333,8 @@ class Receiver
$object_type = self::fetchObjectType($activity, $object_id, $uid); $object_type = self::fetchObjectType($activity, $object_id, $uid);
// Fetch the content only on activities where this matters // Fetch the content only on activities where this matters
if (in_array($type, ['as:Create', 'as:Update', 'as:Announce'])) { // We can receive "#emojiReaction" when fetching content from Hubzilla systems
if (in_array($type, ['as:Create', 'as:Update', 'as:Announce']) || strpos($type, '#emojiReaction')) {
// Always fetch on "Announce" // Always fetch on "Announce"
$object_data = self::fetchObject($object_id, $activity['as:object'], $trust_source && ($type != 'as:Announce'), $uid); $object_data = self::fetchObject($object_id, $activity['as:object'], $trust_source && ($type != 'as:Announce'), $uid);
if (empty($object_data)) { if (empty($object_data)) {
@ -1344,8 +1345,7 @@ class Receiver
// Some AP software allow formatted text in post location, so we run all the text converters we have to boil // Some AP software allow formatted text in post location, so we run all the text converters we have to boil
// down to HTML and then finally format to plaintext. // down to HTML and then finally format to plaintext.
$location = Markdown::convert($location); $location = Markdown::convert($location);
$location = BBCode::convert($location); $location = BBCode::toPlaintext($location);
$location = HTML::toPlaintext($location);
} }
$object_data['sc:identifier'] = JsonLD::fetchElement($object, 'sc:identifier', '@value'); $object_data['sc:identifier'] = JsonLD::fetchElement($object, 'sc:identifier', '@value');

View file

@ -345,7 +345,7 @@ class Transmitter
} }
if (!empty($owner['about'])) { if (!empty($owner['about'])) {
$data['summary'] = BBCode::convert($owner['about'], false); $data['summary'] = BBCode::convertForUriId($owner['uri-id'], $owner['about'], BBCode::EXTERNAL);
} }
$data['url'] = $owner['url']; $data['url'] = $owner['url'];
@ -1464,7 +1464,7 @@ class Transmitter
{ {
$event = []; $event = [];
$event['name'] = $item['event-summary']; $event['name'] = $item['event-summary'];
$event['content'] = BBCode::convert($item['event-desc'], false, BBCode::ACTIVITYPUB); $event['content'] = BBCode::convertForUriId($item['uri-id'], $item['event-desc'], BBCode::ACTIVITYPUB);
$event['startTime'] = DateTimeFormat::utc($item['event-start'] . '+00:00', DateTimeFormat::ATOM); $event['startTime'] = DateTimeFormat::utc($item['event-start'] . '+00:00', DateTimeFormat::ATOM);
if (!$item['event-nofinish']) { if (!$item['event-nofinish']) {
@ -1571,7 +1571,7 @@ class Transmitter
$regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; $regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
$body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body); $body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body);
$data['content'] = BBCode::convert($body, false, BBCode::ACTIVITYPUB); $data['content'] = BBCode::convertForUriId($item['uri-id'], $body, BBCode::ACTIVITYPUB);
} }
// The regular "content" field does contain a minimized HTML. This is done since systems like // The regular "content" field does contain a minimized HTML. This is done since systems like
@ -1583,7 +1583,7 @@ class Transmitter
$richbody = preg_replace_callback($regexp, ['self', 'mentionCallback'], $item['body']); $richbody = preg_replace_callback($regexp, ['self', 'mentionCallback'], $item['body']);
$richbody = BBCode::removeAttachment($richbody); $richbody = BBCode::removeAttachment($richbody);
$data['contentMap'][$language] = BBCode::convert($richbody, false, BBCode::EXTERNAL); $data['contentMap'][$language] = BBCode::convertForUriId($item['uri-id'], $richbody, BBCode::EXTERNAL);
} }
$data['source'] = ['content' => $item['body'], 'mediaType' => "text/bbcode"]; $data['source'] = ['content' => $item['body'], 'mediaType' => "text/bbcode"];

View file

@ -765,12 +765,13 @@ class DFRN
* @param DOMDocument $doc XML document * @param DOMDocument $doc XML document
* @param string $element Element name for the activity * @param string $element Element name for the activity
* @param string $activity activity value * @param string $activity activity value
* @param int $uriid Uri-Id of the post
* *
* @return \DOMElement XML activity object * @return \DOMElement XML activity object
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @todo Find proper type-hints * @todo Find proper type-hints
*/ */
private static function createActivity(DOMDocument $doc, $element, $activity) private static function createActivity(DOMDocument $doc, $element, $activity, $uriid)
{ {
if ($activity) { if ($activity) {
$entry = $doc->createElement($element); $entry = $doc->createElement($element);
@ -817,7 +818,7 @@ class DFRN
} }
} }
if ($r->content) { if ($r->content) {
XML::addElement($doc, $entry, "content", BBCode::convert($r->content), ["type" => "html"]); XML::addElement($doc, $entry, "content", BBCode::convertForUriId($uriid, $r->content, BBCode::EXTERNAL), ["type" => "html"]);
} }
return $entry; return $entry;
@ -918,7 +919,7 @@ class DFRN
$htmlbody = "[b]" . $item['title'] . "[/b]\n\n" . $htmlbody; $htmlbody = "[b]" . $item['title'] . "[/b]\n\n" . $htmlbody;
} }
$htmlbody = BBCode::convert($htmlbody, false, BBCode::OSTATUS); $htmlbody = BBCode::convertForUriId($item['uri-id'], $htmlbody, BBCode::ACTIVITYPUB);
} }
$author = self::addEntryAuthor($doc, "author", $item["author-link"], $item); $author = self::addEntryAuthor($doc, "author", $item["author-link"], $item);
@ -1033,12 +1034,12 @@ class DFRN
XML::addElement($doc, $entry, "activity:object-type", Activity\ObjectType::COMMENT); XML::addElement($doc, $entry, "activity:object-type", Activity\ObjectType::COMMENT);
} }
$actobj = self::createActivity($doc, "activity:object", $item['object']); $actobj = self::createActivity($doc, "activity:object", $item['object'], $item['uri-id']);
if ($actobj) { if ($actobj) {
$entry->appendChild($actobj); $entry->appendChild($actobj);
} }
$actarg = self::createActivity($doc, "activity:target", $item['target']); $actarg = self::createActivity($doc, "activity:target", $item['target'], $item['uri-id']);
if ($actarg) { if ($actarg) {
$entry->appendChild($actarg); $entry->appendChild($actarg);
} }

View file

@ -1107,9 +1107,9 @@ class Feed
XML::addElement($doc, $entry, "id", $item["uri"]); XML::addElement($doc, $entry, "id", $item["uri"]);
XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8')); XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
$body = OStatus::formatPicturePost($item['body']); $body = OStatus::formatPicturePost($item['body'], $item['uri-id']);
$body = BBCode::convert($body, false, BBCode::OSTATUS); $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::ACTIVITYPUB);
XML::addElement($doc, $entry, "content", $body, ["type" => "html"]); XML::addElement($doc, $entry, "content", $body, ["type" => "html"]);
@ -1186,7 +1186,7 @@ class Feed
private static function getTitle(array $item) private static function getTitle(array $item)
{ {
if ($item['title'] != '') { if ($item['title'] != '') {
return BBCode::convert($item['title'], false, BBCode::OSTATUS); return BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::ACTIVITYPUB);
} }
// Fetch information about the post // Fetch information about the post
@ -1199,7 +1199,7 @@ class Feed
// Remove the share element before fetching the first line // Remove the share element before fetching the first line
$title = trim(preg_replace("/\[share.*?\](.*?)\[\/share\]/ism","\n$1\n",$item['body'])); $title = trim(preg_replace("/\[share.*?\](.*?)\[\/share\]/ism","\n$1\n",$item['body']));
$title = HTML::toPlaintext(BBCode::convert($title, false), 0, true)."\n"; $title = BBCode::toPlaintext($title)."\n";
$pos = strpos($title, "\n"); $pos = strpos($title, "\n");
$trailer = ""; $trailer = "";
if (($pos == 0) || ($pos > 100)) { if (($pos == 0) || ($pos > 100)) {

View file

@ -1195,7 +1195,7 @@ class OStatus
* @return string The cleaned body * @return string The cleaned body
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function formatPicturePost($body) public static function formatPicturePost($body, $uriid)
{ {
$siteinfo = BBCode::getAttachedData($body); $siteinfo = BBCode::getAttachedData($body);
@ -1207,7 +1207,7 @@ class OStatus
} }
// Is it a remote picture? Then make a smaller preview here // Is it a remote picture? Then make a smaller preview here
$preview = ProxyUtils::proxifyUrl($preview, false, ProxyUtils::SIZE_SMALL); $preview = Post\Link::getByLink($uriid, $preview, ProxyUtils::SIZE_SMALL);
// Is it a local picture? Then make it smaller here // Is it a local picture? Then make it smaller here
$preview = str_replace(["-0.jpg", "-0.png"], ["-2.jpg", "-2.png"], $preview); $preview = str_replace(["-0.jpg", "-0.png"], ["-2.jpg", "-2.png"], $preview);
@ -1418,7 +1418,7 @@ class OStatus
XML::addElement($doc, $author, "name", $owner["nick"]); XML::addElement($doc, $author, "name", $owner["nick"]);
XML::addElement($doc, $author, "email", $owner["addr"]); XML::addElement($doc, $author, "email", $owner["addr"]);
if ($show_profile) { if ($show_profile) {
XML::addElement($doc, $author, "summary", BBCode::convert($owner["about"], false, BBCode::OSTATUS)); XML::addElement($doc, $author, "summary", BBCode::convertForUriId($owner['uri-id'], $owner["about"], BBCode::OSTATUS));
} }
$attributes = ["rel" => "alternate", "type" => "text/html", "href" => $owner["url"]]; $attributes = ["rel" => "alternate", "type" => "text/html", "href" => $owner["url"]];
@ -1445,7 +1445,7 @@ class OStatus
XML::addElement($doc, $author, "poco:preferredUsername", $owner["nick"]); XML::addElement($doc, $author, "poco:preferredUsername", $owner["nick"]);
XML::addElement($doc, $author, "poco:displayName", $owner["name"]); XML::addElement($doc, $author, "poco:displayName", $owner["name"]);
if ($show_profile) { if ($show_profile) {
XML::addElement($doc, $author, "poco:note", BBCode::convert($owner["about"], false, BBCode::OSTATUS)); XML::addElement($doc, $author, "poco:note", BBCode::convertForUriId($owner['uri-id'], $owner["about"], BBCode::OSTATUS));
if (trim($owner["location"]) != "") { if (trim($owner["location"]) != "") {
$element = $doc->createElement("poco:address"); $element = $doc->createElement("poco:address");
@ -1803,7 +1803,7 @@ class OStatus
if (!$toplevel) { if (!$toplevel) {
if (!empty($item['title'])) { if (!empty($item['title'])) {
$title = BBCode::convert($item['title'], false, BBCode::OSTATUS); $title = BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::OSTATUS);
} else { } else {
$title = sprintf("New note by %s", $owner["nick"]); $title = sprintf("New note by %s", $owner["nick"]);
} }
@ -1886,13 +1886,13 @@ class OStatus
XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8')); XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
$body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']); $body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']);
$body = self::formatPicturePost($body); $body = self::formatPicturePost($body, $item['uri-id']);
if (!empty($item['title'])) { if (!empty($item['title'])) {
$body = "[b]".$item['title']."[/b]\n\n".$body; $body = "[b]".$item['title']."[/b]\n\n".$body;
} }
$body = BBCode::convert($body, false, BBCode::OSTATUS); $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::OSTATUS);
XML::addElement($doc, $entry, "content", $body, ["type" => "html"]); XML::addElement($doc, $entry, "content", $body, ["type" => "html"]);

View file

@ -193,18 +193,7 @@ class Images
$filesize = strlen($img_str); $filesize = strlen($img_str);
try { try {
if (function_exists("getimagesizefromstring")) {
$data = @getimagesizefromstring($img_str); $data = @getimagesizefromstring($img_str);
} else {
$tempfile = tempnam(get_temppath(), "cache");
$stamp1 = microtime(true);
file_put_contents($tempfile, $img_str);
DI::profiler()->saveTimestamp($stamp1, "file");
$data = getimagesize($tempfile);
unlink($tempfile);
}
} catch (\Exception $e) { } catch (\Exception $e) {
return []; return [];
} }

View file

@ -21,6 +21,8 @@
namespace Friendica\Util; namespace Friendica\Util;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\DI; use Friendica\DI;
/** /**
@ -28,12 +30,6 @@ use Friendica\DI;
*/ */
class Proxy class Proxy
{ {
/**
* Default time to keep images in proxy storage
*/
const DEFAULT_TIME = 86400; // 1 Day
/** /**
* Sizes constants * Sizes constants
*/ */
@ -76,55 +72,30 @@ class Proxy
* Transform a remote URL into a local one. * Transform a remote URL into a local one.
* *
* This function only performs the URL replacement on http URL and if the * This function only performs the URL replacement on http URL and if the
* provided URL isn't local, "the isn't deactivated" (sic) and if the config * provided URL isn't local
* system.proxy_disabled is set to false.
* *
* @param string $url The URL to proxyfy * @param string $url The URL to proxyfy
* @param bool $writemode Returns a local path the remote URL should be saved to
* @param string $size One of the ProxyUtils::SIZE_* constants * @param string $size One of the ProxyUtils::SIZE_* constants
* *
* @return string The proxyfied URL or relative path * @return string The proxyfied URL or relative path
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function proxifyUrl($url, $writemode = false, $size = '') public static function proxifyUrl($url, $size = '')
{ {
// Get application instance
$a = DI::app();
// Trim URL first // Trim URL first
$url = trim($url); $url = trim($url);
// Is no http in front of it? // Quit if not an HTTP/HTTPS link or if local
/// @TODO To weak test for being a valid URL if (!in_array(parse_url($url, PHP_URL_SCHEME), ['http', 'https']) || self::isLocalImage($url)) {
if (substr($url, 0, 4) !== 'http') {
return $url;
}
// Only continue if it isn't a local image and the isn't deactivated
if (self::isLocalImage($url)) {
$url = str_replace(Strings::normaliseLink(DI::baseUrl()) . '/', DI::baseUrl() . '/', $url);
return $url;
}
// Is the proxy disabled?
if (DI::config()->get('system', 'proxy_disabled')) {
return $url; return $url;
} }
// Image URL may have encoded ampersands for display which aren't desirable for proxy // Image URL may have encoded ampersands for display which aren't desirable for proxy
$url = html_entity_decode($url, ENT_NOQUOTES, 'utf-8'); $url = html_entity_decode($url, ENT_NOQUOTES, 'utf-8');
// Creating a sub directory to reduce the amount of files in the cache directory
$basepath = $a->getBasePath() . '/proxy';
$shortpath = hash('md5', $url); $shortpath = hash('md5', $url);
$longpath = substr($shortpath, 0, 2); $longpath = substr($shortpath, 0, 2);
if (is_dir($basepath) && $writemode && !is_dir($basepath . '/' . $longpath)) {
mkdir($basepath . '/' . $longpath);
chmod($basepath . '/' . $longpath, 0777);
}
$longpath .= '/' . strtr(base64_encode($url), '+/', '-_'); $longpath .= '/' . strtr(base64_encode($url), '+/', '-_');
// Extract the URL extension // Extract the URL extension
@ -141,14 +112,11 @@ class Proxy
$size = ':' . $size; $size = ':' . $size;
} }
Logger::info('Created proxy link', ['url' => $url, 'callstack' => System::callstack(20)]);
// Too long files aren't supported by Apache // Too long files aren't supported by Apache
// Writemode in combination with long files shouldn't be possible if (strlen($proxypath) > 250) {
if ((strlen($proxypath) > 250) && $writemode) {
return $shortpath;
} elseif (strlen($proxypath) > 250) {
return DI::baseUrl() . '/proxy/' . $shortpath . '?url=' . urlencode($url); return DI::baseUrl() . '/proxy/' . $shortpath . '?url=' . urlencode($url);
} elseif ($writemode) {
return $longpath;
} else { } else {
return $proxypath . $size; return $proxypath . $size;
} }
@ -189,11 +157,7 @@ class Proxy
return true; return true;
} }
// links normalised - bug #431 return Network::isLocalLink($url);
$baseurl = Strings::normaliseLink(DI::baseUrl());
$url = Strings::normaliseLink($url);
return (substr($url, 0, strlen($baseurl)) == $baseurl);
} }
/** /**

View file

@ -38,29 +38,6 @@ class ClearCache
// clear old cache // clear old cache
DI::cache()->clear(); DI::cache()->clear();
// clear old item cache files
clear_cache();
// clear cache for photos
clear_cache($a->getBasePath(), $a->getBasePath() . "/photo");
// clear smarty cache
clear_cache($a->getBasePath() . "/view/smarty3/compiled", $a->getBasePath() . "/view/smarty3/compiled");
// clear cache for image proxy
if (!DI::config()->get("system", "proxy_disabled")) {
clear_cache($a->getBasePath(), $a->getBasePath() . "/proxy");
$cachetime = DI::config()->get('system', 'proxy_cache_time');
if (!$cachetime) {
$cachetime = ProxyUtils::DEFAULT_TIME;
}
$condition = ['`uid` = 0 AND `resource-id` LIKE "pic:%" AND `created` < NOW() - INTERVAL ? SECOND', $cachetime];
Photo::delete($condition);
}
// Delete the cached OEmbed entries that are older than three month // Delete the cached OEmbed entries that are older than three month
DBA::delete('oembed', ["`created` < NOW() - INTERVAL 3 MONTH"]); DBA::delete('oembed', ["`created` < NOW() - INTERVAL 3 MONTH"]);

View file

@ -183,6 +183,10 @@ class ExpirePosts
AND NOT EXISTS(SELECT `thr-parent-id` FROM `post-user` WHERE `thr-parent-id` = `item-uri`.`id`) AND NOT EXISTS(SELECT `thr-parent-id` FROM `post-user` WHERE `thr-parent-id` = `item-uri`.`id`)
AND NOT EXISTS(SELECT `external-id` FROM `post-user` WHERE `external-id` = `item-uri`.`id`) 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 `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 `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 `parent-uri-id` FROM `mail` WHERE `parent-uri-id` = `item-uri`.`id`) AND NOT EXISTS(SELECT `parent-uri-id` FROM `mail` WHERE `parent-uri-id` = `item-uri`.`id`)
AND NOT EXISTS(SELECT `thr-parent-id` FROM `mail` WHERE `thr-parent-id` = `item-uri`.`id`)", $item['uri-id']]); AND NOT EXISTS(SELECT `thr-parent-id` FROM `mail` WHERE `thr-parent-id` = `item-uri`.`id`)", $item['uri-id']]);

View file

@ -55,7 +55,7 @@
use Friendica\Database\DBA; use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) { if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1424); define('DB_UPDATE_VERSION', 1428);
} }
return [ return [
@ -152,6 +152,19 @@ return [
"email" => ["email(64)"], "email" => ["email(64)"],
] ]
], ],
"item-uri" => [
"comment" => "URI and GUID for items",
"fields" => [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"],
"uri" => ["type" => "varbinary(255)", "not null" => "1", "comment" => "URI of an item"],
"guid" => ["type" => "varbinary(255)", "comment" => "A unique identifier for an item"]
],
"indexes" => [
"PRIMARY" => ["id"],
"uri" => ["UNIQUE", "uri"],
"guid" => ["guid"]
]
],
"contact" => [ "contact" => [
"comment" => "contact table", "comment" => "contact table",
"fields" => [ "fields" => [
@ -183,6 +196,7 @@ return [
"dfrn-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "dfrn-id" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"nurl" => ["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"],
"addr" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "addr" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"alias" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "alias" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"pubkey" => ["type" => "text", "comment" => "RSA public key 4096 bit"], "pubkey" => ["type" => "text", "comment" => "RSA public key 4096 bit"],
@ -260,20 +274,8 @@ return [
"uid_contact-type" => ["uid", "contact-type"], "uid_contact-type" => ["uid", "contact-type"],
"uid_self_contact-type" => ["uid", "self", "contact-type"], "uid_self_contact-type" => ["uid", "self", "contact-type"],
"self_network_uid" => ["self", "network", "uid"], "self_network_uid" => ["self", "network", "uid"],
"gsid" => ["gsid"] "gsid" => ["gsid"],
] "uri-id" => ["uri-id"],
],
"item-uri" => [
"comment" => "URI and GUID for items",
"fields" => [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"],
"uri" => ["type" => "varbinary(255)", "not null" => "1", "comment" => "URI of an item"],
"guid" => ["type" => "varbinary(255)", "comment" => "A unique identifier for an item"]
],
"indexes" => [
"PRIMARY" => ["id"],
"uri" => ["UNIQUE", "uri"],
"guid" => ["guid"]
] ]
], ],
"tag" => [ "tag" => [
@ -393,6 +395,7 @@ return [
"comment" => "ActivityPub compatible contacts - used in the ActivityPub implementation", "comment" => "ActivityPub compatible contacts - used in the ActivityPub implementation",
"fields" => [ "fields" => [
"url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "URL of the contact"], "url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "URL of the contact"],
"uri-id" => ["type" => "int unsigned", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the apcontact url"],
"uuid" => ["type" => "varchar(255)", "comment" => ""], "uuid" => ["type" => "varchar(255)", "comment" => ""],
"type" => ["type" => "varchar(20)", "not null" => "1", "comment" => ""], "type" => ["type" => "varchar(20)", "not null" => "1", "comment" => ""],
"following" => ["type" => "varchar(255)", "comment" => ""], "following" => ["type" => "varchar(255)", "comment" => ""],
@ -426,7 +429,8 @@ return [
"followers" => ["followers(190)"], "followers" => ["followers(190)"],
"baseurl" => ["baseurl(190)"], "baseurl" => ["baseurl(190)"],
"sharedinbox" => ["sharedinbox(190)"], "sharedinbox" => ["sharedinbox(190)"],
"gsid" => ["gsid"] "gsid" => ["gsid"],
"uri-id" => ["UNIQUE", "uri-id"],
] ]
], ],
"application" => [ "application" => [
@ -628,6 +632,7 @@ return [
"uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner User id"], "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner User id"],
"cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["contact" => "id"], "comment" => "contact_id (ID of the contact in contact table)"], "cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["contact" => "id"], "comment" => "contact_id (ID of the contact in contact table)"],
"uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "uri" => ["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 event uri"],
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "creation time"], "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "creation time"],
"edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "last edit time"], "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "last edit time"],
"start" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "event start time"], "start" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "event start time"],
@ -648,6 +653,7 @@ return [
"PRIMARY" => ["id"], "PRIMARY" => ["id"],
"uid_start" => ["uid", "start"], "uid_start" => ["uid", "start"],
"cid" => ["cid"], "cid" => ["cid"],
"uri-id" => ["uri-id"],
] ]
], ],
"fcontact" => [ "fcontact" => [
@ -656,6 +662,7 @@ return [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
"guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "unique id"], "guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "unique id"],
"url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "url" => ["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 fcontact url"],
"name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"request" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "request" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
@ -675,6 +682,7 @@ return [
"PRIMARY" => ["id"], "PRIMARY" => ["id"],
"addr" => ["addr(32)"], "addr" => ["addr(32)"],
"url" => ["UNIQUE", "url(190)"], "url" => ["UNIQUE", "url(190)"],
"uri-id" => ["UNIQUE", "uri-id"],
] ]
], ],
"fsuggest" => [ "fsuggest" => [
@ -1151,6 +1159,19 @@ return [
"PRIMARY" => ["uri-id"], "PRIMARY" => ["uri-id"],
] ]
], ],
"post-link" => [
"comment" => "Post related external links",
"fields" => [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
"uri-id" => ["type" => "int unsigned", "not null" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the item uri"],
"url" => ["type" => "varbinary(511)", "not null" => "1", "comment" => "External URL"],
"mimetype" => ["type" => "varchar(60)", "comment" => ""],
],
"indexes" => [
"PRIMARY" => ["id"],
"uri-id-url" => ["UNIQUE", "uri-id", "url"],
]
],
"post-media" => [ "post-media" => [
"comment" => "Attached media", "comment" => "Attached media",
"fields" => [ "fields" => [
@ -1311,6 +1332,7 @@ return [
"post-user-id" => ["post-user-id"], "post-user-id" => ["post-user-id"],
"commented" => ["commented"], "commented" => ["commented"],
"uid_received" => ["uid", "received"], "uid_received" => ["uid", "received"],
"uid_wall_received" => ["uid", "wall", "received"],
"uid_pinned" => ["uid", "pinned"], "uid_pinned" => ["uid", "pinned"],
"uid_commented" => ["uid", "commented"], "uid_commented" => ["uid", "commented"],
"uid_starred" => ["uid", "starred"], "uid_starred" => ["uid", "starred"],

View file

@ -729,6 +729,7 @@
"dfrn-id" => ["contact", "dfrn-id"], "dfrn-id" => ["contact", "dfrn-id"],
"url" => ["contact", "url"], "url" => ["contact", "url"],
"nurl" => ["contact", "nurl"], "nurl" => ["contact", "nurl"],
"uri-id" => ["contact", "uri-id"],
"addr" => ["contact", "addr"], "addr" => ["contact", "addr"],
"alias" => ["contact", "alias"], "alias" => ["contact", "alias"],
"pubkey" => ["contact", "pubkey"], "pubkey" => ["contact", "pubkey"],
@ -833,6 +834,185 @@
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self` INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`" INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid`"
], ],
"account-view" => [
"fields" => [
"id" => ["contact", "id"],
"url" => ["contact", "url"],
"nurl" => ["contact", "nurl"],
"uri-id" => ["contact", "uri-id"],
"addr" => ["contact", "addr"],
"alias" => ["contact", "alias"],
"name" => ["contact", "name"],
"nick" => ["contact", "nick"],
"about" => ["contact", "about"],
"keywords" => ["contact", "keywords"],
"xmpp" => ["contact", "xmpp"],
"avatar" => ["contact", "avatar"],
"photo" => ["contact", "photo"],
"thumb" => ["contact", "thumb"],
"micro" => ["contact", "micro"],
"header" => ["contact", "header"],
"created" => ["contact", "created"],
"updated" => ["contact", "updated"],
"network" => ["contact", "network"],
"protocol" => ["contact", "protocol"],
"location" => ["contact", "location"],
"attag" => ["contact", "attag"],
"pubkey" => ["contact", "pubkey"],
"prvkey" => ["contact", "prvkey"],
"subscribe" => ["contact", "subscribe"],
"last-update" => ["contact", "last-update"],
"success_update" => ["contact", "success_update"],
"failure_update" => ["contact", "failure_update"],
"failed" => ["contact", "failed"],
"last-item" => ["contact", "last-item"],
"last-discovery" => ["contact", "last-discovery"],
"contact-type" => ["contact", "contact-type"],
"manually-approve" => ["contact", "manually-approve"],
"unsearchable" => ["contact", "unsearchable"],
"sensitive" => ["contact", "sensitive"],
"baseurl" => ["contact", "baseurl"],
"gsid" => ["contact", "gsid"],
"info" => ["contact", "info"],
"bdyear" => ["contact", "bdyear"],
"bd" => ["contact", "bd"],
"poco" => ["contact", "poco"],
"name-date" => ["contact", "name-date"],
"uri-date" => ["contact", "uri-date"],
"avatar-date" => ["contact", "avatar-date"],
"term-date" => ["contact", "term-date"],
"global-ignored" => ["contact", "hidden"],
"global-blocked" => ["contact", "blocked"],
"hidden" => ["contact", "hidden"],
"archive" => ["contact", "archive"],
"deleted" => ["contact", "deleted"],
"blocked" => ["contact", "blocked"],
"dfrn-request" => ["contact", "request"],
"dfrn-notify" => ["contact", "notify"],
"dfrn-poll" => ["contact", "poll"],
"dfrn-confirm" => ["contact", "confirm"],
"diaspora-guid" => ["fcontact", "guid"],
"diaspora-batch" => ["fcontact", "batch"],
"diaspora-notify" => ["fcontact", "notify"],
"diaspora-poll" => ["fcontact", "poll"],
"diaspora-alias" => ["fcontact", "alias"],
"ap-uuid" => ["apcontact", "uuid"],
"ap-type" => ["apcontact", "type"],
"ap-following" => ["apcontact", "following"],
"ap-followers" => ["apcontact", "followers"],
"ap-inbox" => ["apcontact", "inbox"],
"ap-outbox" => ["apcontact", "outbox"],
"ap-sharedinbox" => ["apcontact", "sharedinbox"],
"ap-generator" => ["apcontact", "generator"],
"ap-following_count" => ["apcontact", "following_count"],
"ap-followers_count" => ["apcontact", "followers_count"],
"ap-statuses_count" => ["apcontact", "statuses_count"],
],
"query" => "FROM `contact`
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `contact`.`uri-id`
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = contact.`uri-id`
WHERE `contact`.`uid` = 0"
],
"account-user-view" => [
"fields" => [
"id" => ["ucontact", "id"],
"pid" => ["contact", "id"],
"uid" => ["ucontact", "uid"],
"url" => ["contact", "url"],
"nurl" => ["contact", "nurl"],
"uri-id" => ["contact", "uri-id"],
"addr" => ["contact", "addr"],
"alias" => ["contact", "alias"],
"name" => ["contact", "name"],
"nick" => ["contact", "nick"],
"about" => ["contact", "about"],
"keywords" => ["contact", "keywords"],
"xmpp" => ["contact", "xmpp"],
"avatar" => ["contact", "avatar"],
"photo" => ["contact", "photo"],
"thumb" => ["contact", "thumb"],
"micro" => ["contact", "micro"],
"header" => ["contact", "header"],
"created" => ["contact", "created"],
"updated" => ["contact", "updated"],
"self" => ["ucontact", "self"],
"remote_self" => ["ucontact", "remote_self"],
"rel" => ["ucontact", "rel"],
"network" => ["contact", "network"],
"protocol" => ["ucontact", "protocol"],
"location" => ["contact", "location"],
"attag" => ["contact", "attag"],
"pubkey" => ["contact", "pubkey"],
"prvkey" => ["contact", "prvkey"],
"subscribe" => ["contact", "subscribe"],
"last-update" => ["contact", "last-update"],
"success_update" => ["contact", "success_update"],
"failure_update" => ["contact", "failure_update"],
"failed" => ["contact", "failed"],
"last-item" => ["contact", "last-item"],
"last-discovery" => ["contact", "last-discovery"],
"contact-type" => ["contact", "contact-type"],
"manually-approve" => ["contact", "manually-approve"],
"unsearchable" => ["contact", "unsearchable"],
"sensitive" => ["contact", "sensitive"],
"baseurl" => ["contact", "baseurl"],
"gsid" => ["contact", "gsid"],
"info" => ["contact", "info"],
"bdyear" => ["contact", "bdyear"],
"bd" => ["contact", "bd"],
"poco" => ["contact", "poco"],
"name-date" => ["contact", "name-date"],
"uri-date" => ["contact", "uri-date"],
"avatar-date" => ["contact", "avatar-date"],
"term-date" => ["contact", "term-date"],
"global-ignored" => ["contact", "hidden"],
"global-blocked" => ["contact", "blocked"],
"hidden" => ["ucontact", "hidden"],
"archive" => ["ucontact", "archive"],
"pending" => ["ucontact", "pending"],
"deleted" => ["ucontact", "deleted"],
"notify_new_posts" => ["ucontact", "notify_new_posts"],
"fetch_further_information" => ["ucontact", "fetch_further_information"],
"ffi_keyword_denylist" => ["ucontact", "ffi_keyword_denylist"],
"rating" => ["ucontact", "rating"],
"readonly" => ["ucontact", "readonly"],
"blocked" => ["ucontact", "blocked"],
"block_reason" => ["ucontact", "block_reason"],
"subhub" => ["ucontact", "subhub"],
"hub-verify" => ["ucontact", "hub-verify"],
"reason" => ["ucontact", "reason"],
"dfrn-duplex" => ["ucontact", "duplex"],
"dfrn-ret-aes" => ["ucontact", "ret-aes"],
"dfrn-site-pubkey" => ["ucontact", "site-pubkey"],
"dfrn-issued-id" => ["ucontact", "issued-id"],
"dfrn-id" => ["ucontact", "dfrn-id"],
"dfrn-aes_allow" => ["ucontact", "aes_allow"],
"dfrn-request" => ["contact", "request"],
"dfrn-notify" => ["contact", "notify"],
"dfrn-poll" => ["contact", "poll"],
"dfrn-confirm" => ["contact", "confirm"],
"diaspora-guid" => ["fcontact", "guid"],
"diaspora-batch" => ["fcontact", "batch"],
"diaspora-notify" => ["fcontact", "notify"],
"diaspora-poll" => ["fcontact", "poll"],
"diaspora-alias" => ["fcontact", "alias"],
"ap-uuid" => ["apcontact", "uuid"],
"ap-type" => ["apcontact", "type"],
"ap-following" => ["apcontact", "following"],
"ap-followers" => ["apcontact", "followers"],
"ap-inbox" => ["apcontact", "inbox"],
"ap-outbox" => ["apcontact", "outbox"],
"ap-sharedinbox" => ["apcontact", "sharedinbox"],
"ap-generator" => ["apcontact", "generator"],
"ap-following_count" => ["apcontact", "following_count"],
"ap-followers_count" => ["apcontact", "followers_count"],
"ap-statuses_count" => ["apcontact", "statuses_count"],
],
"query" => "FROM `contact` AS `ucontact`
INNER JOIN `contact` ON `contact`.`uri-id` = `ucontact`.`uri-id` AND `contact`.`uid` = 0
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `ucontact`.`uri-id`
LEFT JOIN `fcontact` ON `fcontact`.`uri-id` = `ucontact`.`uri-id` AND `fcontact`.`network` = 'dspr'"
],
"pending-view" => [ "pending-view" => [
"fields" => [ "fields" => [
"id" => ["register", "id"], "id" => ["register", "id"],

View file

@ -570,10 +570,6 @@ return [
// xrd_timeout (Integer) // xrd_timeout (Integer)
// Timeout in seconds for fetching the XRD links. // Timeout in seconds for fetching the XRD links.
'xrd_timeout' => 20, 'xrd_timeout' => 20,
// proxy_file_chmod (Octal Integer like 0640)
// If set, defines the files permissions for downloaded files in the /proxy/ directory, default is system-dependent
'proxy_file_chmod' => 0,
], ],
'experimental' => [ 'experimental' => [
// exp_themes (Boolean) // exp_themes (Boolean)

View file

@ -71,95 +71,6 @@ return [
'theme' => 'frio', 'theme' => 'frio',
], ],
], ],
'contact' => [
[
'id' => 42,
'uid' => 42,
'name' => 'Self contact',
'nick' => 'selfcontact',
'self' => 1,
'nurl' => 'http://localhost/profile/selfcontact',
'url' => 'http://localhost/profile/selfcontact',
'about' => 'User used in tests',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::FOLLOWER,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
// Having the same name and nick allows us to test
// the fallback to api_get_nick() in api_get_user()
[
'id' => 43,
'uid' => 0,
'name' => 'othercontact',
'nick' => 'othercontact',
'self' => 0,
'nurl' => 'http://localhost/profile/othercontact',
'url' => 'http://localhost/profile/othercontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::NOTHING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 44,
'uid' => 42,
'name' => 'Friend contact',
'nick' => 'friendcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/friendcontact',
'url' => 'http://localhost/profile/friendcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::SHARING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 45,
'uid' => 0,
'name' => 'Friend contact',
'nick' => 'friendcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/friendcontact',
'url' => 'http://localhost/profile/friendcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::SHARING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 46,
'uid' => 42,
'name' => 'Mutual contact',
'nick' => 'mutualcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/mutualcontact',
'url' => 'http://localhost/profile/mutualcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::FRIEND,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 47,
'uid' => 0,
'name' => 'Mutual contact',
'nick' => 'mutualcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/mutualcontact',
'url' => 'http://localhost/profile/mutualcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::SHARING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
],
'item-uri' => [ 'item-uri' => [
[ [
'id' => 1, 'id' => 1,
@ -191,6 +102,122 @@ return [
'uri' => '6', 'uri' => '6',
'guid' => '6', 'guid' => '6',
], ],
[
'id' => 42,
'uri' => 'http://localhost/profile/selfcontact',
'guid' => '42',
],
[
'id' => 43,
'uri' => 'http://localhost/profile/othercontact',
'guid' => '43',
],
[
'id' => 44,
'uri' => 'http://localhost/profile/friendcontact',
'guid' => '44',
],
[
'id' => 46,
'uri' => 'http://localhost/profile/mutualcontact',
'guid' => '46',
],
],
'contact' => [
[
'id' => 42,
'uid' => 42,
'uri-id' => 42,
'name' => 'Self contact',
'nick' => 'selfcontact',
'self' => 1,
'nurl' => 'http://localhost/profile/selfcontact',
'url' => 'http://localhost/profile/selfcontact',
'about' => 'User used in tests',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::FOLLOWER,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
// Having the same name and nick allows us to test
// the fallback to api_get_nick() in api_get_user()
[
'id' => 43,
'uid' => 0,
'uri-id' => 43,
'name' => 'othercontact',
'nick' => 'othercontact',
'self' => 0,
'nurl' => 'http://localhost/profile/othercontact',
'url' => 'http://localhost/profile/othercontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::NOTHING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 44,
'uid' => 42,
'uri-id' => 44,
'name' => 'Friend contact',
'nick' => 'friendcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/friendcontact',
'url' => 'http://localhost/profile/friendcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::SHARING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 45,
'uid' => 0,
'uri-id' => 44,
'name' => 'Friend contact',
'nick' => 'friendcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/friendcontact',
'url' => 'http://localhost/profile/friendcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::SHARING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 46,
'uid' => 42,
'uri-id' => 46,
'name' => 'Mutual contact',
'nick' => 'mutualcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/mutualcontact',
'url' => 'http://localhost/profile/mutualcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::FRIEND,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
[
'id' => 47,
'uid' => 0,
'uri-id' => 46,
'name' => 'Mutual contact',
'nick' => 'mutualcontact',
'self' => 0,
'nurl' => 'http://localhost/profile/mutualcontact',
'url' => 'http://localhost/profile/mutualcontact',
'pending' => 0,
'blocked' => 0,
'rel' => Contact::SHARING,
'network' => Protocol::DFRN,
'location' => 'DFRN',
],
], ],
'verb' => [ 'verb' => [
[ [

View file

@ -33,10 +33,18 @@ return [
'theme' => 'frio', 'theme' => 'frio',
], ],
], ],
'item-uri' => [
[
'id' => 42,
'uri' => 'http://localhost/profile/selfcontact',
'guid' => '42',
],
],
'contact' => [ 'contact' => [
[ [
'id' => 42, 'id' => 42,
'uid' => 42, 'uid' => 42,
'uri-id' => 42,
'name' => 'Self contact', 'name' => 'Self contact',
'nick' => 'selfcontact', 'nick' => 'selfcontact',
'self' => 1, 'self' => 1,

View file

@ -2192,9 +2192,9 @@ class ApiTest extends FixtureTest
public function testApiFormatMessages() public function testApiFormatMessages()
{ {
$result = api_format_messages( $result = api_format_messages(
['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], ['id' => 1, 'uri-id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 2, 'uri-id' => 2, 'screen_name' => 'recipient_name'],
['id' => 3, 'screen_name' => 'sender_name'] ['id' => 3, 'uri-id' => 2, 'screen_name' => 'sender_name']
); );
self::assertEquals('item_title' . "\n" . 'item_body', $result['text']); self::assertEquals('item_title' . "\n" . 'item_body', $result['text']);
self::assertEquals(1, $result['id']); self::assertEquals(1, $result['id']);
@ -2213,9 +2213,9 @@ class ApiTest extends FixtureTest
{ {
$_GET['getText'] = 'html'; $_GET['getText'] = 'html';
$result = api_format_messages( $result = api_format_messages(
['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], ['id' => 1, 'uri-id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 2, 'uri-id' => 2, 'screen_name' => 'recipient_name'],
['id' => 3, 'screen_name' => 'sender_name'] ['id' => 3, 'uri-id' => 3, 'screen_name' => 'sender_name']
); );
self::assertEquals('item_title', $result['title']); self::assertEquals('item_title', $result['title']);
self::assertEquals('<strong>item_body</strong>', $result['text']); self::assertEquals('<strong>item_body</strong>', $result['text']);
@ -2230,9 +2230,9 @@ class ApiTest extends FixtureTest
{ {
$_GET['getText'] = 'plain'; $_GET['getText'] = 'plain';
$result = api_format_messages( $result = api_format_messages(
['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], ['id' => 1, 'uri-id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 2, 'uri-id' => 2, 'screen_name' => 'recipient_name'],
['id' => 3, 'screen_name' => 'sender_name'] ['id' => 3, 'uri-id' => 3, 'screen_name' => 'sender_name']
); );
self::assertEquals('item_title', $result['title']); self::assertEquals('item_title', $result['title']);
self::assertEquals('item_body', $result['text']); self::assertEquals('item_body', $result['text']);
@ -2247,9 +2247,9 @@ class ApiTest extends FixtureTest
{ {
$_GET['getUserObjects'] = 'false'; $_GET['getUserObjects'] = 'false';
$result = api_format_messages( $result = api_format_messages(
['id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'], ['id' => 1, 'uri-id' => 1, 'title' => 'item_title', 'body' => '[b]item_body[/b]'],
['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 2, 'uri-id' => 2, 'screen_name' => 'recipient_name'],
['id' => 3, 'screen_name' => 'sender_name'] ['id' => 3, 'uri-id' => 3, 'screen_name' => 'sender_name']
); );
self::assertTrue(!isset($result['sender'])); self::assertTrue(!isset($result['sender']));
self::assertTrue(!isset($result['recipient'])); self::assertTrue(!isset($result['recipient']));
@ -2344,7 +2344,7 @@ class ApiTest extends FixtureTest
public function testApiGetAttachments() public function testApiGetAttachments()
{ {
$body = 'body'; $body = 'body';
self::assertEmpty(api_get_attachments($body)); self::assertEmpty(api_get_attachments($body, 0));
} }
/** /**
@ -2355,7 +2355,7 @@ class ApiTest extends FixtureTest
public function testApiGetAttachmentsWithImage() public function testApiGetAttachmentsWithImage()
{ {
$body = '[img]http://via.placeholder.com/1x1.png[/img]'; $body = '[img]http://via.placeholder.com/1x1.png[/img]';
self::assertIsArray(api_get_attachments($body)); self::assertIsArray(api_get_attachments($body, 0));
} }
/** /**
@ -2367,7 +2367,7 @@ class ApiTest extends FixtureTest
{ {
$_SERVER['HTTP_USER_AGENT'] = 'AndStatus'; $_SERVER['HTTP_USER_AGENT'] = 'AndStatus';
$body = '[img]http://via.placeholder.com/1x1.png[/img]'; $body = '[img]http://via.placeholder.com/1x1.png[/img]';
self::assertIsArray(api_get_attachments($body)); self::assertIsArray(api_get_attachments($body, 0));
} }
/** /**
@ -2378,7 +2378,7 @@ class ApiTest extends FixtureTest
public function testApiGetEntitities() public function testApiGetEntitities()
{ {
$text = 'text'; $text = 'text';
self::assertIsArray(api_get_entitities($text, 'bbcode')); self::assertIsArray(api_get_entitities($text, 'bbcode', 0));
} }
/** /**
@ -2390,7 +2390,7 @@ class ApiTest extends FixtureTest
{ {
$_REQUEST['include_entities'] = 'true'; $_REQUEST['include_entities'] = 'true';
$text = 'text'; $text = 'text';
$result = api_get_entitities($text, 'bbcode'); $result = api_get_entitities($text, 'bbcode', 0);
self::assertIsArray($result['hashtags']); self::assertIsArray($result['hashtags']);
self::assertIsArray($result['symbols']); self::assertIsArray($result['symbols']);
self::assertIsArray($result['urls']); self::assertIsArray($result['urls']);

View file

@ -51,9 +51,6 @@ class BBCodeTest extends MockedTest
$this->configMock->shouldReceive('get') $this->configMock->shouldReceive('get')
->with('system', 'allowed_link_protocols') ->with('system', 'allowed_link_protocols')
->andReturn(null); ->andReturn(null);
$this->configMock->shouldReceive('get')
->with('system', 'itemcache_duration')
->andReturn(-1);
$this->configMock->shouldReceive('get') $this->configMock->shouldReceive('get')
->with('system', 'url') ->with('system', 'url')
->andReturn('friendica.local'); ->andReturn('friendica.local');

View file

@ -151,13 +151,36 @@ span.connector {
} }
/* Shared Messages */ /* Shared Messages */
.shared_header { .shared_header {
display: flex;
justify-content: space-between;
min-height: 32px; min-height: 32px;
color: #999; color: #999;
border-top: 1px solid #D2D2D2; border-top: 1px solid #D2D2D2;
padding-top: 5px; padding-top: 5px;
margin-top: 5px; margin-top: 5px;
} }
.shared_header > .avatar {
display: block;
flex: 0 0 41px;
margin-inline-end: 9px;
}
.shared_header > .avatar > img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.shared_header > .metadata {
flex: 1 0 auto;
}
.shared_header > .metadata > p {
margin: 0;
}
.shared_header > .preferences {
position: static;
flex: 0 0 auto;
}
.shared_header a { .shared_header a {
-webkit-transition: all 0.2s ease-in-out; -webkit-transition: all 0.2s ease-in-out;
@ -167,16 +190,8 @@ span.connector {
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
} }
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
margin-right: 9px;
}
blockquote.shared_content { blockquote.shared_content {
margin-left: 32px; margin-inline-start: 32px;
color: #000; color: #000;
border: none; border: none;
} }

File diff suppressed because it is too large Load diff

View file

@ -106,11 +106,8 @@
<h2>{{$performance}}</h2> <h2>{{$performance}}</h2>
{{include file="field_checkbox.tpl" field=$only_tag_search}} {{include file="field_checkbox.tpl" field=$only_tag_search}}
{{include file="field_input.tpl" field=$itemcache}}
{{include file="field_input.tpl" field=$itemcache_duration}}
{{include file="field_input.tpl" field=$max_comments}} {{include file="field_input.tpl" field=$max_comments}}
{{include file="field_input.tpl" field=$max_display_comments}} {{include file="field_input.tpl" field=$max_display_comments}}
{{include file="field_checkbox.tpl" field=$proxy_disabled}}
{{include file="field_checkbox.tpl" field=$dbclean}} {{include file="field_checkbox.tpl" field=$dbclean}}
{{include file="field_input.tpl" field=$dbclean_expire_days}} {{include file="field_input.tpl" field=$dbclean_expire_days}}
{{include file="field_input.tpl" field=$dbclean_unclaimed}} {{include file="field_input.tpl" field=$dbclean_unclaimed}}

View file

@ -1,45 +0,0 @@
<form id="login-form" action="{{$dest_url}}" role="form" method="post" >
<div id="login-group" role="group" aria-labelledby="login-head">
<input type="hidden" name="auth-params" value="login" />
<h3 id="login-head" class="sr-only">{{$login}}</h3>
<div id="login_standard">
{{include file="field_input.tpl" field=$lname}}
{{include file="field_password.tpl" field=$lpassword}}
<div id="login-lost-password-link">
<a href="lostpass" title="{{$lostpass}}" id="lost-password-link" >{{$lostlink}}</a>
</div>
</div>
{{if $openid}}
<div id="login_openid">
{{include file="field_openid.tpl" field=$lopenid}}
</div>
{{/if}}
<div id="login-submit-wrapper" >
<input type="submit" name="submit" id="login-submit-button" value="{{$login}}" />
</div>
{{include file="field_checkbox.tpl" field=$lremember}}
{{foreach $hiddens as $k=>$v}}
<input type="hidden" name="{{$k}}" value="{{$v}}" />
{{/foreach}}
<video src="/images/login_video.mp4" width="320" controls>
<p>Your browser doesn't support HTML5 video. There is no link to another video instead.</p>
</video>
<img src="/images/login_image.png">
</div>
</form>
{{if $register}}
<div id="login-extra-links">
<h3 id="login-head" class="sr-only">{{$register.title}}</h3>
<a href="{{$register.url}}" title="{{$register.title}}" id="register-link">{{$register.desc}}</a>
</div>
{{/if}}
<script type="text/javascript"> $(document).ready(function() { $("#id_{{$lname.0}}").focus();} );</script>

View file

@ -1,12 +1,38 @@
<div class="shared-wrapper"> <div class="shared-wrapper well well-sm">
<div class="shared_header"> <div class="shared_header">
{{if $avatar}} {{if $avatar}}
<a href="{{$profile}}" target="_blank" rel="noopener noreferrer" class="shared-userinfo"> <a href="{{$profile}}" target="_blank" rel="noopener noreferrer" class="avatar shared-userinfo">
<img src="{{$avatar}}" height="32" width="32"> <img src="{{$avatar}}" alt="">
</a> </a>
{{/if}} {{/if}}
<div><a href="{{$profile}}" target="_blank" rel="noopener noreferrer" class="shared-wall-item-name"><span class="shared-author">{{$author}}</span></a></div> <div class="metadata">
<div class="shared-wall-item-ago"><small><a href="{{$link}}" target="_blank" rel="noopener noreferrer"><span class="shared-time">{{$posted}}</a></a></small></div> <p class="shared-author">
<a href="{{$profile}}" target="_blank" rel="noopener noreferrer" class="shared-wall-item-name">
{{$author}}
</a>
</p>
<p class="shared-wall-item-ago">
{{if $guid}}
<a href="/display/{{$guid}}">
{{/if}}
<span class="shared-time">{{$posted}}</span>
{{if $guid}}
</a>
{{/if}}
</p>
</div>
<div class="preferences">
{{if $network_icon}}
<span class="wall-item-network"><i class="fa fa-{{$network_icon}}" title="{{$network_name}}" aria-hidden="true"></i></span>
{{else}}
<span class="wall-item-network">{{$network_name}}</span>
{{/if}}
{{if $link}}
<a href="{{$link}}" class="plink u-url" aria-label="{{$link_title}}" title="{{$link_title}}">
<i class="fa fa-external-link"></i>
</a>
{{/if}}
</div>
</div> </div>
<blockquote class="shared_content">{{$content nofilter}}</blockquote> <blockquote class="shared_content">{{$content nofilter}}</blockquote>
</div> </div>

View file

@ -1238,44 +1238,13 @@ input#dfrn-url {
background: rgba(0, 0, 0, 0.5) url(shiny.png) no-repeat scroll center center; background: rgba(0, 0, 0, 0.5) url(shiny.png) no-repeat scroll center center;
} }
.shared_header {
height: 32px;
color: #999;
border-top: 1px solid #D2D2D2;
padding-top: 5px;
margin-top: 5px;
}
.shared_header a { .shared_header a {
color: black; color: black;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
-ms-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
} }
.shared_header a:hover { .shared_header a:hover {
color: #36c; color: #36c;
} }
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
.shared_header span {
margin-left: 9px;
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
}
.wall-item-title { .wall-item-title {
float: left; float: left;
font-weight: bold; font-weight: bold;
@ -3244,10 +3213,6 @@ div.jGrowl div.info {
width: 20px; width: 20px;
} }
.shared_header span {
margin-left: 10px;
}
/* small screens */ /* small screens */
@media all and (max-width: 1089px) { @media all and (max-width: 1089px) {
.field label { width: 90%; } .field label { width: 90%; }

View file

@ -1709,10 +1709,20 @@ aside .panel-body {
right: 0; right: 0;
top: 0; top: 0;
} }
.shared_header .preferences { .shared_header {
top: 7px; margin-left: 0px;
right: 9px; margin-top: 0px;
padding-top: 0px;
margin-bottom: 10px;
border-top: none;
color: inherit;
} }
blockquote.shared_content {
padding: 0px;
margin-inline-start: 0px;
color: inherit;
}
.wall-item-network { .wall-item-network {
font-size: 13px; font-size: 13px;
} }
@ -1837,19 +1847,6 @@ aside .panel-body {
.vevent:hover { .vevent:hover {
box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.15) inset, 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.15) inset, 0 1px 1px rgba(0, 0, 0, 0.05);
} }
.shared_header {
margin-left: 0px;
margin-top: 0px;
padding-top: 0px;
margin-bottom: 10px;
border-top: none;
color: inherit;
}
blockquote.shared_content {
padding: 0px;
margin-left: 0px;
color: inherit;
}
code > .hl-main { code > .hl-main {
padding: 10px 10px 1px 0; padding: 10px 10px 1px 0;
} }

View file

@ -241,11 +241,8 @@
<div id="admin-settings-performance-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="admin-settings-performance"> <div id="admin-settings-performance-collapse" class="panel-collapse collapse" role="tabpanel" aria-labelledby="admin-settings-performance">
<div class="panel-body"> <div class="panel-body">
{{include file="field_checkbox.tpl" field=$only_tag_search}} {{include file="field_checkbox.tpl" field=$only_tag_search}}
{{include file="field_input.tpl" field=$itemcache}}
{{include file="field_input.tpl" field=$itemcache_duration}}
{{include file="field_input.tpl" field=$max_comments}} {{include file="field_input.tpl" field=$max_comments}}
{{include file="field_input.tpl" field=$max_display_comments}} {{include file="field_input.tpl" field=$max_display_comments}}
{{include file="field_checkbox.tpl" field=$proxy_disabled}}
{{include file="field_checkbox.tpl" field=$dbclean}} {{include file="field_checkbox.tpl" field=$dbclean}}
{{include file="field_input.tpl" field=$dbclean_expire_days}} {{include file="field_input.tpl" field=$dbclean_expire_days}}
{{include file="field_input.tpl" field=$dbclean_unclaimed}} {{include file="field_input.tpl" field=$dbclean_unclaimed}}

View file

@ -1,32 +0,0 @@
<div class="shared-wrapper well well-sm">
<div class="shared_header">
{{if $avatar}}
<a href="{{$profile}}" target="_blank" rel="noopener noreferrer" class="shared-userinfo">
<img src="{{$avatar}}" height="32" width="32">
</a>
{{/if}}
<div><a href="{{$profile}}" target="_blank" rel="noopener noreferrer" class="shared-wall-item-name"><span class="shared-author">{{$author}}</span></a></div>
<div class="preferences">
{{if $network_icon}}
<span class="wall-item-network"><i class="fa fa-{{$network_icon}}" title="{{$network_name}}" aria-hidden="true"></i></span>
{{else}}
<span class="wall-item-network">{{$network_name}}</span>
{{/if}}
{{if $link}}
<a href="{{$link}}" class="plink u-url" aria-label="{{$link_title}}" title="{{$link_title}}">
<i class="fa fa-external-link"></i>
</a>
{{/if}}
</div>
<div class="shared-wall-item-ago"><small>
{{if $guid}}
<a href="/display/{{$guid}}">
{{/if}}
<span class="shared-time">{{$posted}}</span>
{{if $guid}}
</a>
{{/if}}
</small></div>
</div>
<blockquote class="shared_content">{{$content nofilter}}</blockquote>
</div>

View file

@ -1437,27 +1437,6 @@ section {
.type-video blockquote { .type-video blockquote {
padding-left: 1em; padding-left: 1em;
} }
.shared_header {
height: 32px;
color: #999;
border-top: 1px solid #cccccc;
padding-top: 5px;
margin-top: 5px;
}
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
.shared_header span {
margin-left: 9px;
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
}
.oembed.video > a.embed_video { .oembed.video > a.embed_video {
display: block; display: block;
position: relative; position: relative;

View file

@ -1437,27 +1437,6 @@ section {
.type-video blockquote { .type-video blockquote {
padding-left: 1em; padding-left: 1em;
} }
.shared_header {
height: 32px;
color: #999;
border-top: 1px solid #cccccc;
padding-top: 5px;
margin-top: 5px;
}
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
.shared_header span {
margin-left: 9px;
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
}
.oembed.video > a.embed_video { .oembed.video > a.embed_video {
display: block; display: block;
position: relative; position: relative;

View file

@ -1437,27 +1437,6 @@ section {
.type-video blockquote { .type-video blockquote {
padding-left: 1em; padding-left: 1em;
} }
.shared_header {
height: 32px;
color: #999;
border-top: 1px solid #cccccc;
padding-top: 5px;
margin-top: 5px;
}
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
.shared_header span {
margin-left: 9px;
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
}
.oembed.video > a.embed_video { .oembed.video > a.embed_video {
display: block; display: block;
position: relative; position: relative;

View file

@ -770,22 +770,6 @@ section {
border-top: 1px solid @ThreadBottomBorderColor; border-top: 1px solid @ThreadBottomBorderColor;
padding-top: 5px; padding-top: 5px;
margin-top: 5px; margin-top: 5px;
img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
span { margin-left: 9px; }
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
} }
.oembed.video { .oembed.video {

View file

@ -1815,44 +1815,13 @@ ul .sidebar-group-li .icon {
.type-link .oembed { .type-link .oembed {
} }
.shared_header {
height: 32px;
color: #999;
border-top: 1px solid #D2D2D2;
padding-top: 5px;
margin-top: 5px;
}
.shared_header a { .shared_header a {
color: black; color: black;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
-ms-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
} }
.shared_header a:hover { .shared_header a:hover {
color: #36c; color: #36c;
} }
.shared_header img {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
float: left;
}
.shared_header span {
margin-left: 9px;
}
blockquote.shared_content {
margin-left: 32px;
color: #000;
border: none;
}
.icon.drop, .icon.drop,
.icon.drophide { .icon.drophide {
float: left; float: left;
@ -4620,7 +4589,6 @@ div #datebrowse-sidebar.widget {
margin: 25px 0 25px 0; margin: 25px 0 25px 0;
} }
#id_itemcache,
#id_basepath, #id_basepath,
#id_temppath, #id_temppath,
#id_lockpath, #id_lockpath,
@ -4633,7 +4601,6 @@ div #datebrowse-sidebar.widget {
width: 440px; width: 440px;
} }
#id_itemcache_duration,
#id_abandon_days, #id_abandon_days,
#id_maxloadavg, #id_maxloadavg,
#id_poll_interval, #id_poll_interval,

View file

@ -345,15 +345,6 @@ div.pager, ul.tabs {
line-height: normal; line-height: normal;
} }
.shared_header {
min-height: 32px;;
color: #999;
border-top: 0px;
padding-top: 5px;
margin-top: 5px;
}
/* Post footer */ /* Post footer */
.wall-item-like { font-size:12px; } .wall-item-like { font-size:12px; }

View file

@ -1438,10 +1438,6 @@ section.minimal {
font-size: 12px; font-size: 12px;
} }
.shared_header {
line-height: 14px;
}
.wall-item-network { .wall-item-network {
color: #999; color: #999;
font-size: 12px; font-size: 12px;