Browse Source

Merge branch 'master' into develop

- Updated new develop version label
- Incremented database build number
pull/5155/head
Hypolite Petovan 4 years ago
parent
commit
93daf7883e
  1. 106
      CHANGELOG
  2. 2
      VERSION
  3. 2
      bin/dev/make_credits.py
  4. 2
      bin/run_xgettext.sh
  5. 4
      boot.php
  6. 25
      database.sql
  7. 1
      doc/Home.md
  8. 24
      doc/Tags-and-Mentions.md
  9. 1
      doc/de/Home.md
  10. 76
      doc/tools.md
  11. 8
      htconfig.php
  12. 50
      include/api.php
  13. 63
      include/conversation.php
  14. 10
      include/dba.php
  15. 8
      include/items.php
  16. 5
      include/text.php
  17. 4
      mod/_well_known.php
  18. 27
      mod/admin.php
  19. 2
      mod/community.php
  20. 95
      mod/dfrn_confirm.php
  21. 1
      mod/dfrn_request.php
  22. 44
      mod/display.php
  23. 2
      mod/events.php
  24. 4
      mod/group.php
  25. 7
      mod/item.php
  26. 16
      mod/network.php
  27. 85
      mod/nodeinfo.php
  28. 6
      mod/notes.php
  29. 2
      mod/notifications.php
  30. 2
      mod/openid.php
  31. 22
      mod/photos.php
  32. 5
      mod/profile.php
  33. 93
      mod/profiles.php
  34. 87
      mod/pubsubhubbub.php
  35. 9
      mod/register.php
  36. 12
      mod/removeme.php
  37. 6
      mod/search.php
  38. 23
      mod/settings.php
  39. 2
      mod/update_community.php
  40. 2
      mod/update_display.php
  41. 2
      mod/update_network.php
  42. 2
      mod/update_notes.php
  43. 2
      mod/update_profile.php
  44. 2
      mod/videos.php
  45. 25
      mods/sample-nginx.config
  46. 23
      src/App.php
  47. 4
      src/Content/Feature.php
  48. 4
      src/Content/Nav.php
  49. 30
      src/Content/Text/BBCode.php
  50. 10
      src/Core/Console/AutomaticInstallation.php
  51. 1
      src/Core/Console/PoToPhp.php
  52. 1
      src/Core/Worker.php
  53. 22
      src/Database/DBStructure.php
  54. 12
      src/Database/PostUpdate.php
  55. 57
      src/Model/Contact.php
  56. 2
      src/Model/GContact.php
  57. 134
      src/Model/Item.php
  58. 2
      src/Model/Profile.php
  59. 154
      src/Model/PushSubscriber.php
  60. 4
      src/Model/User.php
  61. 3
      src/Module/Login.php
  62. 44
      src/Module/Tos.php
  63. 41
      src/Network/Probe.php
  64. 38
      src/Object/Post.php
  65. 61
      src/Protocol/DFRN.php
  66. 239
      src/Protocol/Diaspora.php
  67. 3
      src/Protocol/Feed.php
  68. 7
      src/Protocol/OStatus.php
  69. 27
      src/Protocol/PortableContact.php
  70. 30
      src/Worker/Cron.php
  71. 2
      src/Worker/CronJobs.php
  72. 11
      src/Worker/Notifier.php
  73. 61
      src/Worker/PubSubPublish.php
  74. 3
      src/Worker/Queue.php
  75. 49
      update.php
  76. 17
      util/credits.txt
  77. 9395
      util/messages.po
  78. 1
      view/lang/bg/strings.php
  79. 1
      view/lang/ca/strings.php
  80. 1
      view/lang/cs/strings.php
  81. 14137
      view/lang/de/messages.po
  82. 3029
      view/lang/de/strings.php
  83. 11599
      view/lang/en-gb/messages.po
  84. 1713
      view/lang/en-gb/strings.php
  85. 11599
      view/lang/en-us/messages.po
  86. 1713
      view/lang/en-us/strings.php
  87. 1
      view/lang/eo/strings.php
  88. 1
      view/lang/es/strings.php
  89. 7075
      view/lang/fi-fi/messages.po
  90. 1155
      view/lang/fi-fi/strings.php
  91. 13852
      view/lang/fr/messages.po
  92. 2939
      view/lang/fr/strings.php
  93. 11295
      view/lang/is/messages.po
  94. 1943
      view/lang/is/strings.php
  95. 11595
      view/lang/it/messages.po
  96. 1895
      view/lang/it/strings.php
  97. 1
      view/lang/nb-no/strings.php
  98. 11439
      view/lang/nl/messages.po
  99. 2127
      view/lang/nl/strings.php
  100. 8605
      view/lang/pl/messages.po

106
CHANGELOG

@ -1,3 +1,105 @@
Version 2018.05 (2018-06-01)
Friendica Core:
Update to the translations (DE, EN-GB, EN-US, FI, IS, IT, NL, PL, RU, ZN CH) [translation teams]
Update to the documentation [andyhee, annando, fabrixxm, M-arcus, MrPedovan, rudloff, tobiasd]
Enhancements to the DB handling [annando]
Enhancements to the relay system [annando]
Enhancements to the handling of URL that contain unicode characters [annando]
Enhancements to the Vagrant VM configuration [fabrixxm, tobiasd]
Enhancementa to the Babel module [MrPetovan]
Enhancements to the display of the [code] elements [MrPetovan]
Enhancements to the federation (OStatus, diaspora) [annando]
Enhancements to the PHP7.2 compatibility [Alkarex, MrPetovan, Quix0r]
Enhancements to the themes (frio, vier) [astifter, fabrixxm, koyuawsmbrtn, M-arcus, MrPetovan, Quix0r, rabuzarus]
Enhancements to the accessibility using the frio theme [annando]
Enhancements to the display of the registration note and the privacy statements on the registration page [tobiasd]
Enhancements to the UI by clarification of the wording (deletion of items, network widget, invitations) [annando, tobiasd]
Enhancements to the background worker [annando]
Enhancements to the forum display in the sidebar [annando]
Enhancements to the testing system [rudloff, tobiasd]
Enhancements to the display of events [MrPetovan]
Enhancements to the language detection of postings [MrPetovan]
Enhancements to the memcached handling [MrPetovan]
Enhancements to the Dandelion app support [annando]
Enhancements to the API [rudloff]
Enhancements to the systemd timer example [ben-utzer]
Enhancements to the notification emails to better integrate the securemail addon [tobiasd]
Enhancements to the caching/loading mechanisms [MrPetovan]
Enhancements to the sample-nginx configfile to not use $uri in the rewrite rules [anmol26s]
Fixed a bug in the relocation process of a Friendica instance [annando]
Fixed a bug in the shell wrapper for the console [MrPetovan]
Fixed a bug with the console tool po2php [MrPetovan]
Fixed a bug with the console tool blockaccounts [MrPetovan]
Fixed a bug in the ACL [annando, MrPetovan]
Fixed a bug that prevented the deletion of contact groups [annando]
Fixed a bug that made edited mentions and hashtags plaintext [annando]
Fixed a bug that caused the /display page to receive constandly new updates [annando]
Fixed wrong version of a dependency preventing the usage of PHP 5.6 [MrPetovan]
Fixed a bug in OpenID authentification [Quix0r]
Fixed a bug in the item deletion [annando]
Fixed a bug that prevented public comments from being distributed [annando]
Fixed a bug that caused empty profile pictures for public contacts [annando]
Fixed a bug that prevented the display of some postings in the network stream [annando]
Fixed a bug in the display of videos with parameters [annando]
Fixed a bug that caused the display of blocked contacts under some conditions [annando]
Fixed bugs in the installer [annando, M-arcus]
Fixed a bug in the installer running on nginx [astifter]
Fixed a bug with reshares from diaspora* [annando]
Fixed a bug that accounts from diaspora* could join private forums automatically [annando]
Fixed a bug that prevented the selection of displayed profiles for other Friendica contacts [MrPetovan]
Fixed the version sorting in the federation statistics page [annando]
Fixed a bug in the nodeinfo calculation of total comments [annando]
Fixed a bug during registration that prevented the detected language to be saved [tobiasd]
Added an optional module to display the Terms of Service [rabuzarus, tobiasd]
Added testfeed module [MrPetovan]
Added hashtag autocomplete (ported from Hubzilla) [rabuzarus]
Added password exposed check [MrPetovan]
Added preloading config adapter [MrPetovan]
Added a console to unify the PHP utility scripts [MrPetovan]
Added a tool to set user passwords to the console [annando]
Added memcached support [MrPetovan]
Added password exposure check [MrPetovan]
Added hashtag autocompletion [rabuzarus]
Added feedtest module [MrPetovan]
Added dbclean options to the admin panel [annando]
Added the possibility to add the remote_self flag to contacts from diaspora* and Twitter [annando]
Added the possibility of automatic installations [M-arcus]
Added the sending of a notification mail to the admin when a user deletes their account [tobiasd]
Added examples for home.html and home.css files [tobiasd]
Added an option to define after how many days a contact should be archived [annando]
Added parts of the list API [rudloff]
Added support of ALT texts for images [annando]
Removed the connection postings [annando]
Corrected a long standing typo in config variable names; should your bandwidth saver mode stop working please turn it off and on again [abanink]
The execute-ables were moved from /util to /bin [MrPetovan]
The execute-ables for the developers were moved from /util to /bin/dev [MrPetovan]
The last year deprecated themes frost and frost mobile got removed from the Friendica repository. They can be found in the dedicated repository for deprecated themes [tobiasd]
General code refactoring and beautification work [annando, MrPetovan, rudloff]
Switched to cropperjs to better support touch screen devices [rabuzarus]
Use the diaspora transport layer for the DFRN protocol as well [annando]
Friendica Addons:
Updates to the translations (DE, EN_GB, EN_US, ES, FI, FR, IS, IT, NL, PL, RU, ZH_CN) [translation teams]
advancedcontentfilter: new addon with advanced filter capabilities [MrPetova]
catavatar: new addon for profile pictures based on David Revoy's cat-avatar generator [annando, fabrixxm, tobiasd]
languagefilter: better help text [andyhee]
mathjax: fixed the config form and adopted new CDN URL [tobiasd]
NSFW: add hashtag only hiding [MrPetovan]
notifyall: fixed a bug in handling the sender name [tobiasd]
Twitter: fixed a bug during the creation of public contacts [annando]
Twitter: remote self now also works for Twitter contacts [annando]
Twitter: optimizations for sending media [annando]
Closed Issues:
839, 1186, 1729, 2115, 2247, 2781, 2880, 3174, 3395, 3409, 3412,
3611, 3834, 3837, 3979, 4146, 4572, 4601, 4616, 4629, 4647, 4660,
4661, 4663, 4664, 4665, 4666, 4669, 4670, 4681, 4695, 4670, 4689,
4730, 4749, 4760, 4772, 4786, 4790, 4791, 4816, 4867, 4878, 4819,
4860, 4876, 4879, 4886, 4898, 4899, 4902, 4921, 4926, 4927, 4928,
4938, 4943, 4946, 4947, 4965, 4976, 4966, 4994, 4997, 5002, 5014,
5033, 5043, 5050, 5051, 5056, 5063, 5067, 5010, 5111, 5116, 5128,
5137, 5147
Version 3.6 (2018-03-23)
Friendica Core:
Updates to the translations (DE, EN_GB, EN_US, ES, FR, IT, ZH_CN) [translation teams]
@ -93,6 +195,8 @@ Version 3.6 (2018-03-23)
Updates to the translations (DE, EN_GB, ES, FR, IT, NL, ZH_CN) [translation teams]
all bridges don't relay postings anymore that are posted to a public forum [annando]
DAV addon marked unsupported [tobiasd]
communityhome addon marked unsupported [MrPetovan]
yourls addon makrked unsupported [MrPetovan]
Current Weather: fixing a problem with the weathermap link [zeroadam]
NSFW added config examples, reworked the description, now ignores the CW from Mastodon [andyhee, annando, rebeka-catalina]
Twitter support 280 chars limit [annando]
@ -102,7 +206,7 @@ Version 3.6 (2018-03-23)
Public Server reworked [annando]
pageheader settings beautifications [tobiasd]
mailstream settings beautifications [tobiasd]
Membersince is now part of the core [rabuzarus]
Membersince is now part of the core, addon marked unsupported [rabuzarus]
Forum posts are not transmitted over the connectors anymore [annando]
Friendica Dir:

2
VERSION

@ -1 +1 @@
2018-05-dev
2018.08-dev

2
bin/dev/make_credits.py

@ -29,7 +29,7 @@ dontinclude = ['root', 'friendica', 'bavatar', 'tony baldwin', 'Taek', 'silke m'
# this script is in the /util sub-directory of the friendica installation
# so the friendica path is the 0th argument of calling this script but we
# need to remove the name of the file and the name of the directory
path = os.path.abspath(argv[0].split('util/make_credits.py')[0])
path = os.path.abspath(argv[0].split('bin/dev/make_credits.py')[0])
print('> base directory is assumed to be: '+path)
# a place to store contributors
contributors = ["Andi Stadler", "Ratten", "Vít Šesták 'v6ak'"]

2
bin/run_xgettext.sh

@ -48,7 +48,7 @@ case "$MODE" in
OUTFILE="$FULLPATH/../util/messages.po"
FINDSTARTDIR="."
# skip addon folder
FINDOPTS="( -wholename */addon -or -wholename */addons-extra -or -wholename */smarty3 ) -prune -o"
FINDOPTS="( -wholename */addon -or -wholename */addons -or -wholename */addons-extra -or -wholename */smarty3 ) -prune -o"
F9KVERSION=$(sed -n "s/.*'FRIENDICA_VERSION'.*'\([0-9.]*\)'.*/\1/p" ./boot.php);
echo "Friendica version $F9KVERSION"

4
boot.php

@ -39,9 +39,9 @@ require_once 'include/text.php';
define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily');
define('FRIENDICA_VERSION', '2018-05-dev');
define('FRIENDICA_VERSION', '2018.08-dev');
define('DFRN_PROTOCOL_VERSION', '2.23');
define('DB_UPDATE_VERSION', 1260);
define('DB_UPDATE_VERSION', 1267);
define('NEW_UPDATE_ROUTINE_VERSION', 1170);
/**

25
database.sql

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2018-05-dev (The Tazmans Flax-lily)
-- DB_UPDATE_VERSION 1260
-- Friendica 2018.08-dev (The Tazmans Flax-lily)
-- DB_UPDATE_VERSION 1267
-- ------------------------------------------
@ -855,10 +855,13 @@ CREATE TABLE IF NOT EXISTS `push_subscriber` (
`callback_url` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`topic` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`nickname` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`push` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
`last_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`push` tinyint NOT NULL DEFAULT 0 COMMENT 'Retrial counter',
`last_update` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last successful trial',
`next_try` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Next retrial date',
`renewed` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last subscription renewal',
`secret` varchar(255) NOT NULL DEFAULT '' COMMENT '',
PRIMARY KEY(`id`)
PRIMARY KEY(`id`),
INDEX `next_try` (`next_try`)
) DEFAULT COLLATE utf8mb4_general_ci;
--
@ -1073,6 +1076,16 @@ CREATE TABLE IF NOT EXISTS `userd` (
INDEX `username` (`username`(32))
) DEFAULT COLLATE utf8mb4_general_ci;
--
-- TABLE user-item
--
CREATE TABLE IF NOT EXISTS `user-item` (
`iid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Item id',
`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id',
`hidden` boolean NOT NULL DEFAULT '0' COMMENT 'Hidden marker',
PRIMARY KEY(`uid`,`iid`)
) DEFAULT COLLATE utf8mb4_general_ci;
--
-- TABLE workerqueue
--
@ -1088,7 +1101,7 @@ CREATE TABLE IF NOT EXISTS `workerqueue` (
INDEX `pid` (`pid`),
INDEX `parameter` (`parameter`(64)),
INDEX `priority_created` (`priority`,`created`),
INDEX `executed` (`executed`)
INDEX `done_executed` (`done`,`executed`)
) DEFAULT COLLATE utf8mb4_general_ci;

1
doc/Home.md

@ -34,6 +34,7 @@ Friendica Documentation and Resources
* [Using SSL with Friendica](help/SSL)
* [Config values that can only be set in .htconfig.php](help/htconfig)
* [Improve Performance](help/Improve-Performance)
* [Administration Tools](help/tools)
**Developer Manual**

24
doc/Tags-and-Mentions.md

@ -23,16 +23,19 @@ You can tag a person on a different network or one that is **not in your social
Unless their system blocks unsolicited "mentions", the person tagged will likely receive a "Mention" post/activity or become a direct participant in the conversation in the case of public posts.
Friendica blocks incoming “mentions” from people with no relationship to you.
The exception is an ongiong conversation started from a contact of both you and the 3rd person or a conversation in a forum where you are a member of.
The exception is an ongoing conversation started from a contact of both you and the 3rd person or a conversation in a forum where you are a member of.
This is a spam prevention measure.
Remote mentions are delivered using the OStatus protocol.
This protocol is used by Friendica and GNU Social and several other systems, but is not currently implemented in Diaspora.
This protocol is used by Friendica and GNU Social and several other systems like Mastodon, but is not currently implemented in Diaspora.
As the OStatus protocol allows this Friendica user can be @-mentioned by users from platforms using this protocol in conversations if the "Enable OStatus support" is activated on the Friendica node.
These @-mentions wont be blocked, even if there is no relationship between the sender and the receiver of the message.
Friendica makes no distinction between people and forums for the purpose of tagging.
(Some other networks use !forum to indicate a forum.)
You can use @-mentions for forums like for other accounts to tag the forum.
If you want to post something exclusively to a forum (e.g. the support forum) please use the bang-notation instead of the @tag.
So !helpers will be an exclusive posting to the support forum if you are connected with the forum.
If you select a forum from the ACL a !-mention will be added automatically to your posting.
If you sort your contacts into groups, you cannot @-mention these groups.
But you can select the group in the access control when creating a new posting, to allow (or disallow) a certain group of people to see the posting.
@ -40,11 +43,14 @@ See [Groups and Privacy](help/Groups-and-Privacy) for more details about groupin
**Topical Tags**
Topical tags are indicated by preceding the tag name with the # character. This will create a link in the post to a generalised site search for the term provided. For example, #cars will provide a search link for all posts mentioning 'cars' on your site. Topical tags are generally a minimum of three characters in length. Shorter search terms are not likely to yield any search results, although this depends on the database configuration. The same rules apply as with names that spaces within tags are represented by the underscore character. It is therefore not possible to create a tag whose target contains an underscore.
Topical tags are indicated by preceding the tag name with the # character.
This will create a link in the post to a generalised site search for the term provided.
For example, #cars will provide a search link for all posts mentioning 'cars' on your site.
Topical tags are generally a minimum of three characters in length.
Shorter search terms are not likely to yield any search results, although this depends on the database configuration.
The same rules apply as with names that spaces within tags are represented by the underscore character.
It is therefore not possible to create a tag whose target contains an underscore.
Topical tags are also not linked if they are purely numeric, e.g. #1. If you wish to use a numerica hashtag, please add some descriptive text such as #2012-elections.
Topical tags are also not linked if they are purely numeric, e.g. #1.
If you wish to use a numerica hashtag, please add some descriptive text such as #2012-elections.

1
doc/de/Home.md

@ -36,6 +36,7 @@ Friendica - Dokumentation und Ressourcen
* [Betreibe deine Seite mit einem SSL-Zertifikat](help/SSL)
* [Konfigurationswerte, die nur in der .htconfig.php gesetzt werden können](help/htconfig) (EN)
* [Performance verbessern](help/Improve-Performance)
* [Administration Werkzeuge](help/tools) (EN)
**Dokumentation für Entwickler**

76
doc/tools.md

@ -0,0 +1,76 @@
Admin Tools
===========
* [Home](help)
Friendica Tools
---------------
Friendica has a build in command console you can find in the *bin* directory.
The console provides the following commands:
* config: Edit site config
* createdoxygen: Generate Doxygen headers
* dbstructure: Do database updates
* docbloxerrorchecker: Check the file tree for DocBlox errors
* extract: Generate translation string file for the Friendica project (deprecated)
* globalcommunityblock: Block remote profile from interacting with this node
* globalcommunitysilence: Silence remote profile from global community page
* archivecontact: Archive a contact when you know that it isn't existing anymore
* help: Show help about a command, e.g (bin/console help config)
* autoinstall: Starts automatic installation of friendica based on values from htconfig.php
* maintenance: Set maintenance mode for this node
* newpassword: Set a new password for a given user
* php2po: Generate a messages.po file from a strings.php file
* po2php: Generate a strings.php file from a messages.po file
* typo: Checks for parse errors in Friendica files
Please consult *bin/console help* on the command line interface of your server for details about the commands.
3rd Party Tools
---------------
In addition to the tools Friendica includes, some 3rd party tools can make your admin days easier.
### Fail2ban
Fail2ban is an intrusion prevention framework ([see Wikipedia](https://en.wikipedia.org/wiki/Fail2ban)) that you can use to forbid access to a server under certain conditions, e.g. 3 failed attempts to log in, for a certain amount of time.
The following configuration was [provided](https://forum.friendi.ca/display/174591b4135ae40c1ad7e93897572454) by Steffen K9 using Debian.
You need to adjust the *logpath* in the *jail.local* file and the *bantime* (value is in seconds).
In */etc/fail2ban/jail.local* create a section for Friendica:
[friendica]
enabled = true
findtime = 300
bantime = 900
filter = friendica
port = http,https
logpath = /var/log/friend.log
logencoding = utf-8
And create a filter definition in */etc/fail2ban/filter.d/friendica.conf*:
[Definition]
failregex = ^.*Login\.php.*failed login attempt.*from IP <HOST>.*$
ignoreregex =
Additionally you have to define the number of failed logins before the ban should be activated.
This is done either in the global configuration or for each jail separately.
You should inform your users about the number of failed login attempts you grant them.
Otherwise you'll get many reports about the server not functioning if the number is too low.
### Log rotation
If you have activated the logs in Friendica, be aware that they can grow to a significant size.
To keep them in control you should add them to the automatic [log rotation](https://en.wikipedia.org/wiki/Log_rotation), e.g. using the *logrotate* command.
In */etc/logrotate.d/* add a file called *friendica* that contains the configuration.
The following will compress */var/log/friendica* (assuming this is the location of the log file) on a daily basis and keep 2 days of back-log.
/var/log/friendica.log {
compress
daily
rotate 2
}

8
htconfig.php

@ -24,11 +24,15 @@ $db_data = 'mysqldatabasename';
// Use environment variables for mysql if they are set beforehand
if (!empty(getenv('MYSQL_HOST'))
&& !empty(getenv('MYSQL_PORT'))
&& !empty(getenv('MYSQL_USERNAME'))
&& (!empty(getenv('MYSQL_USERNAME')) || !empty(getenv('MYSQL_USER')))
&& !empty(getenv('MYSQL_PASSWORD'))
&& !empty(getenv('MYSQL_DATABASE'))) {
$db_host = getenv('MYSQL_HOST') . ':' . getenv('MYSQL_PORT');
$db_user = getenv('MYSQL_USERNAME');
if (!empty(getenv('MYSQL_USERNAME'))) {
$db_user = getenv('MYSQL_USERNAME');
} elseif (!empty(getenv('MYSQL_USER'))) {
$db_user = getenv('MYSQL_USER');
}
$db_pass = getenv('MYSQL_PASSWORD');
$db_data = getenv('MYSQL_DATABASE');
}

50
include/api.php

@ -1663,7 +1663,7 @@ function api_search($type)
$r = dba::p(
"SELECT ".item_fieldlists()."
FROM `item` ".item_joins()."
FROM `item` ".item_joins(api_user())."
WHERE ".item_condition()." AND (`item`.`uid` = 0 OR (`item`.`uid` = ? AND NOT `item`.`global`))
AND `item`.`body` LIKE CONCAT('%',?,'%')
$sql_extra
@ -1827,7 +1827,7 @@ function api_statuses_public_timeline($type)
"SELECT " . item_fieldlists() . "
FROM `thread`
STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
" . item_joins() . "
" . item_joins(api_user()) . "
STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid`
AND NOT `user`.`hidewall`
AND `verb` = ?
@ -1856,7 +1856,7 @@ function api_statuses_public_timeline($type)
$r = dba::p(
"SELECT " . item_fieldlists() . "
FROM `item`
" . item_joins() . "
" . item_joins(api_user()) . "
STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid`
AND NOT `user`.`hidewall`
AND `verb` = ?
@ -1930,7 +1930,7 @@ function api_statuses_networkpublic_timeline($type)
"SELECT " . item_fieldlists() . "
FROM `thread`
STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
" . item_joins() . "
" . item_joins(api_user()) . "
WHERE `thread`.`uid` = 0
AND `verb` = ?
AND NOT `thread`.`private`
@ -2002,6 +2002,19 @@ function api_statuses_show($type)
$sql_extra .= " AND `item`.`id` = %d";
}
// try to fetch the item for the local user - or the public item, if there is no local one
$uri_item = dba::selectFirst('item', ['uri'], ['id' => $id]);
if (!DBM::is_result($uri_item)) {
throw new BadRequestException("There is no status with this id.");
}
$item = dba::selectFirst('item', ['id'], ['uri' => $uri_item['uri'], 'uid' => [0, api_user()]], ['order' => ['uid' => true]]);
if (!DBM::is_result($item)) {
throw new BadRequestException("There is no status with this id.");
}
$id = $item['id'];
$r = q(
"SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
@ -2011,7 +2024,7 @@ function api_statuses_show($type)
INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id` AND `contact`.`uid` = `item`.`uid`
AND (NOT `contact`.`blocked` OR `contact`.`pending`)
WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted`
AND `item`.`uid` = %d AND `item`.`verb` = '%s'
AND `item`.`uid` IN (0, %d) AND `item`.`verb` = '%s'
$sql_extra",
intval(api_user()),
dbesc(ACTIVITY_POST),
@ -2075,22 +2088,25 @@ function api_conversation_show($type)
logger('API: api_conversation_show: '.$id);
$r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($id));
if (DBM::is_result($r)) {
$id = $r[0]["parent"];
// try to fetch the item for the local user - or the public item, if there is no local one
$item = dba::selectFirst('item', ['parent-uri'], ['id' => $id]);
if (!DBM::is_result($item)) {
throw new BadRequestException("There is no status with this id.");
}
$parent = dba::selectFirst('item', ['id'], ['uri' => $item['parent-uri'], 'uid' => [0, api_user()]], ['order' => ['uid' => true]]);
if (!DBM::is_result($parent)) {
throw new BadRequestException("There is no status with this id.");
}
$id = $parent['id'];
$sql_extra = '';
if ($max_id > 0) {
$sql_extra = ' AND `item`.`id` <= ' . intval($max_id);
}
// Not sure why this query was so complicated. We should keep it here for a while,
// just to make sure that we really don't need it.
// FROM `item` INNER JOIN (SELECT `uri`,`parent` FROM `item` WHERE `id` = %d) AS `temp1`
// ON (`item`.`thr-parent` = `temp1`.`uri` AND `item`.`parent` = `temp1`.`parent`)
$r = q(
"SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
`contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
@ -2101,7 +2117,7 @@ function api_conversation_show($type)
AND (NOT `contact`.`blocked` OR `contact`.`pending`)
WHERE `item`.`parent` = %d AND `item`.`visible`
AND NOT `item`.`moderated` AND NOT `item`.`deleted`
AND `item`.`uid` = %d AND `item`.`verb` = '%s'
AND `item`.`uid` IN (0, %d) AND `item`.`verb` = '%s'
AND `item`.`id`>%d $sql_extra
ORDER BY `item`.`id` DESC LIMIT %d ,%d",
intval($id),
@ -2240,7 +2256,7 @@ function api_statuses_destroy($type)
$ret = api_statuses_show($type);
Item::deleteById($id);
Item::deleteForUser(['id' => $id], api_user());
return $ret;
}
@ -4132,7 +4148,7 @@ function api_fr_photoalbum_delete($type)
if (!DBM::is_result($photo_item)) {
throw new InternalServerErrorException("problem with deleting items occured");
}
Item::deleteById($photo_item[0]['id']);
Item::deleteForUser(['id' => $photo_item[0]['id']], api_user());
}
// now let's delete all photos from the album
@ -4424,7 +4440,7 @@ function api_fr_photo_delete($type)
}
// function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore
// to the user and the contacts of the users (drop_items() do all the necessary magic to avoid orphans in database and federate deletion)
Item::deleteById($photo_item[0]['id']);
Item::deleteForUser(['id' => $photo_item[0]['id']], api_user());
$answer = ['result' => 'deleted', 'message' => 'photo with id `' . $photo_id . '` has been deleted from server.'];
return api_format_data("photo_delete", $type, ['$result' => $answer]);

63
include/conversation.php

@ -401,10 +401,12 @@ function visible_activity($item) {
/**
* @brief SQL query for items
*
* @param int $uid user id
*/
function item_query() {
function item_query($uid = 0) {
return "SELECT " . item_fieldlists() . " FROM `item` " .
item_joins() . " WHERE " . item_condition();
item_joins($uid) . " WHERE " . item_condition();
}
/**
@ -429,7 +431,6 @@ These Fields are not added below (yet). They are here to for bug search.
`item`.`bookmark`,
`item`.`unseen`,
`item`.`deleted`,
`item`.`origin`,
`item`.`forum_mode`,
`item`.`mention`,
`item`.`global`,
@ -442,7 +443,7 @@ These Fields are not added below (yet). They are here to for bug search.
`item`.`uri`, `item`.`thr-parent`, `item`.`parent-uri`, `item`.`content-warning`,
`item`.`commented`, `item`.`created`, `item`.`edited`, `item`.`received`,
`item`.`verb`, `item`.`object-type`, `item`.`postopts`, `item`.`plink`,
`item`.`guid`, `item`.`wall`, `item`.`private`, `item`.`starred`,
`item`.`guid`, `item`.`wall`, `item`.`private`, `item`.`starred`, `item`.`origin`,
`item`.`title`, `item`.`body`, `item`.`file`, `item`.`event-id`,
`item`.`location`, `item`.`coord`, `item`.`app`, `item`.`attach`,
`item`.`rendered-hash`, `item`.`rendered-html`, `item`.`object`,
@ -464,16 +465,19 @@ These Fields are not added below (yet). They are here to for bug search.
/**
* @brief SQL join for contacts that are needed for displaying items
*
* @param int $uid user id
*/
function item_joins() {
function item_joins($uid = 0) {
return sprintf("STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
AND NOT `contact`.`blocked`
AND ((NOT `contact`.`readonly` AND NOT `contact`.`pending` AND (`contact`.`rel` IN (%s, %s)))
OR `contact`.`self` OR (`item`.`id` != `item`.`parent`))
OR `contact`.`self` OR (`item`.`id` != `item`.`parent`) OR `contact`.`uid` = 0)
INNER JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id` AND NOT `author`.`blocked`
INNER JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id` AND NOT `owner`.`blocked`
LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d
LEFT JOIN `event` ON `event-id` = `event`.`id`",
CONTACT_IS_SHARING, CONTACT_IS_FRIEND
CONTACT_IS_SHARING, CONTACT_IS_FRIEND, intval($uid)
);
}
@ -481,7 +485,7 @@ function item_joins() {
* @brief SQL condition for items that are needed for displaying items
*/
function item_condition() {
return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`";
return "`item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated` AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) ";
}
/**
@ -494,7 +498,7 @@ function item_condition() {
* that are based on unique features of the calling module.
*
*/
function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'commented') {
function conversation(App $a, $items, $mode, $update, $preview = false, $order = 'commented', $uid = 0) {
require_once 'mod/proxy.php';
$ssl_state = ((local_user()) ? true : false);
@ -518,7 +522,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order =
$previewing = (($preview) ? ' preview ' : '');
if ($mode === 'network') {
$items = conversation_add_children($items, false, $order);
$items = conversation_add_children($items, false, $order, $uid);
$profile_owner = local_user();
if (!$update) {
/*
@ -579,7 +583,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order =
. " var profile_page = 1; </script>";
}
} elseif ($mode === 'community') {
$items = conversation_add_children($items, true, $order);
$items = conversation_add_children($items, true, $order, $uid);
$profile_owner = 0;
if (!$update) {
$live_update_div = '<div id="live-community"></div>' . "\r\n"
@ -882,7 +886,7 @@ function conversation(App $a, $items, $mode, $update, $preview = false, $order =
*
* @return array items with parents and comments
*/
function conversation_add_children($parents, $block_authors, $order) {
function conversation_add_children($parents, $block_authors, $order, $uid) {
$max_comments = Config::get('system', 'max_comments', 100);
if ($max_comments > 0) {
@ -896,37 +900,12 @@ function conversation_add_children($parents, $block_authors, $order) {
$block_sql = $block_authors ? "AND NOT `author`.`hidden` AND NOT `author`.`blocked`" : "";
foreach ($parents AS $parent) {
$thread_items = dba::p(item_query()." AND `item`.`uid` = ?
AND `item`.`parent-uri` = ? $block_sql
ORDER BY `item`.`commented` DESC" . $limit,
local_user(),
$parent['uri']
);
$comments = dba::inArray($thread_items);
$thread_items = dba::p(item_query(local_user())."AND `item`.`parent-uri` = ?
AND `item`.`uid` IN (0, ?) $block_sql
ORDER BY `item`.`uid` ASC, `item`.`commented` DESC" . $limit,
$parent['uri'], local_user());
// Check if the original item is in the result.
// When commenting from the community page there can be incomplete threads
if (count($comments) > 0) {
$parent_found = false;
foreach ($comments as $comment) {
if ($comment['uri'] == $comment['parent-uri']) {
$parent_found = true;
break;
}
}
if (!$parent_found) {
$comments = [];
}
}
if (count($comments) == 0) {
$thread_items = dba::p(item_query()." AND `item`.`uid` = 0
AND `item`.`parent-uri` = ?
ORDER BY `item`.`commented` DESC LIMIT ".intval($max_comments + 1),
$parent['uri']
);
$comments = dba::inArray($thread_items);
}
$comments = dba::inArray($thread_items);
if (count($comments) != 0) {
$items = array_merge($items, $comments);

10
include/dba.php

@ -52,16 +52,6 @@ class dba {
return false;
}
if ($a->mode == App::MODE_INSTALL) {
// server has to be a non-empty string that is not 'localhost' and not an IP
if (strlen($server) && ($server !== 'localhost') && filter_var($server, FILTER_VALIDATE_IP) === false) {
if (! dns_get_record($server, DNS_A + DNS_CNAME)) {
self::$error = L10n::t('Cannot locate DNS info for database server \'%s\'', $server);
return false;
}
}
}
if (class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) {
self::$driver = 'pdo';
$connect = "mysql:host=".$server.";dbname=".$db;

8
include/items.php

@ -29,7 +29,7 @@ function add_page_info_data($data, $no_photos = false) {
// It maybe is a rich content, but if it does have everything that a link has,
// then treat it that way
if (($data["type"] == "rich") && is_string($data["title"]) &&
is_string($data["text"]) && (sizeof($data["images"]) > 0)) {
is_string($data["text"]) && !empty($data["images"])) {
$data["type"] = "link";
}
@ -63,7 +63,7 @@ function add_page_info_data($data, $no_photos = false) {
$text .= " title='".$data["title"]."'";
}
if (sizeof($data["images"]) > 0) {
if (!empty($data["images"])) {
$preview = str_replace(["[", "]"], ["&#91;", "&#93;"], htmlentities($data["images"][0]["src"], ENT_QUOTES, 'UTF-8', false));
// if the preview picture is larger than 500 pixels then show it in a larger mode
// But only, if the picture isn't higher than large (To prevent huge posts)
@ -322,7 +322,7 @@ function drop_items($items) {
if (count($items)) {
foreach ($items as $item) {
$owner = Item::deleteById($item);
$owner = Item::deleteForUser(['id' => $item], local_user());
if ($owner && !$uid)
$uid = $owner;
}
@ -394,7 +394,7 @@ function drop_item($id) {
}
// delete the item
Item::deleteById($item['id']);
Item::deleteForUser(['id' => $item['id']], local_user());
goaway(System::baseUrl() . '/' . $_SESSION['return_url']);
//NOTREACHED

5
include/text.php

@ -14,6 +14,7 @@ use Friendica\Core\L10n;
use Friendica\Core\PConfig;
use Friendica\Core\System;
use Friendica\Database\DBM;
use Friendica\Model\Contact;
use Friendica\Model\Event;
use Friendica\Model\Item;
use Friendica\Model\Profile;
@ -1966,6 +1967,10 @@ function undo_post_tagging($s) {
$cnt = preg_match_all('/([!#@])\[url=(.*?)\](.*?)\[\/url\]/ism', $s, $matches, PREG_SET_ORDER);
if ($cnt) {
foreach ($matches as $mtch) {
if (in_array($mtch[1], ['!', '@'])) {
$contact = Contact::getDetailsByURL($mtch[2]);
$mtch[3] = empty($contact['addr']) ? $mtch[2] : $contact['addr'];
}
$s = str_replace($mtch[0], $mtch[1] . $mtch[3],$s);
}
}

4
mod/_well_known.php

@ -73,8 +73,8 @@ function wk_social_relay()
'subscribe' => $subscribe,
'scope' => $scope,
'tags' => $taglist,
'protocols' => ['diaspora' => System::baseUrl() . '/receive/public',
'dfrn' => System::baseUrl() . '/dfrn_notify']
'protocols' => ['diaspora' => ['receive' => System::baseUrl() . '/receive/public'],
'dfrn' => ['receive' => System::baseUrl() . '/dfrn_notify']]
];
header('Content-type: application/json; charset=utf-8');

27
mod/admin.php

@ -20,6 +20,7 @@ use Friendica\Model\Contact;
use Friendica\Model\Item;
use Friendica\Model\User;
use Friendica\Module\Login;
use Friendica\Module\Tos;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Temporal;
@ -296,12 +297,15 @@ function admin_content(App $a)
*/
function admin_page_tos(App $a)
{
$tos = new Tos();
$t = get_markup_template('admin/tos.tpl');
return replace_macros($t, [
'$title' => L10n::t('Administration'),
'$page' => L10n::t('Terms of Service'),
'$displaytos' => ['displaytos', L10n::t('Display Terms of Service'), Config::get('system', 'tosdisplay'), L10n::t('Enable the Terms of Service page. If this is enabled a link to the terms will be added to the registration form and the general information page.')],
'$displayprivstatement' => ['displayprivstatement', L10n::t('Display Privacy Statement'), Config::get('system','tosprivstatement'), L10n::t('Show some informations regarding the needed information to operate the node according e.g. to <a href="%s" target="_blank">EU-GDPR</a>.','https://en.wikipedia.org/wiki/General_Data_Protection_Regulation')],
'$preview' => L10n::t('Privacy Statement Preview'),
'$privtext' => $tos->privacy_complete,
'$tostext' => ['tostext', L10n::t('The Terms of Service'), Config::get('system', 'tostext'), L10n::t('Enter the Terms of Service for your node here. You can use BBCode. Headers of sections should be [h2] and below.')],
'$form_security_token' => get_form_security_token("admin_tos"),
'$submit' => L10n::t('Save Settings'),
@ -551,14 +555,9 @@ function admin_page_deleteitem_post(App $a)
if (strpos($guid, '/')) {
$guid = substr($guid, strrpos($guid, '/') + 1);
}
// Now that we have the GUID get all IDs of the associated entries in the
// item table of the DB and drop those items, which will also delete the
// Now that we have the GUID, drop those items, which will also delete the
// associated threads.
$r = dba::select('item', ['id'], ['guid' => $guid]);
while ($row = dba::fetch($r)) {
Item::deleteById($row['id']);
}
dba::close($r);
Item::delete(['guid' => $guid]);
}
info(L10n::t('Item marked for deletion.') . EOL);
@ -1345,16 +1344,12 @@ function admin_page_site(App $a)
}
$diaspora_able = ($a->get_path() == "");
$optimize_max_tablesize = Config::get('system', 'optimize_max_tablesize', 100);
$optimize_max_tablesize = Config::get('system', 'optimize_max_tablesize', -1);
if ($optimize_max_tablesize < -1) {
if ($optimize_max_tablesize <= 0) {
$optimize_max_tablesize = -1;
}
if ($optimize_max_tablesize == 0) {
$optimize_max_tablesize = 100;
}
$t = get_markup_template('admin/site.tpl');
return replace_macros($t, [
'$title' => L10n::t('Administration'),
@ -1399,7 +1394,7 @@ function admin_page_site(App $a)
'$no_oembed_rich_content' => ['no_oembed_rich_content', L10n::t("No OEmbed rich content"), Config::get('system','no_oembed_rich_content'), L10n::t("Don't show the rich content \x28e.g. embedded PDF\x29, except from the domains listed below.")],
'$allowed_oembed' => ['allowed_oembed', L10n::t("Allowed OEmbed domains"), Config::get('system','allowed_oembed'), L10n::t("Comma separated list of domains which oembed content is allowed to be displayed. Wildcards are accepted.")],
'$block_public' => ['block_public', L10n::t("Block public"), Config::get('system','block_public'), L10n::t("Check to block public access to all otherwise public personal pages on this site unless you are currently logged in.")],
'$force_publish' => ['publish_all', L10n::t("Force publish"), Config::get('system','publish_all'), L10n::t("Check to force all profiles on this site to be listed in the site directory.")],
'$force_publish' => ['publish_all', L10n::t("Force publish"), Config::get('system','publish_all'), L10n::t("Check to force all profiles on this site to be listed in the site directory.") . '<strong>' . L10n::t('Enabling this may violate privacy laws like the GDPR') . '</strong>'],
'$global_directory' => ['directory', L10n::t("Global directory URL"), Config::get('system', 'directory', 'https://dir.friendica.social'), L10n::t("URL to the global directory. If this is not set, the global directory is completely unavailable to the application.")],
'$newuser_private' => ['newuser_private', L10n::t("Private posts by default for new users"), Config::get('system','newuser_private'), L10n::t("Set default post permissions for all new members to the default privacy group rather than public.")],
'$enotify_no_content' => ['enotify_no_content', L10n::t("Don't include post content in email notifications"), Config::get('system','enotify_no_content'), L10n::t("Don't include the content of a post/comment/private message/etc. in the email notifications that are sent out from this site, as a privacy measure.")],
@ -1425,7 +1420,7 @@ function admin_page_site(App $a)
'$maxloadavg' => ['maxloadavg', L10n::t("Maximum Load Average"), Config::get('system', 'maxloadavg', 50), L10n::t("Maximum system load before delivery and poll processes are deferred - default 50.")],
'$maxloadavg_frontend' => ['maxloadavg_frontend', L10n::t("Maximum Load Average \x28Frontend\x29"), Config::get('system', 'maxloadavg_frontend', 50), L10n::t("Maximum system load before the frontend quits service - default 50.")],
'$min_memory' => ['min_memory', L10n::t("Minimal Memory"), Config::get('system', 'min_memory', 0), L10n::t("Minimal free memory in MB for the worker. Needs access to /proc/meminfo - default 0 \x28deactivated\x29.")],
'$optimize_max_tablesize'=> ['optimize_max_tablesize', L10n::t("Maximum table size for optimization"), $optimize_max_tablesize, L10n::t("Maximum table size \x28in MB\x29 for the automatic optimization - default 100 MB. Enter -1 to disable it.")],
'$optimize_max_tablesize'=> ['optimize_max_tablesize', L10n::t("Maximum table size for optimization"), $optimize_max_tablesize, L10n::t("Maximum table size \x28in MB\x29 for the automatic optimization. Enter -1 to disable it.")],
'$optimize_fragmentation'=> ['optimize_fragmentation', L10n::t("Minimum level of fragmentation"), Config::get('system', 'optimize_fragmentation', 30), L10n::t("Minimum fragmenation level to start the automatic optimization - default value is 30%.")],
'$poco_completion' => ['poco_completion', L10n::t("Periodical check of global contacts"), Config::get('system','poco_completion'), L10n::t("If enabled, the global contacts are checked periodically for missing or outdated data and the vitality of the contacts and servers.")],
@ -1446,7 +1441,7 @@ function admin_page_site(App $a)
'$max_comments' => ['max_comments', L10n::t("Maximum numbers of comments per post"), Config::get('system','max_comments'), L10n::t("How much comments should be shown for each post? Default value is 100.")],
'$temppath' => ['temppath', L10n::t("Temp path"), Config::get('system','temppath'), L10n::t("If you have a restricted system where the webserver can't access the system temp path, enter another path here.")],
'$basepath' => ['basepath', L10n::t("Base path to installation"), Config::get('system','basepath'), L10n::t("If the system cannot detect the correct path to your installation, enter the correct path here. This setting should only be set if you are using a restricted system and symbolic links to your webroot.")],
'$proxy_disabled' => ['proxy_disabled', L10n::t("Disable picture proxy"), Config::get('system','proxy_disabled'), L10n::t("The picture proxy increases performance and privacy. It shouldn't be used on systems with very low bandwith.")],
'$proxy_disabled' => ['proxy_disabled', L10n::t("Disable picture proxy"), Config::get('system','proxy_disabled'), 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', L10n::t("Only search in tags"), Config::get('system','only_tag_search'), L10n::t("On large systems the text search can slow down the system extremely.")],
'$relocate_url' => ['relocate_url', L10n::t("New base url"), System::baseUrl(), L10n::t("Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users.")],

2
mod/community.php

@ -171,7 +171,7 @@ function community_content(App $a, $update = 0)
$s = $r;
}
$o .= conversation($a, $s, 'community', $update);
$o .= conversation($a, $s, 'community', $update, false, 'commented', local_user());
if (!$update) {
$o .= alt_pager($a, count($r));

95
mod/dfrn_confirm.php

@ -83,14 +83,12 @@ function dfrn_confirm_post(App $a, $handsfree = null)
$duplex = $handsfree['duplex'];
$cid = 0;
$hidden = intval(defaults($handsfree, 'hidden' , 0));
$activity = intval(defaults($handsfree, 'activity', 0));
} else {
$dfrn_id = notags(trim(defaults($_POST, 'dfrn_id' , '')));
$intro_id = intval(defaults($_POST, 'intro_id' , 0));
$duplex = intval(defaults($_POST, 'duplex' , 0));
$cid = intval(defaults($_POST, 'contact_id', 0));
$hidden = intval(defaults($_POST, 'hidden' , 0));
$activity = intval(defaults($_POST, 'activity' , 0));
}
/*
@ -284,6 +282,11 @@ function dfrn_confirm_post(App $a, $handsfree = null)
}
if (($status == 0) && $intro_id) {
$intro = dba::selectFirst('intro', ['note'], ['id' => $intro_id]);
if (DBM::is_result($intro)) {
dba::update('contact', ['reason' => $intro['note']], ['id' => $contact_id]);
}
// Success. Delete the notification.
dba::delete('intro', ['id' => $intro_id]);
}
@ -385,7 +388,6 @@ function dfrn_confirm_post(App $a, $handsfree = null)
);
}
/// @TODO is DBM::is_result() working here?
if (!DBM::is_result($r)) {
notice(L10n::t('Unable to set contact photo.') . EOL);
}
@ -397,50 +399,6 @@ function dfrn_confirm_post(App $a, $handsfree = null)
$ret = Diaspora::sendShare($user, $contact);
logger('share returns: ' . $ret);
}
// Send a new friend post if we are allowed to...
$profile = dba::selectFirst('profile', ['hide-friends'], ['is-default' => true, 'uid' => $uid]);
if (x($profile, 'hide-friends') === 0 && $activity && !$hidden) {
$self = dba::selectFirst('contact', [], ['self' => true, 'uid' => $uid]);
if (DBM::is_result($self)) {
$arr = [];
$arr['guid'] = get_guid(32);
$arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $uid);
$arr['uid'] = $uid;
$arr['contact-id'] = $self['id'];
$arr['wall'] = 1;
$arr['type'] = 'wall';
$arr['gravity'] = 0;
$arr['origin'] = 1;
$arr['author-name'] = $arr['owner-name'] = $self['name'];
$arr['author-link'] = $arr['owner-link'] = $self['url'];
$arr['author-avatar'] = $arr['owner-avatar'] = $self['thumb'];
$A = '[url=' . $self['url'] . ']' . $self['name'] . '[/url]';
$B = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
$BPhoto = '[url=' . $contact['url'] . ']' . '[img]' . $contact['thumb'] . '[/img][/url]';
$arr['verb'] = ACTIVITY_FRIEND;
$arr['object-type'] = ACTIVITY_OBJ_PERSON;
$arr['body'] = L10n::t('%1$s is now friends with %2$s', $A, $B) . "\n\n\n" . $BPhoto;
$arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $contact['name'] . '</title>'
. '<id>' . $contact['url'] . '/' . $contact['name'] . '</id>';
$arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $contact['url'] . '" />' . "\n");
$arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $contact['thumb'] . '" />' . "\n");
$arr['object'] .= '</link></object>' . "\n";
$arr['allow_cid'] = $user['allow_cid'];
$arr['allow_gid'] = $user['allow_gid'];
$arr['deny_cid'] = $user['deny_cid'];
$arr['deny_gid'] = $user['deny_gid'];
$i = Item::insert($arr);
if ($i) {
Worker::add(PRIORITY_HIGH, "Notifier", "activity", $i);
}
}
}
}
Group::addMember(User::getDefaultGroup($uid, $contact["network"]), $contact['id']);
@ -661,49 +619,6 @@ function dfrn_confirm_post(App $a, $handsfree = null)
}
}
// Send a new friend post if we are allowed to...
if ($page && intval(PConfig::get($local_uid, 'system', 'post_joingroup'))) {
$profile = dba::selectFirst('profile', ['hide-friends'], ['is-default' => true, 'uid' => $local_uid]);
if (x($profile, 'hide-friends') === 0) {
$self = dba::selectFirst('contact', [], ['self' => true, 'uid' => $local_uid]);
if (DBM::is_result($self)) {
$arr = [];
$arr['uri'] = $arr['parent-uri'] = item_new_uri($a->get_hostname(), $local_uid);
$arr['uid'] = $local_uid;
$arr['contact-id'] = $self['id'];
$arr['wall'] = 1;
$arr['type'] = 'wall';
$arr['gravity'] = 0;
$arr['origin'] = 1;
$arr['author-name'] = $arr['owner-name'] = $self['name'];
$arr['author-link'] = $arr['owner-link'] = $self['url'];
$arr['author-avatar'] = $arr['owner-avatar'] = $self['thumb'];
$A = '[url=' . $self['url'] . ']' . $self['name'] . '[/url]';
$B = '[url=' . $combined['url'] . ']' . $combined['name'] . '[/url]';
$BPhoto = '[url=' . $combined['url'] . ']' . '[img]' . $combined['thumb'] . '[/img][/url]';
$arr['verb'] = ACTIVITY_JOIN;
$arr['object-type'] = ACTIVITY_OBJ_GROUP;
$arr['body'] = L10n::t('%1$s has joined %2$s', $A, $B) . "\n\n\n" . $BPhoto;
$arr['object'] = '<object><type>' . ACTIVITY_OBJ_GROUP . '</type><title>' . $combined['name'] . '</title>'
. '<id>' . $combined['url'] . '/' . $combined['name'] . '</id>';
$arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $combined['url'] . '" />' . "\n");
$arr['object'] .= xmlify('<link rel="photo" type="image/jpeg" href="' . $combined['thumb'] . '" />' . "\n");
$arr['object'] .= '</link></object>' . "\n";
$arr['allow_cid'] = $user['allow_cid'];
$arr['allow_gid'] = $user['allow_gid'];
$arr['deny_cid'] = $user['deny_cid'];
$arr['deny_gid'] = $user['deny_gid'];
$i = Item::insert($arr);
if ($i) {
Worker::add(PRIORITY_HIGH, "Notifier", "activity", $i);
}
}
}
}
System::xmlExit(0); // Success
return; // NOTREACHED
////////////////////// End of this scenario ///////////////////////////////////////////////

1
mod/dfrn_request.php

@ -577,7 +577,6 @@ function dfrn_request_content(App $a)
'dfrn_id' => $r[0]['issued-id'],
'intro_id' => $intro[0]['id'],
'duplex' => (($r[0]['page-flags'] == PAGE_FREELOVE) ? 1 : 0),
'activity' => intval(PConfig::get($r[0]['uid'], 'system', 'post_newfriend'))
];
dfrn_confirm_post($a, $handsfree);
}

44
mod/display.php

@ -211,13 +211,14 @@ function display_content(App $a, $update = false, $update_uid = 0) {
if ($update) {
$item_id = $_REQUEST['item_id'];
$item = dba::selectFirst('item', ['uid', 'parent'], ['id' => $item_id]);
$item = dba::selectFirst('item', ['uid', 'parent', 'parent-uri'], ['id' => $item_id]);
if ($item['uid'] != 0) {
$a->profile = ['uid' => intval($item['uid']), 'profile_uid' => intval($item['uid'])];
} else {
$a->profile = ['uid' => intval($update_uid), 'profile_uid' => intval($update_uid)];
}
$item_parent = $item['parent'];
$item_parent_uri = $item['parent-uri'];
} else {
$item_id = (($a->argc > 2) ? $a->argv[2] : 0);
@ -225,23 +226,25 @@ function display_content(App $a, $update = false, $update_uid = 0) {
$item_parent = 0;
if (local_user()) {
$r = dba::fetch_first("SELECT `id`, `parent` FROM `item`
$r = dba::fetch_first("SELECT `id`, `parent`, `parent-uri` FROM `item`
WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
AND `guid` = ? AND `uid` = ?", $a->argv[1], local_user());
if (DBM::is_result($r)) {
$item_id = $r["id"];
$item_parent = $r["parent"];
$item_parent_uri = $r['parent-uri'];
}
}
if ($item_parent == 0) {
$r = dba::fetch_first("SELECT `item`.`id`, `item`.`parent` FROM `item`
$r = dba::fetch_first("SELECT `item`.`id`, `item`.`parent`, `item`.`parent-uri` FROM `item`
WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
AND NOT `item`.`private` AND `item`.`uid` = 0
AND `item`.`guid` = ?", $a->argv[1]);
if (DBM::is_result($r)) {
$item_id = $r["id"];
$item_parent = $r["parent"];
$item_parent_uri = $r['parent-uri'];
}
}
}
@ -332,22 +335,21 @@ function display_content(App $a, $update = false, $update_uid = 0) {
$sql_extra = item_permissions_sql($a->profile['uid'], $remote_contact, $groups);
if ($update) {
$r = dba::p("SELECT `id` FROM `item` WHERE
`item`.`parent` = (SELECT `parent` FROM `item` WHERE `id` = ?)
$sql_extra AND `unseen`",
$item_id
);
if (local_user() && (local_user() == $a->profile['uid'])) {
$condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true];
$unseen = dba::exists('item', $condition);
} else {
$unseen = false;
}
if (dba::num_rows($r) == 0) {
return '';
}
if ($update && !$unseen) {
return '';
}
$r = dba::p(item_query()."AND `item`.`parent` = (SELECT `parent` FROM `item` WHERE `id` = ?)
$sql_extra
ORDER BY `parent` DESC, `gravity` ASC, `id` ASC",
$item_id
$r = dba::p(item_query(local_user())."AND `item`.`parent-uri` = (SELECT `parent-uri` FROM `item` WHERE `id` = ?)
AND `item`.`uid` IN (0, ?) $sql_extra
ORDER BY `item`.`uid` ASC, `parent` DESC, `gravity` ASC, `id` ASC",
$item_id, local_user()
);
if (!DBM::is_result($r)) {
@ -357,11 +359,9 @@ function display_content(App $a, $update = false, $update_uid = 0) {
$s = dba::inArray($r);
if (local_user() && (local_user() == $a->profile['uid'])) {
$unseen = dba::selectFirst('item', ['id'], ['parent' => $s[0]['parent'], 'unseen' => true]);
if (DBM::is_result($unseen)) {
dba::update('item', ['unseen' => false], ['parent' => $s[0]['parent'], 'unseen' => true]);
}
if ($unseen) {
$condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true];
dba::update('item', ['unseen' => false], $condition);
}
$items = conv_sort($s, "`commented`");
@ -369,7 +369,7 @@ function display_content(App $a, $update = false, $update_uid = 0) {
if (!$update) {
$o .= "<script> var netargs = '?f=&item_id=" . $item_id . "'; </script>";
}
$o .= conversation($a, $items, 'display', $update_uid);
$o .= conversation($a, $items, 'display', $update_uid, false, 'commented', local_user());
// Preparing the meta header
$description = trim(HTML::toPlaintext(BBCode::convert($s[0]["body"], false), 0, true));

2
mod/events.php

@ -546,7 +546,7 @@ function events_content(App $a) {
// Delete only real events (no birthdays)
if (DBM::is_result($ev) && $ev[0]['type'] == 'event') {
$del = Item::deleteById($ev[0]['itemid']);
$del = Item::deleteForUser(['id' => $ev[0]['itemid']], local_user());
}
if ($del == 0) {

4
mod/group.php

@ -226,7 +226,7 @@ function group_content(App $a) {
$entry['label'] = 'members';
$entry['photo_menu'] = '';
$entry['change_member'] = [
'title' => L10n::t("Remove Contact"),
'title' => L10n::t("Remove contact from group"),
'gid' => $group['id'],
'cid' => $member['id'],
'sec_token' => $sec_token
@ -250,7 +250,7 @@ function group_content(App $a) {
$entry['label'] = 'contacts';
$entry['photo_menu'] = '';
$entry['change_member'] = [
'title' => L10n::t("Add Contact"),
'title' => L10n::t("Add contact to group"),
'gid' => $group['id'],
'cid' => $member['id'],
'sec_token' => $sec_token

7
mod/item.php

@ -661,6 +661,11 @@ function item_post(App $a) {
$datarray['edit'] = true;
}
// Check for hashtags in the body and repair or add hashtag links
if ($preview || $orig_post) {
Item::setHashtags($datarray);
}
// preview mode - prepare the body for display and send it via json
if ($preview) {
require_once 'include/conversation.php';
@ -872,7 +877,7 @@ function item_content(App $a) {
$o = '';
if (($a->argc == 3) && ($a->argv[1] === 'drop') && intval($a->argv[2])) {
if (is_ajax()) {
$o = Item::deleteById($a->argv[2]);
$o = Item::deleteForUser(['id' => $a->argv[2]], local_user());
} else {
$o = drop_item($a->argv[2]);
}

16
mod/network.php

@ -345,7 +345,7 @@ function networkConversation($a, $items, $mode, $update, $ordering = '')
// Set this so that the conversation function can find out contact info for our wall-wall items
$a->page_contact = $a->contact;
$o = conversation($a, $items, $mode, $update, false, $ordering);
$o = conversation($a, $items, $mode, $update, false, $ordering, local_user());
if (!$update) {
if (PConfig::get(local_user(), 'system', 'infinite_scroll')) {
@ -456,8 +456,8 @@ function networkFlatView(App $a, $update = 0)
$items = q("SELECT %s FROM `item` $sql_post_table %s
WHERE %s AND `item`.`uid` = %d
ORDER BY `item`.`id` DESC $pager_sql ",
item_fieldlists(), item_joins(), item_condition(),
intval($_SESSION['uid'])
item_fieldlists(), item_joins(local_user()), item_condition(),
intval(local_user())
);
$condition = ['unseen' => true, 'uid' => local_user()];
@ -610,7 +610,7 @@ function networkThreadedView(App $a, $update, $parent)
$sql_tag_nets = (($nets) ? sprintf(" AND `item`.`network` = '%s' ", dbesc($nets)) : '');
if ($gid) {
$group = dba::selectFirst('group', ['name'], ['id' => $gid, 'uid' => $_SESSION['uid']]);
$group = dba::selectFirst('group', ['name'], ['id' => $gid, 'uid' => local_user()]);
if (!DBM::is_result($group)) {
if ($update) {
killme();
@ -626,7 +626,7 @@ function networkThreadedView(App $a, $update, $parent)
$contact_str_self = '';
$contact_str = implode(',', $contacts);
$self = dba::selectFirst('contact', ['id'], ['uid' => $_SESSION['uid'], 'self' => true]);
$self = dba::selectFirst('contact', ['id'], ['uid' => local_user(), 'self' => true]);
if (DBM::is_result($self)) {
$contact_str_self = $self['id'];
}
@ -774,12 +774,15 @@ function networkThreadedView(App $a, $update, $parent)
AND (`item`.`parent-uri` != `item`.`uri`
OR `contact`.`uid` = `item`.`uid` AND `contact`.`self`
OR `contact`.`rel` IN (%d, %d) AND NOT `contact`.`readonly`)
LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d
WHERE `item`.`uid` = %d AND `item`.`visible` AND NOT `item`.`deleted`
AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`)
AND NOT `item`.`moderated` AND $sql_extra4
$sql_extra3 $sql_extra $sql_range $sql_nets
ORDER BY `order_date` DESC LIMIT 100",
intval(CONTACT_IS_SHARING),
intval(CONTACT_IS_FRIEND),
intval(local_user()),
intval(local_user())
);
} else {
@ -791,12 +794,15 @@ function networkThreadedView(App $a, $update, $parent)
AND (`item`.`parent-uri` != `item`.`uri`
OR `contact`.`uid` = `item`.`uid` AND `contact`.`self`
OR `contact`.`rel` IN (%d, %d) AND NOT `contact`.`readonly`)
LEFT JOIN `user-item` ON `user-item`.`iid` = `item`.`id` AND `user-item`.`uid` = %d
WHERE `thread`.`uid` = %d AND `thread`.`visible` AND NOT `thread`.`deleted`
AND NOT `thread`.`moderated`
AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`)
$sql_extra2 $sql_extra3 $sql_range $sql_extra $sql_nets
ORDER BY `order_date` DESC $pager_sql",
intval(CONTACT_IS_SHARING),
intval(CONTACT_IS_FRIEND),
intval(local_user()),
intval(local_user())
);
}

85
mod/nodeinfo.php

@ -10,6 +10,7 @@ use Friendica\Core\Addon;
use Friendica\Core\System;
use Friendica\Core\Config;
use Friendica\Util\Network;
require_once 'include/dba.php';
function nodeinfo_wellknown(App $a) {
$nodeinfo = ['links' => [['rel' => 'http://nodeinfo.diaspora.software/ns/schema/1.0',
@ -153,7 +154,7 @@ function nodeinfo_cron() {
$a = get_app();
// If the addon 'statistics_json' is enabled then disable it and actrivate nodeinfo.
// If the addon 'statistics_json' is enabled then disable it and activate nodeinfo.
if (Addon::isEnabled('statistics_json')) {
Config::set('system', 'nodeinfo', true);
@ -176,17 +177,8 @@ function nodeinfo_cron() {
if (!Config::get('system', 'nodeinfo')) {
return;
}
$last = Config::get('nodeinfo', 'last_calucation');
if ($last) {
// Calculate every 24 hours
$next = $last + (24 * 60 * 60);
if ($next > time()) {
logger('calculation intervall not reached');
return;
}
}
logger('cron_start');
logger('cron_start');
$users = q("SELECT `user`.`uid`, `user`.`login_date`, `contact`.`last-item`
FROM `user`
@ -196,60 +188,43 @@ function nodeinfo_cron() {
AND NOT `user`.`blocked` AND NOT `user`.`account_removed`
AND NOT `user`.`account_expired`");
if (is_array($users)) {
$total_users = count($users);
$active_users_halfyear = 0;
$active_users_monthly = 0;
$halfyear = time() - (180 * 24 * 60 * 60);
$month = time() - (30 * 24 * 60 * 60);
foreach ($users AS $user) {
if ((strtotime($user['login_date']) > $halfyear) ||
(strtotime($user['last-item']) > $halfyear)) {
++$active_users_halfyear;
}
if ((strtotime($user['login_date']) > $month) ||
(strtotime($user['last-item']) > $month)) {
++$active_users_monthly;
}
}
Config::set('nodeinfo', 'total_users', $total_users);
logger('total_users: '.$total_users, LOGGER_DEBUG);
$total_users = count($users);
$active_users_halfyear = 0;
$active_users_monthly = 0;
Config::set('nodeinfo', 'active_users_halfyear', $active_users_halfyear);
Config::set('nodeinfo', 'active_users_monthly', $active_users_monthly);
}
$halfyear = time() - (180 * 24 * 60 * 60);
$month = time() - (30 * 24 * 60 * 60);
$posts = q("SELECT COUNT(*) AS `local_posts` FROM `thread` WHERE `thread`.`wall` AND `thread`.`uid` != 0");
foreach ($users AS $user) {
if ((strtotime($user['login_date']) > $halfyear) ||
(strtotime($user['last-item']) > $halfyear)) {
++$active_users_halfyear;
}
if ((strtotime($user['login_date']) > $month) ||
(strtotime($user['last-item']) > $month)) {
++$active_users_monthly;
}
}
Config::set('nodeinfo', 'total_users', $total_users);
Config::set('nodeinfo', 'active_users_halfyear', $active_users_halfyear);
Config::set('nodeinfo', 'active_users_monthly', $active_users_monthly);
if (!is_array($posts)) {
$local_posts = -1;
} else {
$local_posts = $posts[0]['local_posts'];
logger('total_users: ' . $total_users . '/' . $active_users_halfyear. '/' . $active_users_monthly, LOGGER_DEBUG);
}
Config::set('nodeinfo', 'local_posts', $local_posts);
logger('local_posts: '.$local_posts, LOGGER_DEBUG);
$posts = q("SELECT COUNT(*) AS `local_comments` FROM `contact`
INNER JOIN `item` ON `item`.`contact-id` = `contact`.`id` AND `item`.`uid` = `contact`.`uid` AND
`item`.`id` != `item`.`parent` AND `item`.`network` IN ('%s', '%s', '%s')
WHERE `contact`.`self`",
dbesc(NETWORK_OSTATUS), dbesc(NETWORK_DIASPORA), dbesc(NETWORK_DFRN));
$local_posts = dba::count('thread', ["`wall` AND NOT `deleted` AND `uid` != 0"]);
Config::set('nodeinfo', 'local_posts', $local_posts);
logger('local_posts: ' . $local_posts, LOGGER_DEBUG);
if (!is_array($posts)) {
$local_comments = -1;
} else {
$local_comments = $posts[0]['local_comments'];
}
$local_comments = dba::count('item', ["`origin` AND `id` != `parent` AND NOT `deleted` AND `uid` != 0"]);
Config::set('nodeinfo', 'local_comments', $local_comments);
logger('local_comments: ' . $local_comments, LOGGER_DEBUG);
// Now trying to register
$url = 'http://the-federation.info/register/'.$a->get_hostname();
logger('registering url: '.$url, LOGGER_DEBUG);
logger('registering url: '.$url, LOGGER_DEBUG);
$ret = Network::fetchUrl($url);
logger('registering answer: '.$ret, LOGGER_DEBUG);
logger('registering answer: '.$ret, LOGGER_DEBUG);
logger('cron_end');
Config::set('nodeinfo', 'last_calucation', time());
logger('cron_end');
}

6
mod/notes.php

@ -82,7 +82,7 @@ function notes_content(App $a, $update = false)
WHERE %s AND `item`.`uid` = %d AND `item`.`type` = 'note'
AND `contact`.`self` AND `item`.`id` = `item`.`parent` AND NOT `item`.`wall`
$sql_extra ",
item_joins(),
item_joins(local_user()),
item_condition(),
intval(local_user())
);
@ -97,7 +97,7 @@ function notes_content(App $a, $update = false)
AND `item`.`id` = `item`.`parent` AND NOT `item`.`wall`
$sql_extra
ORDER BY `item`.`created` DESC LIMIT %d ,%d ",
item_joins(),
item_joins(local_user()),
item_condition(),
intval(local_user()),
intval($a->pager['start']),
@ -119,7 +119,7 @@ function notes_content(App $a, $update = false)
$sql_extra
ORDER BY `parent` DESC, `gravity` ASC, `item`.`id` ASC ",
item_fieldlists(),
item_joins(),
item_joins(local_user()),
item_condition(),
intval(local_user()),
dbesc($parents_str)

2
mod/notifications.php

@ -173,7 +173,6 @@ function notifications_content(App $a) {
'$fullname' => $it['name'],
'$url' => $it['url'],
'$hidden' => ['hidden', L10n::t('Hide this contact from others'), ($it['hidden'] == 1), ''],
'$activity' => ['activity', L10n::t('Post a new friend activity'), $it['post_newfriend'], L10n::t('if applicable')],
'$knowyou' => $it['knowyou'],
'$approve' => L10n::t('Approve'),
@ -252,7 +251,6 @@ function notifications_content(App $a) {
'$gender' => $it['gender'],
'$lbl_gender' => L10n::t('Gender:'),
'$hidden' => ['hidden', L10n::t('Hide this contact from others'), ($it['hidden'] == 1), ''],
'$activity' => ['activity', L10n::t('Post a new friend activity'), $it['post_newfriend'], L10n::t('if applicable')],
'$url' => $it['url'],
'$zrl' => $it['zrl'],
'$lbl_url' => L10n::t('Profile URL'),

2
mod/openid.php

@ -19,7 +19,7 @@ function openid_content(App $a) {
if((x($_GET,'openid_mode')) && (x($_SESSION,'openid'))) {
$openid = new LightOpenID;
$openid = new LightOpenID($a->get_hostname());
if($openid->validate()) {

22
mod/photos.php

@ -284,14 +284,7 @@ function photos_post(App $a)
);
// find and delete the corresponding item with all the comments and likes/dislikes
$r = q("SELECT `id` FROM `item` WHERE `resource-id` IN ( $str_res ) AND `uid` = %d",
intval($page_owner_uid)
);
if (DBM::is_result($r)) {
foreach ($r as $rr) {
Item::deleteById($rr['id']);
}
}
Item::deleteForUser(['resource-id' => $res, 'uid' => $page_owner_uid], $page_owner_uid);
// Update the photo albums cache
Photo::clearAlbumCache($page_owner_uid);
@ -344,16 +337,11 @@ function photos_post(App $a)
intval($page_owner_uid),
dbesc($r[0]['resource-id'])
);
$i = q("SELECT `id` FROM `item` WHERE `resource-id` = '%s' AND `uid` = %d LIMIT 1",
dbesc($r[0]['resource-id']),
intval($page_owner_uid)
);