Merge pull request #1 from friendica/develop

Update develop branch
This commit is contained in:
Andy H 2017-06-07 15:06:13 +07:00 committed by GitHub
commit 1c107b2e1f
94 changed files with 62698 additions and 39804 deletions

148
CHANGELOG
View file

@ -1,10 +1,64 @@
Version 3.5.2 (2017-06-06)
Friendica Core:
Updates to the translations (DE, EN-GB, EN-US, ES, IT, PT-BR, RU) [translation teams]
Updates to the documentation [annando, beardyunixer, rabuzarus, tobiasd]
Updated the nginx example configuration [beardyunixer]
Code revision and refactoring [annando, hypolite, Quix0r, rebeka-catalina]
Background process is now done by the new worker process [annando]
Added support of Composer for dependencies [Hypolite]
Added support of Web app manifests [Rudloff]
Added basic robot.txt functionality if none exists [Shnoulle]
Added server blocklist [Hypolite, tobiasd]
Removed mcrypt dependency [annando]
Removed unused libraries [annando]
Removed Embedly integration [Hypolite]
Fixed a bug in the language detection for EN [Hypolite]
Fixed a bug in the probing mechanism on old PHP version [annando]
Improved API [annando, gerhard6380]
Improved Diaspora federation [annando]
Improved Mastodon federation [annando, Hypolite]
Improved import from OStatus threads [annando]
Improved the themes (frio, quattro) [fabrixxm, Hypolite, rabuzarus, Rudloff, strk, tobiasd]
Improved maintenance mode [annando]
Improved gcontact handling [annando]
Improved desktop notifications [rabuzarus]
Improved keyboard shortcuts for navigation [Rudloff]
Improved the installer [annando]
Improved openid handling [strk]
Improved php7 support [annando]
Improved display of notifications [annando]
Improved logging mechanism [beardyunixer]
Improved the worker [annando]
Behaviour clarification of the group filter / new tab [annando]
Old options for the pager and share element were removed [annando]
Support of PDO was added [annando]
Improved error logging for issues with the database [annando]
Improved compatibility to MySQL version 5.7+ [annando]
Friendica Addons:
Updates to the translation (RU) [pztrm]
(core) Fix blocking issue for Communityhome [annando]
Pledgie addon was updated to remove cert problems [tobiasd]
Securemail now uses openpgp-php and phpseclib [fabrixxm]
Superblock Configuration [tobiasd]
Twitter Connector updated to use with new deletion method [annando]
Closed Issues:
1626, 1720, 2432, 2792, 2833, 2364, 2448, 2496, 2690, 2752, 2775,
2803, 2956, 2957, 2961, 2971, 2995, 2999, 3011, 3053, 3107, 3114,
3134, 3138, 3142, 3157, 3172, 3189, 3194, 3195, 3198, 3206, 3215,
3217, 3220, 3237, 3242, 3255, 3256, 3260, 3268, 3273, 3274, 3285,
3288, 3292, 3293, 3300, 3314, 3316, 3317, 3322, 3325, 3327, 3328,
3331, 3334, 3336, 3346, 3347, 3358, 3359, 3383, 3387, 3401, 3406,
3428, 3440, 3435, 3436, 3452
Version 3.5.1 (2017-03-12) Version 3.5.1 (2017-03-12)
Friendica Core: Friendica Core:
Updates to the translations (BG, CA, CS, DE, EO, ES, FR, IS, IT, NL, PL, PT-BR, RU, SV) [translation teams] Updates to the translations (BG, CA, CS, DE, EO, ES, FR, IS, IT, NL, PL, PT-BR, RU, SV) [translation teams]
Fix for a potential XSS vector [heluecht, thanks to Vít Šesták 'v6ak' for reporting the problem] Fix for a potential XSS vector [annando, thanks to Vít Šesták 'v6ak' for reporting the problem]
Fix for ghost request notifications on single user instances [Hypolite] Fix for ghost request notifications on single user instances [Hypolite]
Fix user language selection [tobiasd] Fix user language selection [tobiasd]
Fix a problem with communication to Diaspora with set posting locations [heluecht] Fix a problem with communication to Diaspora with set posting locations [annando]
Fix schema handling of direct links to a original posting [Rabuzarus] Fix schema handling of direct links to a original posting [Rabuzarus]
Fix a bug in notification handling [Rabuzarus] Fix a bug in notification handling [Rabuzarus]
Adjustments for the Vagrant VM settings [silke, eelcomaljaars] Adjustments for the Vagrant VM settings [silke, eelcomaljaars]
@ -12,22 +66,22 @@ Version 3.5.1 (2017-03-12)
Improvements to the API and Friendica specific extensions [gerhard6380] Improvements to the API and Friendica specific extensions [gerhard6380]
Improvements to the Browser Notification functionality [Hypolite] Improvements to the Browser Notification functionality [Hypolite]
Improvements to the themes [Hypolite, rabuzarus, rebeka-catalina, tobiasd] Improvements to the themes [Hypolite, rabuzarus, rebeka-catalina, tobiasd]
Improvements to the database handling [heluecht] Improvements to the database handling [annando]
Improvements to the admin panel [tobiasd, Hypolite] Improvements to the admin panel [tobiasd, Hypolite]
Improvements to the update process [heluecht] Improvements to the update process [annando]
Improvements to the handling of worker processes [heluecht] Improvements to the handling of worker processes [annando]
Improvements to the performance [heluecht, Hypolite] Improvements to the performance [annando, Hypolite]
Improvements to the documentation [Hypolite, tobiasd, rabuzarus, beardyunixer, eelcomaljaars] Improvements to the documentation [Hypolite, tobiasd, rabuzarus, beardyunixer, eelcomaljaars]
Improvements to the BBCode / Markdown conversation [Hypolite] Improvements to the BBCode / Markdown conversation [Hypolite]
Improvements to the OStatus protocol implementation [heluecht] Improvements to the OStatus protocol implementation [annando]
Improvements to the installation wizzard [tobiasd] Improvements to the installation wizzard [tobiasd]
Improvements to the Diaspora connectivity [heluecht, Hypolite] Improvements to the Diaspora connectivity [annando, Hypolite]
Work on PHP7 compatibility [ddorian1] Work on PHP7 compatibility [ddorian1]
Code cleanup [Hypolite, Quix0r] Code cleanup [Hypolite, Quix0r]
Initial federation with Mastodon [heluecht] Initial federation with Mastodon [annando]
The worker process can now also be started from the frontend [heluecht] The worker process can now also be started from the frontend [annando]
Deletion of postings is now done in the background [heluecht] Deletion of postings is now done in the background [annando]
Extension of the DFRN transmitted information fields [heluecht] Extension of the DFRN transmitted information fields [annando]
Translations of the core are now in /view/lang [Hypolite, tobiasd] Translations of the core are now in /view/lang [Hypolite, tobiasd]
Update of the fullCalendar library to 3.0.1 and adjusting the themes [rabuzarus] Update of the fullCalendar library to 3.0.1 and adjusting the themes [rabuzarus]
ping now works with JSON as well [Hypolite] ping now works with JSON as well [Hypolite]
@ -46,16 +100,16 @@ Version 3.5.1 (2017-03-12)
Updates to the translations (DE, ES, FR, IT, PT-BR) [translation teams] Updates to the translations (DE, ES, FR, IT, PT-BR) [translation teams]
Improvements to the IFTTT addon [Hypolite] Improvements to the IFTTT addon [Hypolite]
Improvements to the language filter addon [strk] Improvements to the language filter addon [strk]
Improvements to the pump.io bridge [heluecht] Improvements to the pump.io bridge [annando]
Improvements to the jappixmini addon [heluecht] Improvements to the jappixmini addon [annando]
Improvements to the gpluspost addon [heluecht] Improvements to the gpluspost addon [annando]
Improvements to the performance of the Twitter bridge when using workers [heluecht] Improvements to the performance of the Twitter bridge when using workers [annando]
Diaspora Export addon is now working again [heluecht] Diaspora Export addon is now working again [annando]
Pledgie badge now uses https protocol for embedding [tobiasd] Pledgie badge now uses https protocol for embedding [tobiasd]
Better posting loop prevention for the Google+/Twitter/GS connectors [heluecht] Better posting loop prevention for the Google+/Twitter/GS connectors [annando]
One can now configure the message for wppost bridged blog postings [tobiasd] One can now configure the message for wppost bridged blog postings [tobiasd]
On some pages the result of the Rendertime is not shown anymore [heluecht] On some pages the result of the Rendertime is not shown anymore [annando]
Twitter-bridge now supports quotes and long posts when importing tweets [heluecht] Twitter-bridge now supports quotes and long posts when importing tweets [annando]
Closed Issues Closed Issues
1019, 1163, 1612, 1613, 2103, 2177, 2252, 2260, 2403, 2991, 2614, 1019, 1163, 1612, 1613, 2103, 2177, 2252, 2260, 2403, 2991, 2614,
@ -67,48 +121,48 @@ Version 3.5.1 (2017-03-12)
Version 3.5 (2016-09-13) Version 3.5 (2016-09-13)
Friendica Core: Friendica Core:
NEW Optional local directory with possible federated contacts [heluecht] NEW Optional local directory with possible federated contacts [annando]
NEW Autocompletion for @-mentions and BBCode tags [rabuzarus] NEW Autocompletion for @-mentions and BBCode tags [rabuzarus]
NEW Added a composer derived autoloader which allows composer autoloaders in addons/libraries [fabrixxm] NEW Added a composer derived autoloader which allows composer autoloaders in addons/libraries [fabrixxm]
NEW theme: frio [rabuzarus, heluecht, fabrixxm] NEW theme: frio [rabuzarus, annando, fabrixxm]
Enhance .htaccess file (nerdoc, dissolve) Enhance .htaccess file (nerdoc, dissolve)
Updates to the translations (DE, ES, IS, IT, RU) [translation teams] Updates to the translations (DE, ES, IS, IT, RU) [translation teams]
Updates to the documentation [tobiasd, heluecht, mexcon, silke, rabuzarus, fabrixxm, Olivier Mehani, gerhard6380, ben utzer] Updates to the documentation [tobiasd, annando, mexcon, silke, rabuzarus, fabrixxm, Olivier Mehani, gerhard6380, ben utzer]
Extended the BBCode by [abstract] tag used for bridged postings to networks with limited character length [heluecht] Extended the BBCode by [abstract] tag used for bridged postings to networks with limited character length [annando]
Code cleanup [heluecht, QuixOr] Code cleanup [annando, QuixOr]
Improvements to the API and Friendica specific extensions [heluecht, fabrixxm, gerhard6380] Improvements to the API and Friendica specific extensions [annando, fabrixxm, gerhard6380]
Improvements to the RSS/Atom feed import [mexcon] Improvements to the RSS/Atom feed import [mexcon]
Improvements to the communication with federated networks (Diaspora, Hubzilla, OStatus) [heluecht] Improvements to the communication with federated networks (Diaspora, Hubzilla, OStatus) [annando]
Improvements on the themes (quattro, vier, frost) [rabuzarus, fabrixxm, stieben, heluecht, Quix0r, tobiasd] Improvements on the themes (quattro, vier, frost) [rabuzarus, fabrixxm, stieben, annando, Quix0r, tobiasd]
Improvements to the ACL dialog [fabrixxm, rabuzarus] Improvements to the ACL dialog [fabrixxm, rabuzarus]
Improvements to the database structure and optimization of queries [heluecht] Improvements to the database structure and optimization of queries [annando]
Improvements to the UI (contacts, hotkeys, remember me, ARIA, code hightlighting) [rabuzarus, heluecht, tobiasd] Improvements to the UI (contacts, hotkeys, remember me, ARIA, code hightlighting) [rabuzarus, annando, tobiasd]
Improvements to the background process (poller, worker) [heluecht] Improvements to the background process (poller, worker) [annando]
Improvements to the admin panel [tobiasd, heluecht, fabrixxm] Improvements to the admin panel [tobiasd, annando, fabrixxm]
Improvements to the performance [heluecht] Improvements to the performance [annando]
Improvements to the installation wizzard (language selection, RINO version, check required PHP modules, default theme is now vier) [tobiasd] Improvements to the installation wizzard (language selection, RINO version, check required PHP modules, default theme is now vier) [tobiasd]
Improvements to the relocation of nodes and accounts [heluecht] Improvements to the relocation of nodes and accounts [annando]
Improvements to the DDoS detection [heluecht] Improvements to the DDoS detection [annando]
Improvements to the calendar/events module [heluecht, rabuzarus] Improvements to the calendar/events module [annando, rabuzarus]
Improvements to OpenID login [strk] Improvements to OpenID login [strk]
Improvements to the ShaShape font [andi] Improvements to the ShaShape font [andi]
Reworked the implementation of the DFRN, Diaspora protocols [heluecht] Reworked the implementation of the DFRN, Diaspora protocols [annando]
Reworked the notifications code [fabrixxm, rabuzarus, heluecht] Reworked the notifications code [fabrixxm, rabuzarus, annando]
Reworked the p/config code [fabrixxm, rabuzarus] Reworked the p/config code [fabrixxm, rabuzarus]
Reworked XML generation [heluecht] Reworked XML generation [annando]
Removed now unused simplepie from library [heluecht] Removed now unused simplepie from library [annando]
Friendica Addons Friendica Addons
Updated to the translations (DE, ES, IS, NL, PT BR), [translation teams] Updated to the translations (DE, ES, IS, NL, PT BR), [translation teams]
Piwik [tobiasd] Piwik [tobiasd]
Twitter Connector [heluecht] Twitter Connector [annando]
Pumpio Connector [heluecht] Pumpio Connector [annando]
Rendertime [heluecht] Rendertime [annando]
wppost [heluecht] wppost [annando]
showmore [rabuzarus] showmore [rabuzarus]
fromgplus [heluecht] fromgplus [annando]
app.net Connector [heluecht] app.net Connector [annando]
GNU Social Connector [heluecht] GNU Social Connector [annando]
LDAP [Olivier Mehani] LDAP [Olivier Mehani]
smileybutton [rabuzarus] smileybutton [rabuzarus]
retriver [mexon] retriver [mexon]

View file

@ -1 +1 @@
3.5.2-dev 3.5.3-dev

View file

@ -35,12 +35,13 @@ require_once 'include/features.php';
require_once 'include/identity.php'; require_once 'include/identity.php';
require_once 'update.php'; require_once 'update.php';
require_once 'include/dbstructure.php'; require_once 'include/dbstructure.php';
require_once 'include/poller.php';
define ( 'FRIENDICA_PLATFORM', 'Friendica'); define ( 'FRIENDICA_PLATFORM', 'Friendica');
define ( 'FRIENDICA_CODENAME', 'Asparagus'); define ( 'FRIENDICA_CODENAME', 'Asparagus');
define ( 'FRIENDICA_VERSION', '3.5.2-dev' ); define ( 'FRIENDICA_VERSION', '3.5.3-dev' );
define ( 'DFRN_PROTOCOL_VERSION', '2.23' ); define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
define ( 'DB_UPDATE_VERSION', 1224 ); define ( 'DB_UPDATE_VERSION', 1228 );
/** /**
* @brief Constant with a HTML line break. * @brief Constant with a HTML line break.
@ -457,6 +458,13 @@ if (!defined("SIGTERM")) {
define("SIGTERM", 15); define("SIGTERM", 15);
} }
/**
* Depending on the PHP version this constant does exist - or not.
* See here: http://php.net/manual/en/curl.constants.php#117928
*/
if (!defined('CURLE_OPERATION_TIMEDOUT')) {
define('CURLE_OPERATION_TIMEDOUT', CURLE_OPERATION_TIMEOUTED);
}
/** /**
* *
* Reverse the effect of magic_quotes_gpc if it is enabled. * Reverse the effect of magic_quotes_gpc if it is enabled.
@ -1088,18 +1096,8 @@ function proc_run($cmd) {
return; return;
} }
// Checking number of workers
$workers = q("SELECT COUNT(*) AS `workers` FROM `workerqueue` WHERE `executed` > '%s'", dbesc(NULL_DATE));
// Get number of allowed number of worker threads
$queues = intval(get_config("system", "worker_queues"));
if ($queues == 0) {
$queues = 4;
}
// If there are already enough workers running, don't fork another one // If there are already enough workers running, don't fork another one
if ($workers[0]["workers"] >= $queues) { if (poller_too_much_workers()) {
return; return;
} }
@ -1375,7 +1373,7 @@ function get_server() {
$server = get_config("system", "directory"); $server = get_config("system", "directory");
if ($server == "") { if ($server == "") {
$server = "http://dir.friendi.ca"; $server = "http://dir.friendica.social";
} }
return($server); return($server);

View file

@ -1,6 +1,6 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 3.5.2-dev (Asparagus) -- Friendica 3.5.3dev (Asparagus)
-- DB_UPDATE_VERSION 1221 -- DB_UPDATE_VERSION 1228
-- ------------------------------------------ -- ------------------------------------------
@ -193,7 +193,7 @@ CREATE TABLE IF NOT EXISTS `contact` (
-- --
CREATE TABLE IF NOT EXISTS `conv` ( CREATE TABLE IF NOT EXISTS `conv` (
`id` int(10) unsigned NOT NULL auto_increment, `id` int(10) unsigned NOT NULL auto_increment,
`guid` varchar(64) NOT NULL DEFAULT '', `guid` varchar(255) NOT NULL DEFAULT '',
`recips` text, `recips` text,
`uid` int(11) NOT NULL DEFAULT 0, `uid` int(11) NOT NULL DEFAULT 0,
`creator` varchar(255) NOT NULL DEFAULT '', `creator` varchar(255) NOT NULL DEFAULT '',
@ -270,7 +270,7 @@ CREATE TABLE IF NOT EXISTS `fcontact` (
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY(`id`), PRIMARY KEY(`id`),
INDEX `addr` (`addr`(32)), INDEX `addr` (`addr`(32)),
INDEX `url` (`url`) UNIQUE INDEX `url` (`url`(190))
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
-- --
@ -355,7 +355,7 @@ CREATE TABLE IF NOT EXISTS `gcontact` (
`generation` tinyint(3) NOT NULL DEFAULT 0, `generation` tinyint(3) NOT NULL DEFAULT 0,
`server_url` varchar(255) NOT NULL DEFAULT '', `server_url` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY(`id`), PRIMARY KEY(`id`),
INDEX `nurl` (`nurl`(64)), UNIQUE INDEX `nurl` (`nurl`(190)),
INDEX `name` (`name`(64)), INDEX `name` (`name`(64)),
INDEX `nick` (`nick`(32)), INDEX `nick` (`nick`(32)),
INDEX `addr` (`addr`(64)), INDEX `addr` (`addr`(64)),
@ -425,7 +425,7 @@ CREATE TABLE IF NOT EXISTS `gserver` (
`last_contact` datetime DEFAULT '0001-01-01 00:00:00', `last_contact` datetime DEFAULT '0001-01-01 00:00:00',
`last_failure` datetime DEFAULT '0001-01-01 00:00:00', `last_failure` datetime DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY(`id`), PRIMARY KEY(`id`),
INDEX `nurl` (`nurl`(32)) UNIQUE INDEX `nurl` (`nurl`(190))
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
-- --
@ -544,6 +544,7 @@ CREATE TABLE IF NOT EXISTS `item` (
INDEX `uid_parenturi` (`uid`,`parent-uri`(190)), INDEX `uid_parenturi` (`uid`,`parent-uri`(190)),
INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`), INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`),
INDEX `authorid_created` (`author-id`,`created`), INDEX `authorid_created` (`author-id`,`created`),
INDEX `ownerid` (`owner-id`),
INDEX `uid_uri` (`uid`,`uri`(190)), INDEX `uid_uri` (`uid`,`uri`(190)),
INDEX `resource-id` (`resource-id`), INDEX `resource-id` (`resource-id`),
INDEX `contactid_allowcid_allowpid_denycid_denygid` (`contact-id`,`allow_cid`(10),`allow_gid`(10),`deny_cid`(10),`deny_gid`(10)), INDEX `contactid_allowcid_allowpid_denycid_denygid` (`contact-id`,`allow_cid`(10),`allow_gid`(10),`deny_cid`(10),`deny_gid`(10)),
@ -579,7 +580,7 @@ CREATE TABLE IF NOT EXISTS `locks` (
`id` int(11) NOT NULL auto_increment, `id` int(11) NOT NULL auto_increment,
`name` varchar(128) NOT NULL DEFAULT '', `name` varchar(128) NOT NULL DEFAULT '',
`locked` tinyint(1) NOT NULL DEFAULT 0, `locked` tinyint(1) NOT NULL DEFAULT 0,
`created` datetime DEFAULT '0001-01-01 00:00:00', `pid` int(10) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY(`id`) PRIMARY KEY(`id`)
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
@ -589,7 +590,7 @@ CREATE TABLE IF NOT EXISTS `locks` (
CREATE TABLE IF NOT EXISTS `mail` ( CREATE TABLE IF NOT EXISTS `mail` (
`id` int(10) unsigned NOT NULL auto_increment, `id` int(10) unsigned NOT NULL auto_increment,
`uid` int(10) unsigned NOT NULL DEFAULT 0, `uid` int(10) unsigned NOT NULL DEFAULT 0,
`guid` varchar(64) NOT NULL DEFAULT '', `guid` varchar(255) NOT NULL DEFAULT '',
`from-name` varchar(255) NOT NULL DEFAULT '', `from-name` varchar(255) NOT NULL DEFAULT '',
`from-photo` varchar(255) NOT NULL DEFAULT '', `from-photo` varchar(255) NOT NULL DEFAULT '',
`from-url` varchar(255) NOT NULL DEFAULT '', `from-url` varchar(255) NOT NULL DEFAULT '',
@ -608,7 +609,8 @@ CREATE TABLE IF NOT EXISTS `mail` (
INDEX `uid_seen` (`uid`,`seen`), INDEX `uid_seen` (`uid`,`seen`),
INDEX `convid` (`convid`), INDEX `convid` (`convid`),
INDEX `uri` (`uri`(64)), INDEX `uri` (`uri`(64)),
INDEX `parent-uri` (`parent-uri`(64)) INDEX `parent-uri` (`parent-uri`(64)),
INDEX `contactid` (`contact-id`)
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;
-- --
@ -746,6 +748,7 @@ CREATE TABLE IF NOT EXISTS `photo` (
`deny_cid` mediumtext, `deny_cid` mediumtext,
`deny_gid` mediumtext, `deny_gid` mediumtext,
PRIMARY KEY(`id`), PRIMARY KEY(`id`),
INDEX `contactid` (`contact-id`),
INDEX `uid_contactid` (`uid`,`contact-id`), INDEX `uid_contactid` (`uid`,`contact-id`),
INDEX `uid_profile` (`uid`,`profile`), INDEX `uid_profile` (`uid`,`profile`),
INDEX `uid_album_scale_created` (`uid`,`album`(32),`scale`,`created`), INDEX `uid_album_scale_created` (`uid`,`album`(32),`scale`,`created`),
@ -1019,6 +1022,9 @@ CREATE TABLE IF NOT EXISTS `thread` (
INDEX `uid_network_created` (`uid`,`network`,`created`), INDEX `uid_network_created` (`uid`,`network`,`created`),
INDEX `uid_contactid_commented` (`uid`,`contact-id`,`commented`), INDEX `uid_contactid_commented` (`uid`,`contact-id`,`commented`),
INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`), INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`),
INDEX `contactid` (`contact-id`),
INDEX `ownerid` (`owner-id`),
INDEX `authorid` (`author-id`),
INDEX `uid_created` (`uid`,`created`), INDEX `uid_created` (`uid`,`created`),
INDEX `uid_commented` (`uid`,`commented`), INDEX `uid_commented` (`uid`,`commented`),
INDEX `uid_wall_created` (`uid`,`wall`,`created`) INDEX `uid_wall_created` (`uid`,`wall`,`created`)
@ -1108,6 +1114,9 @@ CREATE TABLE IF NOT EXISTS `workerqueue` (
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
`pid` int(11) NOT NULL DEFAULT 0, `pid` int(11) NOT NULL DEFAULT 0,
`executed` datetime NOT NULL DEFAULT '0001-01-01 00:00:00', `executed` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY(`id`) PRIMARY KEY(`id`),
INDEX `pid` (`pid`),
INDEX `parameter` (`parameter`(192)),
INDEX `priority_created` (`priority`,`created`)
) DEFAULT COLLATE utf8mb4_general_ci; ) DEFAULT COLLATE utf8mb4_general_ci;

View file

@ -10,10 +10,10 @@ Not all Friendica sites allow open registration.
If registration is allowed, you will see a "Register" link immediately below the login prompt on the site home page. If registration is allowed, you will see a "Register" link immediately below the login prompt on the site home page.
Following this link will take you to the site registration page. Following this link will take you to the site registration page.
The strength of our network is that lots of different sites are all completely compatible with each other. The strength of our network is that lots of different sites are all completely compatible with each other.
If the site you're visting doesn't allow registration, or you think you might prefer another one, you can find a [list of public servers here](http://dir.friendica.com/siteinfo), and find one that meets your needs. If the site you're visting doesn't allow registration, or you think you might prefer another one, you can find a [list of public servers here](https://dir.friendica.social/servers), and find one that meets your needs.
If you'd like to have your own server, you can do that too. If you'd like to have your own server, you can do that too.
Visit [the Friendica website](http://friendica.com/download) to download the code with setup instructions. Visit [the Friendica website](http://friendi.ca/) to download the code with setup instructions.
It's a very simple installation process that anybody experienced in hosting websites, or with basic Linux experience can handle easily. It's a very simple installation process that anybody experienced in hosting websites, or with basic Linux experience can handle easily.
###OpenID ###OpenID

View file

@ -61,17 +61,17 @@ table.bbcodes > * > tr > th {
<td><span style="color: red;">red</span></td> <td><span style="color: red;">red</span></td>
</tr> </tr>
<tr> <tr>
<td>[url=http://www.friendica.com]Friendica[/url]</td> <td>[url=http://friendi.ca]Friendica[/url]</td>
<td><a href="http://www.friendica.com" target="external-link">Friendica</a></td> <td><a href="http://friendi.ca" target="external-link">Friendica</a></td>
</tr> </tr>
<tr> <tr>
<td>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</td> <td>[img]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto"></td> <td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" alt="Immagine/foto"></td>
</tr> </tr>
<tr> <tr>
<td>[img=64x32]http://friendica.com/sites/default/files/friendika-32.png[/img]<br> <td>[img=64x32]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]<br>
<br>Note: provided height is simply discarded.</td> <br>Note: provided height is simply discarded.</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" style="width: 64px;"></td> <td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" style="width: 64px;"></td>
</tr> </tr>
<tr> <tr>
<td>[size=xx-small]small text[/size]</td> <td>[size=xx-small]small text[/size]</td>
@ -82,7 +82,7 @@ table.bbcodes > * > tr > th {
<td><span style="font-size: xx-large;">big text</span></td> <td><span style="font-size: xx-large;">big text</span></td>
</tr> </tr>
<tr> <tr>
<td>[size=20]exact size[/size] (size can be any number, in pixel)</td> <td>[size=20]exact size[/size] (size can be any number, in pixels)</td>
<td><span style="font-size: 20px;">exact size</span></td> <td><span style="font-size: 20px;">exact size</span></td>
</tr> </tr>
<tr> <tr>
@ -99,23 +99,23 @@ table.bbcodes > * > tr > th {
<th>Result</th> <th>Result</th>
</tr> </tr>
<tr> <tr>
<td>[url]http://friendica.com[/url]</td> <td>[url]http://friendi.ca[/url]</td>
<td><a href="http://friendica.com">http://friendica.com</a></td> <td><a href="http://friendi.ca">http://friendi.ca</a></td>
</tr> </tr>
<tr> <tr>
<td>[url=http://friendica.com]Friendica[/url]</td> <td>[url=http://friendi.ca]Friendica[/url]</td>
<td><a href="http://friendica.com">Friendica</a></td> <td><a href="http://friendi.ca">Friendica</a></td>
</tr> </tr>
<tr> <tr>
<td>[bookmark]http://friendica.com[/bookmark]<br><br> <td>[bookmark]http://friendi.ca[/bookmark]<br><br>
#^[url]http://friendica.com[/url]</td> #^[url]http://friendi.ca[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">http://friendica.com</a></h4></span></td> <td><span class="oembed link"><h4>Friendica: <a href="http://friendi.ca" rel="oembed"></a><a href="http://friendi.ca" target="_blank">http://friendi.ca</a></h4></span></td>
</tr> </tr>
<tr> <tr>
<td>[bookmark=http://friendica.com]Bookmark[/bookmark]<br><br> <td>[bookmark=http://friendi.ca]Bookmark[/bookmark]<br><br>
#^[url=http://friendica.com]Bookmark[/url]<br><br> #^[url=http://friendi.ca]Bookmark[/url]<br><br>
#[url=http://friendica.com]^[/url][url=http://friendica.com]Bookmark[/url]</td> #[url=http://friendi.ca]^[/url][url=http://friendi.ca]Bookmark[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">Bookmark</a></h4></span></td> <td><span class="oembed link"><h4>Friendica: <a href="http://friendi.ca" rel="oembed"></a><a href="http://friendi.ca" target="_blank">Bookmark</a></h4></span></td>
</tr> </tr>
<tr> <tr>
<td>[url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora post with GUID[/url]</td> <td>[url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora post with GUID[/url]</td>
@ -490,7 +490,7 @@ Page title with a link to *url* will be shown.</td>
## Map ## Map
This require "openstreetmap" or "Google Maps" addon version 1.3 or newer. This requires "openstreetmap" or "Google Maps" addon version 1.3 or newer.
If the addon isn't activated, the raw coordinates are shown instead. If the addon isn't activated, the raw coordinates are shown instead.
<table class="bbcodes"> <table class="bbcodes">
@ -514,10 +514,10 @@ If the addon isn't activated, the raw coordinates are shown instead.
## Abstract for longer posts ## Abstract for longer posts
If you want to spread your post to several third party networks you can have the problem that these networks have a length limitation like on Twitter. If you want to spread your post to several third party networks you may have the problem that these networks have a length limitation like on Twitter.
Friendica is using a semi intelligent mechanism to generate a fitting abstract. Friendica uses a semi-intelligent mechanism to generate a fitting abstract.
But it can be interesting to define a custom abstract that will only be displayed on the external network. But it can be useful to define a custom abstract that will only be displayed on the external network.
This is done with the [abstract]-element. This is done with the [abstract]-element.
<table class="bbcodes"> <table class="bbcodes">
<tr> <tr>
@ -566,7 +566,7 @@ Instead you have to name the explicit network:
<tr> <tr>
<td> <td>
[abstract]These days I had a strange encounter...[/abstract]<br> [abstract]These days I had a strange encounter...[/abstract]<br>
[abstract=goog]Helly my dear Google+ followers. You have to read my newest blog post![/abstract]<br> [abstract=goog]Hello my dear Google+ followers. You have to read my newest blog post![/abstract]<br>
[abstract=face]Hello my Facebook friends. These days happened something really cool.[/abstract]<br> [abstract=face]Hello my Facebook friends. These days happened something really cool.[/abstract]<br>
While taking pictures in the woods I had a really strange encounter...</td> While taking pictures in the woods I had a really strange encounter...</td>
<td>Google and Facebook will show the respective abstracts while the other networks will show the default one.<br> <td>Google and Facebook will show the respective abstracts while the other networks will show the default one.<br>
@ -574,7 +574,7 @@ While taking pictures in the woods I had a really strange encounter...</td>
</tr> </tr>
</table> </table>
The [abstract] element isn't working with connectors where we post the HTML like Tumblr, Wordpress or Pump.io. The [abstract] element is not working with connectors where we post HTML directly, like Tumblr, Wordpress or Pump.io.
For the native connections--that is to e.g. Friendica, Hubzilla, Diaspora or GNU Social--the full posting is used and the contacts instance will display the posting as desired. For the native connections--that is to e.g. Friendica, Hubzilla, Diaspora or GNU Social--the full posting is used and the contacts instance will display the posting as desired.
## Special ## Special

View file

@ -5,9 +5,9 @@ Bugs and Issues
If your server has a support page, you should report any bugs/issues you encounter there first. If your server has a support page, you should report any bugs/issues you encounter there first.
Reporting to your support page before reporting to the developers makes their job easier, as they don't have to deal with bug reports that might not have anything to do with them. Reporting to your support page before reporting to the developers makes their job easier, as they don't have to deal with bug reports that might not have anything to do with them.
This helps us get new features faster. Reducing the workload in this way helps us get new features faster.
You can also contact the [friendica support forum](https://helpers.pyxis.uberspace.de/profile/helpers) and report your problem there. You can also contact the [friendica support forum](https://helpers.pyxis.uberspace.de/profile/helpers) and report your problem there.
Maybe someone from another node encountered the problem as well and can help you. Bugs are rarely limited to one person, and the chances are somebody from another node has encountered the problem too, and will be able to help you.
If you're a technical user, or your site doesn't have a support page, you'll need to use the [Bug Tracker](https://github.com/friendica/friendica/issues). If you're a technical user, or your site doesn't have a support page, you'll need to use the [Bug Tracker](https://github.com/friendica/friendica/issues).
Please perform a search to see if there's already an open bug that matches yours before submitting anything. Please perform a search to see if there's already an open bug that matches yours before submitting anything.
@ -15,6 +15,6 @@ Please perform a search to see if there's already an open bug that matches yours
Try to provide as much information as you can about the bug, including the **full** text of any error messages or notices, and any steps required to replicate the problem in as much detail as possible. Try to provide as much information as you can about the bug, including the **full** text of any error messages or notices, and any steps required to replicate the problem in as much detail as possible.
It's generally better to provide too much information than not enough. It's generally better to provide too much information than not enough.
See [this article](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) to learn more about submitting **good** bug reports. See [this article](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) to learn more about submitting **good** bug reports. The better your bug report, the more likely we are to be able to actually fix it.
And last but not least: Better report an issue you encountered even if you don't write the perfect bug report! And last but not least: It is better to report an issue you encountered even if you can't write the perfect bug report!

View file

@ -3,7 +3,7 @@ Chats
* [Home](help) * [Home](help)
There are two possibilities to use a chat on your friendica site There are two possibilities to use chat on your friendica site
* IRC Chat * IRC Chat
* Jappix * Jappix
@ -14,13 +14,13 @@ IRC-Chat Plugin
After activating the plugin, you can find the chat at [yoursite.com/irc](../irc). After activating the plugin, you can find the chat at [yoursite.com/irc](../irc).
Note: you can use this chat without any login at your site so that everyone could use it. Note: you can use this chat without any login at your site so that everyone could use it.
If you follow the link, you will see the login page of the IR chat. If you follow the link, you will see the login page of the IRC chat.
Now choose a nickname and a chatroom. Now choose a nickname and a chatroom.
You can choose every name for the room, even something like #superchatwhosenameisonlyknownbyme. You can choose any name you like for the room, even something like #superchatwhosenameisonlyknownbyme.
At last, solve the captchas and click the connect button. Finally, solve the captchas and click the connect button.
The following window shows some text while connecting. The following window shows some text while connecting.
This text isn't importend for you, just wait for the next window. This text isn't important, just wait for the next window.
The first line shows your name and your current IP address. The first line shows your name and your current IP address.
The right part of the window shows all users. The right part of the window shows all users.
The lower part of the window contains an input field. The lower part of the window contains an input field.

View file

@ -176,7 +176,7 @@ Depending on the features of the client you might encounter some glitches in usa
###Where I can find help? ###Where I can find help?
If you have problems with your Friendica page, you can ask the community at the [Friendica Support Group](https://helpers.pyxis.uberspace.de/profile/helpers). If you have problems with your Friendica page, you can ask the community at the [Friendica Support Group](https://helpers.pyxis.uberspace.de/profile/helpers).
If you can't use your default profile you can either use a test account [test server](http://friendica.com/node/31) respectively an account at a public site [list](http://dir.friendica.com/siteinfo) or you can use the Librelist mailing list. If you can't use your default profile you can use an account at a public site [list](https://dir.friendica.social/servers) or you can use the Librelist mailing list.
If you want to use the mailing list, please just send a mail to friendica AT librelist DOT com. If you want to use the mailing list, please just send a mail to friendica AT librelist DOT com.
If you are a theme developer, you will find help at this forum: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs). If you are a theme developer, you will find help at this forum: [Friendica Theme Developers](https://friendica.eu/profile/ftdevs).
@ -188,7 +188,7 @@ Admin
###Can I configure multiple domains with the same code instance? ###Can I configure multiple domains with the same code instance?
No, this function is no longer supported from Friendica 3.3 onwards. No, this function is no longer supported as of Friendica 3.3 onwards.
<a name="sources"></a> <a name="sources"></a>

View file

@ -22,7 +22,7 @@ This is the default selection.
Community Forum/Celebrity Accounts provide the ability for people to become friends/fans of the forum without requiring approval. Community Forum/Celebrity Accounts provide the ability for people to become friends/fans of the forum without requiring approval.
The exact setting you would use depends on how you wish to interact with people who join the page. The exact setting you would use depends on how you wish to interact with people who join the page.
The "Soapbox" setting let's the page owner control all communications. The "Soapbox" setting lets the page owner control all communications.
Everything you post will go out to the forum members, but there will be no opportunity for interaction. Everything you post will go out to the forum members, but there will be no opportunity for interaction.
This setting would typically be used for announcements or corporate communications. This setting would typically be used for announcements or corporate communications.

View file

@ -9,7 +9,7 @@ How do you do it?
The Directories The Directories
--- ---
Friendica has two different kinds of "addressbook": Friendica has two different kinds of "address book":
The directory of the Friendica server you are registered on and the global directory that collects account information across all Friendica instances. The directory of the Friendica server you are registered on and the global directory that collects account information across all Friendica instances.
The first thing you can do is look at the **Directory**. The first thing you can do is look at the **Directory**.

View file

@ -130,7 +130,7 @@ By default, any (valid) email address is allowed in registrations.
#### Allow Users to set remote_self #### Allow Users to set remote_self
If you enable the `Allow Users to set remote_self` users can select Atom feeds from their contact list being their *remote self* in die advanced contact settings. If you enable the `Allow Users to set remote_self` users can select Atom feeds from their contact list being their *remote self* in the advanced contact settings.
Which means that postings by the remote self are automatically reposted by Friendica in their names. Which means that postings by the remote self are automatically reposted by Friendica in their names.
This feature can be used to let the user mirror e.g. blog postings into their Friendica postings. This feature can be used to let the user mirror e.g. blog postings into their Friendica postings.
@ -212,7 +212,7 @@ To simplify this process there is a button at the top of the page to reload all
## Themes ## Themes
The Themes section of the admin panel works similar to the Plugins section but let you control the themes on your Friendica node. The Themes section of the admin panel works similar to the Plugins section but let you control the themes on your Friendica node.
Each theme has a dedicated suppage showing the current status, some information about the theme and a screen-shot of the Friendica interface using the theme. Each theme has a dedicated subpage showing the current status, some information about the theme and a screen-shot of the Friendica interface using the theme.
Should the theme offer special settings, admins can set a global default value here. Should the theme offer special settings, admins can set a global default value here.
You can activate and deactivate themes on their dedicated sub-pages thus making them available for the users of the node. You can activate and deactivate themes on their dedicated sub-pages thus making them available for the users of the node.

View file

@ -1,22 +0,0 @@
[[!meta title="And Finally..."]]
And that brings the Quick Start to an end.
Here are some more things to help get you started:
**Groups**
- <a href="http://helpers.pyxis.uberspace.de/profile/helpers">Friendica Support</a> - problems? This is the place to ask.
- <a href="https://letstalk.pyxis.uberspace.de/profile/letstalk">Let's Talk</a> a group for finding people and groups who share similar interests.
- <a href="http://newzot.hydra.uberspace.de/profile/newzot">Local Friendica</a> a page for local Friendica groups</a>
**Documentation**
- <a href="help/Connectors">Connecting to more networks</a>
- <a href="help">Help Index</a>

View file

@ -3,7 +3,7 @@ Friendica API
* [Home](help) * [Home](help)
The Friendica API aims to be compatible to the [GNU Social API](http://wiki.gnusocial.de/gnusocial:api) and the [Twitter API](https://dev.twitter.com/rest/public). The Friendica API aims to be compatible with the [GNU Social API](http://wiki.gnusocial.de/gnusocial:api) and the [Twitter API](https://dev.twitter.com/rest/public).
Please refer to the linked documentation for further information. Please refer to the linked documentation for further information.
@ -43,13 +43,13 @@ In this document, endpoints which requires auth are marked with "AUTH" after end
* network: network of the user * network: network of the user
#### Errors #### Errors
When an error occour in API call, an HTTP error code is returned, with an error message When an error occurs in API call, an HTTP error code is returned, with an error message
Usually: Usually:
- 400 Bad Request: if parameter are missing or items can't be found - 400 Bad Request: if parameters are missing or items can't be found
- 403 Forbidden: if authenticated user is missing - 403 Forbidden: if the authenticated user is missing
- 405 Method Not Allowed: if API was called with invalid method, eg. GET when API require POST - 405 Method Not Allowed: if API was called with an invalid method, eg. GET when API require POST
- 501 Not Implemented: if requested API doesn't exists - 501 Not Implemented: if the requested API doesn't exist
- 500 Internal Server Error: on other error contitions - 500 Internal Server Error: on other error conditions
Error body is Error body is
@ -89,7 +89,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original
* id: id of the post * id: id of the post
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false)
@ -103,7 +103,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain" * getText: Defines the format of the status field. Can be "html" or "plain"
* include_entities: "true" shows entities for pictures and links (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false)
@ -117,7 +117,7 @@ Unofficial Twitter command. It shows all direct answers (excluding the original
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain" * getText: Defines the format of the status field. Can be "html" or "plain"
* friendica_verbose: "true" enables different error returns (default: "false") * friendica_verbose: "true" enables different error returns (default: "false")
@ -128,7 +128,7 @@ Shows all direct messages of a conversation
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain" * getText: Defines the format of the status field. Can be "html" or "plain"
* uri: URI of the conversation * uri: URI of the conversation
@ -139,7 +139,7 @@ Shows all direct messages of a conversation
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* getText: Defines the format of the status field. Can be "html" or "plain" * getText: Defines the format of the status field. Can be "html" or "plain"
* include_entities: "true" shows entities for pictures and links (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false)
@ -182,7 +182,7 @@ HTTP 400 BadRequest
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false)
@ -208,26 +208,26 @@ Set this values will result in an empty array.
--- ---
### followers/ids (*; AUTH) ### followers/ids (*; AUTH)
#### Parameters #### Parameters
* stringify_ids: Should the id numbers be sent as text (true) or number (false)? (default: false) * stringify_ids: Send id numbers as text (true) or integers (false)? (default: false)
#### Unsupported parameters #### Unsupported parameters
* user_id * user_id
* screen_name * screen_name
* cursor * cursor
Friendica doesn't allow showing followers of other users. Friendica doesn't allow showing the followers of other users.
--- ---
### friends/ids (*; AUTH) ### friends/ids (*; AUTH)
#### Parameters #### Parameters
* stringify_ids: Should the id numbers be sent as text (true) or number (false)? (default: false) * stringify_ids: Send the id numbers as text (true) or integers (false)? (default: false)
#### Unsupported parameters #### Unsupported parameters
* user_id * user_id
* screen_name * screen_name
* cursor * cursor
Friendica doesn't allow showing friends of other users. Friendica doesn't allow showing the friends of other users.
--- ---
### help/test (*) ### help/test (*)
@ -283,7 +283,7 @@ Friendica doesn't allow showing friends of other users.
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* exclude_replies: don't show replies (default: false) * exclude_replies: don't show replies (default: false)
* conversation_id: Shows all statuses of a given conversation. * conversation_id: Shows all statuses of a given conversation.
@ -299,7 +299,7 @@ Friendica doesn't allow showing friends of other users.
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* exclude_replies: don't show replies (default: false) * exclude_replies: don't show replies (default: false)
* conversation_id: Shows all statuses of a given conversation. * conversation_id: Shows all statuses of a given conversation.
@ -315,7 +315,7 @@ Friendica doesn't allow showing friends of other users.
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false)
@ -329,7 +329,7 @@ Friendica doesn't allow showing friends of other users.
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* exclude_replies: don't show replies (default: false) * exclude_replies: don't show replies (default: false)
* conversation_id: Shows all statuses of a given conversation. * conversation_id: Shows all statuses of a given conversation.
@ -343,7 +343,7 @@ Friendica doesn't allow showing friends of other users.
#### Parameters #### Parameters
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false)
@ -403,7 +403,7 @@ Friendica doesn't allow showing friends of other users.
* screen_name: screen name (for technical reasons, this value is not unique!) * screen_name: screen name (for technical reasons, this value is not unique!)
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* exclude_replies: don't show replies (default: false) * exclude_replies: don't show replies (default: false)
* conversation_id: Shows all statuses of a given conversation. * conversation_id: Shows all statuses of a given conversation.
@ -426,7 +426,7 @@ It shows all direct answers (excluding the original post) to a given id.
* id: id of the post * id: id of the post
* count: Items per page (default: 20) * count: Items per page (default: 20)
* page: page number * page: page number
* since_id: minimal id * since_id: minimum id
* max_id: maximum id * max_id: maximum id
* include_entities: "true" shows entities for pictures and links (Default: false) * include_entities: "true" shows entities for pictures and links (Default: false)
@ -640,7 +640,7 @@ If the note is linked to an item, the item is returned, just like one of the "st
If the note is not linked to an item, a success status is returned: If the note is not linked to an item, a success status is returned:
* "success" (json) | "&lt;status&gt;success&lt;/status&gt;" (xml) * "success" (json) | <status>success</status>;" (xml)
--- ---
@ -671,8 +671,8 @@ json
``` ```
{ {
"id": "photo id" "id": "photo id"
"created": "date(YYYY-MM-GG HH:MM:SS)", "created": "date(YYYY-MM-DD HH:MM:SS)",
"edited": "date(YYYY-MM-GG HH:MM:SS)", "edited": "date(YYYY-MM-DD HH:MM:SS)",
"title": "photo title", "title": "photo title",
"desc": "photo description", "desc": "photo description",
"album": "album name", "album": "album name",
@ -695,8 +695,8 @@ xml
``` ```
<photo> <photo>
<id>photo id</id> <id>photo id</id>
<created>date(YYYY-MM-GG HH:MM:SS)</created> <created>date(YYYY-MM-DD HH:MM:SS)</created>
<edited>date(YYYY-MM-GG HH:MM:SS)</edited> <edited>date(YYYY-MM-DD HH:MM:SS)</edited>
<title>photo title</title> <title>photo title</title>
<desc>photo description</desc> <desc>photo description</desc>
<album>album name</album> <album>album name</album>
@ -793,13 +793,13 @@ On error:
* album: name of the album to be deleted (always necessary) * album: name of the album to be deleted (always necessary)
* album_new (optional): can be used to change the album of a single photo if photo_id is specified * album_new (optional): can be used to change the album of a single photo if photo_id is specified
* allow_cid/allow_gid/deny_cid/deny_gid (optional): on create: empty string or omitting = public photo, specify in format '```<x><y><z>```' for private photo; * allow_cid/allow_gid/deny_cid/deny_gid (optional): on create: empty string or omitting = public photo, specify in format '```<x><y><z>```' for private photo;
on update: keys need to be present with empty values for setting a private photo now to public on update: keys need to be present with empty values for changing a private photo to public
both calls point to one function for creating AND updating photos. both calls point to one function for creating AND updating photos.
Saves data for the scales 0-2 to database (see above for scale description). Saves data for the scales 0-2 to database (see above for scale description).
Call adds non-visible entries to items table to enable authenticated contacts to comment/like the photo. Call adds non-visible entries to items table to enable authenticated contacts to comment/like the photo.
Client should pay attention to the fact that updated access rights are not transferred to the contacts. i.e. public photos remain publicly visible if they have been commented/liked before setting visibility back to a limited group. Client should pay attention to the fact that updated access rights are not transferred to the contacts. i.e. public photos remain publicly visible if they have been commented/liked before setting visibility back to a limited group.
Currently it is best way to inform user that updating rights is not the best way, offer a solution to add photo as a new photo with the new rights. Currently it is best to inform user that updating rights is not the right way to do this, and offer a solution to add photo as a new photo with the new rights instead.
#### Return values #### Return values
@ -884,8 +884,8 @@ On success: Array of:
* profiles: array of the profile data * profiles: array of the profile data
On error: On error:
HTTP 403 Forbidden: when no authentication provided HTTP 403 Forbidden: when no authentication was provided
HTTP 400 Bad Request: if given profile_id is not in db or not assigned to authenticated user HTTP 400 Bad Request: if given profile_id is not in the database or is not assigned to the authenticated user
General description of profile data in API returns: General description of profile data in API returns:
* profile_id * profile_id
@ -913,7 +913,7 @@ The following API calls are implemented in GNU Social but not in Friendica: (inc
* blocks/create * blocks/create
* blocks/destroy * blocks/destroy
The following API calls from the Twitter API aren't implemented neither in Friendica nor in GNU Social: The following API calls from the Twitter API are not implemented in either Friendica or GNU Social:
* statuses/mentions_timeline * statuses/mentions_timeline
* statuses/retweets/:id * statuses/retweets/:id
@ -990,7 +990,6 @@ The following API calls from the Twitter API aren't implemented neither in Frien
## Usage Examples ## Usage Examples
### BASH / cURL ### BASH / cURL
Betamax has documentated some example API usage from a [bash script](https://en.wikipedia.org/wiki/Bash_(Unix_shell) employing [curl](https://en.wikipedia.org/wiki/CURL) (see [his posting](https://betamax65.de/display/betamax65/43539)).
/usr/bin/curl -u USER:PASS https://YOUR.FRIENDICA.TLD/api/statuses/update.xml -d source="some source id" -d status="the status you want to post" /usr/bin/curl -u USER:PASS https://YOUR.FRIENDICA.TLD/api/statuses/update.xml -d source="some source id" -d status="the status you want to post"

View file

@ -2,10 +2,10 @@ Table locks
=========== ===========
| Field | Description | Type | Null | Key | Default | Extra | | Field | Description | Type | Null | Key | Default | Extra |
|---------|------------------|--------------|------|-----|---------------------|----------------| |---------|------------------|------------------|------|-----|---------------------|----------------|
| id | sequential ID | int(11) | NO | PRI | NULL | auto_increment | | id | sequential ID | int(11) | NO | PRI | NULL | auto_increment |
| name | | varchar(128) | NO | | | | | name | | varchar(128) | NO | | | |
| locked | | tinyint(1) | NO | | 0 | | | locked | | tinyint(1) | NO | | 0 | |
| created | | datetime | YES | | 0001-01-01 00:00:00 | | | pid | Process ID | int(10) unsigned | NO | | 0 | |
Return to [database documentation](help/database) Return to [database documentation](help/database)

View file

@ -9,10 +9,10 @@ Account - Basics
Nicht alle Friendica-Knoten bieten die Möglichkeit zur Registrierung. Nicht alle Friendica-Knoten bieten die Möglichkeit zur Registrierung.
Wenn die Registrierung möglich ist, wird ein "Registrieren"-Link unter dem Login-Feld auf der Startseite angezeigt, der zur Registrierungsseite führt. Wenn die Registrierung möglich ist, wird ein "Registrieren"-Link unter dem Login-Feld auf der Startseite angezeigt, der zur Registrierungsseite führt.
Die Stärke unseres Netzwerks ist, dass die verschiedenen Knoten komplett kompatibel zueinander sind. Die Stärke unseres Netzwerks ist, dass die verschiedenen Knoten komplett kompatibel zueinander sind.
Wenn der Knoten, den Du besuchst, keine Registrierung anbietet, oder wenn Du glaubst, dass Dir eine andere Seite möglicherweise besser gefällt, dann kannst Du hier eine <a href="http://dir.friendica.com/siteinfo">Liste von öffentlichen Servern (Knoten)</a> finden und den Knoten heraus suchen, der am Besten zu Deinen Anforderungen passt. Wenn der Knoten, den Du besuchst, keine Registrierung anbietet, oder wenn Du glaubst, dass Dir eine andere Seite möglicherweise besser gefällt, dann kannst Du hier eine <a href="https://dir.friendica.social/servers">Liste von öffentlichen Servern (Knoten)</a> finden und den Knoten heraus suchen, der am Besten zu Deinen Anforderungen passt.
Wenn Du Deinen eigenen Server aufsetzen willst, kannst Du das ebenfalls machen. Wenn Du Deinen eigenen Server aufsetzen willst, kannst Du das ebenfalls machen.
Besuche <a href="http://friendica.com/download">die Friendica-Webseite</a>, um den Code mit den Installationsanleitungen herunterzuladen. Besuche <a href="http://friendi.ca">die Friendica-Webseite</a>, um den Code mit den Installationsanleitungen herunterzuladen.
Es ist ein einfacher Installationsprozess, den jeder mit ein wenig Erfahrungen im Webseiten-Hosting oder mit grundlegenden Linux-Erfahrungen einfach handhaben kann. Es ist ein einfacher Installationsprozess, den jeder mit ein wenig Erfahrungen im Webseiten-Hosting oder mit grundlegenden Linux-Erfahrungen einfach handhaben kann.

View file

@ -61,17 +61,17 @@ table.bbcodes > * > tr > th {
<td><span style="color: red;">rot</span></td> <td><span style="color: red;">rot</span></td>
</tr> </tr>
<tr> <tr>
<td>[url=http://www.friendica.com]Friendica[/url]</td> <td>[url=http://friendi.ca]Friendica[/url]</td>
<td><a href="http://www.friendica.com" target="external-link">Friendica</a></td> <td><a href="http://friendi.ca" target="external-link">Friendica</a></td>
</tr> </tr>
<tr> <tr>
<td>[img]http://friendica.com/sites/default/files/friendika-32.png[/img]</td> <td>[img]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" alt="Immagine/foto"></td> <td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" alt="Immagine/foto"></td>
</tr> </tr>
<tr> <tr>
<td>[img=64x32]http://friendica.com/sites/default/files/friendika-32.png[/img]<br> <td>[img=64x32]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]<br>
<br>Note: provided height is simply discarded.</td> <br>Note: provided height is simply discarded.</td>
<td><img src="http://friendica.com/sites/default/files/friendika-32.png" style="width: 64px;"></td> <td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" style="width: 64px;"></td>
</tr> </tr>
<tr> <tr>
<td>[size=xx-small]kleiner Text[/size]</td> <td>[size=xx-small]kleiner Text[/size]</td>
@ -99,23 +99,23 @@ table.bbcodes > * > tr > th {
<th>Ergebnis</th> <th>Ergebnis</th>
</tr> </tr>
<tr> <tr>
<td>[url]http://friendica.com[/url]</td> <td>[url]http://friendi.ca[/url]</td>
<td><a href="http://friendica.com">http://friendica.com</a></td> <td><a href="http://friendi.ca">http://friendi.ca</a></td>
</tr> </tr>
<tr> <tr>
<td>[url=http://friendica.com]Friendica[/url]</td> <td>[url=http://friendi.ca.com]Friendica[/url]</td>
<td><a href="http://friendica.com">Friendica</a></td> <td><a href="http://friendi.ca.com">Friendica</a></td>
</tr> </tr>
<tr> <tr>
<td>[bookmark]http://friendica.com[/bookmark]<br><br> <td>[bookmark]http://friendi.ca[/bookmark]<br><br>
#^[url]http://friendica.com[/url]</td> #^[url]http://friendi.ca[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">http://friendica.com</a></h4></span></td> <td><span class="oembed link"><h4>Friendica: <a href="http://friendi.ca" rel="oembed"></a><a href="http://friendi.ca" target="_blank">http://friendi.ca</a></h4></span></td>
</tr> </tr>
<tr> <tr>
<td>[bookmark=http://friendica.com]Lesezeichen[/bookmark]<br><br> <td>[bookmark=http://friendi.ca]Lesezeichen[/bookmark]<br><br>
#^[url=http://friendica.com]Lesezeichen[/url]<br><br> #^[url=http://friendi.ca]Lesezeichen[/url]<br><br>
#[url=http://friendica.com]^[/url][url=http://friendica.com]Lesezeichen[/url]</td> #[url=http://friendi.ca]^[/url][url=http://friendi.ca]Lesezeichen[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendica.com" rel="oembed"></a><a href="http://friendica.com" target="_blank">Lesezeichen</a></h4></span></td> <td><span class="oembed link"><h4>Friendica: <a href="http://friendi.ca" rel="oembed"></a><a href="http://friendi.ca" target="_blank">Lesezeichen</a></h4></span></td>
</tr> </tr>
<tr> <tr>
<td>[url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora Beitrag mit GUID[/url]</td> <td>[url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora Beitrag mit GUID[/url]</td>

View file

@ -1,19 +0,0 @@
... und zuletzt
===============
Und damit sind wir auch schon am Ende der Schnellstartanleitung.
Hier sind noch einige weitere Dinge, die Dir den Start vereinfachen können.
**Gruppen**
- <a href="http://helpers.pyxis.uberspace.de/profile/helpers">Friendica Support</a> - Probleme? Dann ist das der Platz, um zu fragen!
**Dokumentation**
- <a href="help/Connectors">Zu weiteren Netzwerken verbinden</a>
- <a href="help">Zur Startseite der Hilfe</a>

View file

@ -1,27 +0,0 @@
Neue Freunde finden
==============
* [Zur Startseite der Hilfe](help)
Hier siehst du die Kontaktvorschläge.
Wenn du dich mal verirrt hast, kannst du <a href="help/makenewfriends">diesen Link klicken</a> und wieder hierher kommen.
Diese Seite ist ein wenig wie die Kontaktvorschläge in Facebook.
Jeder auf dieser Liste hat zugestimmt, als Kontaktvorschlag zu erscheinen.
Das bedeutet, das sie Anfragen meist nicht ablehnen, da sie neue Leute kennenlernen wollen.
Siehst du jemanden, dessen Aussehen du magst?
Klicke auf den "Verbinden"-Button beim Foto.
Als nächstes kommst du zur Seite "Freundschafts-/Kontaktanfrage".
Fülle das Formular wie vorgegeben aus und trage optional eine kleine Notiz ein.
Nun musst du nur noch auf die Bestätigung warten.
Beachte dabei, dass es sich um reale Personen handelt und es somit etwas dauern kann.
Jetzt, nachdem du jemanden hinzugefügt hast, weißt du vielleicht nicht mehr, wie du zurückkommst.
Klicke einfach auf den Link oben auf dieser Seite und du kommst zurück zur Seite mit den Kontaktvorschlägen, um weitere Personen hinzuzufügen.
Du willst nicht einfach Personen hinzufügen, die du nicht kennst?
Kein Problem - an dieser Stelle kommen wir zu den <a href="help/groupsandpages">Gruppen und Seiten</a>.
<iframe src="suggest" width="950" height="600"></iframe>

View file

@ -1,20 +0,0 @@
Deine "Netzwerk"-Seite
==============
* [Zur Startseite der Hilfe](help)
Das ist dein "Netzwerk"-Tab.
Wenn du dich mal verirrt hast, kannst du <a href="help/network">diesen Link klicken</a>, um wieder hierher zu kommen.
Diese Seite ist ein wenig wie die News-Seite in Facebook oder der Stream in Diaspora.
Hier findest du alle Beiträge deiner Kontakte, Gruppen und Feeds, die du eingetragen hast.
Wenn du neu bist, siehst du hier noch nichts, falls du deinen Status im letzten Schritt noch nicht eingetragen hast.
Wenn du bereits ein paar Freunde eingetragen hast, findest du hier ihre Beiträge.
Hier kannst du Beiträge kommentieren, eintragen, dass du den Beitrag magst oder ablehnst oder die Profile durch einen Klick auf deren Namen anschauen und auf deren Seite ("Wall") Nachrichten schreiben.
Nun wollen wir diese Seite mit Inhalt füllen.
Der erste Schritt ist es, Leute <a href="help/makingnewfriends">zu deinem Account hinzuzufügen</a>.
<iframe src="network" width="950" height="600"></iframe>

View file

@ -9,15 +9,15 @@ Depending on the theme you are using, there might be an additional link from the
## Event Overview ## Event Overview
The overview page shows the calendar of the current month, plus eventually some days in the beginning and the end. The overview page shows the calendar of the current month, plus a few days days at the beginning and the end.
Listed are all events for this month you created, or your contacts have shared with you. Listed are all events for this month, created by you, or shared with you by your contacts,
This includes birthday reminders for contacts who share their birthday with you. This includes birthday reminders for contacts who share their birthday with you.
From the controls, you can switch between month/week/day view. From the controls, you can switch between month/week/day view.
Flip through the view forwards and backwards. Flip through the view forwards and backwards.
And return to *today*. And return to *today*.
To create a new event, you can either follow the link "Create New Event" or make a double click on the desired box in the calendarium for when the event should take place. To create a new event, you can either follow the link "Create New Event" or double click on the desired box in the calendar in which the event should take place.
With a click on an existing event a pop-up box will be opened which shows you the event. With a click on an existing event a pop-up box will be opened which shows you the event.
From there you can edit the event or view the event at the source link, if you are the one who created the event. From there you can edit the event or view the event at the source link, if you are the one who created the event.
@ -31,14 +31,14 @@ Fields marked with a *** have to be filled.
* **Event Finishes**: enter the finishing date/time for the event here * **Event Finishes**: enter the finishing date/time for the event here
When you click in one of these fields a pop-up will be opened that allows you to pick the day and the time. When you click in one of these fields a pop-up will be opened that allows you to pick the day and the time.
If you double clicked on the day box in the calendarium these fields will be pre-filled for you. If you double clicked on the day box in the calendar these fields will be pre-filled for you.
The finishing date/time has to be after the beginning date/time of the event. The finishing date/time has to be after the beginning date/time of the event.
But you don't have to specify it. But you don't have to specify it.
If the event is open-end or the finishing date/time does not matter, just select the box below the two first fields. If the event is open-ended or the finishing date/time does not matter, just select the box below the two first fields.
* **Adjust for viewer timezone**: If you check this box, the beginning and finisching times will automatically converted to the local time according to the timezone setting * **Adjust for viewer timezone**: If you check this box, the beginning and finishing times will automatically converted to the local time according to the timezone setting
This might prevent too early birthday wishes, or the panic attac that you have forgotten the birthday from your buddy at the other end of the world. This might prevent early birthday wishes, or the panic that you have forgotten the birthday from your buddy at the other side of the world.
And similar events. And similar events.
* **Title**: a title for the event * **Title**: a title for the event
@ -46,7 +46,7 @@ And similar events.
* **Location**: the location the event will took place * **Location**: the location the event will took place
These three fields describe your events. These three fields describe your events.
In the descirption and location field you can use BBCode to format the text. In the description and location field you can use BBCode to format the text.
* **Share this event**: when this box is checked the ACL will be shown to let you select with whom you wish to share the event. This works just like the controls of any other posting. * **Share this event**: when this box is checked the ACL will be shown to let you select with whom you wish to share the event. This works just like the controls of any other posting.
@ -59,13 +59,13 @@ When you publish an event, you can choose who shall receive it, as with a regula
The recipients will see the posting about the event in their network-stream. The recipients will see the posting about the event in their network-stream.
Additionally it will be added to their calendar and thus be shown in their events overview page. Additionally it will be added to their calendar and thus be shown in their events overview page.
Recipients of the event-posting can comment or dis-/like the event, as with a regular posting, but also announce that they will attend, not attend or may-be attend the event with a single click. Recipients of the event-posting can comment or dis-/like the event, as with a regular posting, and also announce that they will attend, not attend or may-be attend the event with a single click.
### Addons ### Addons
#### OpenStreetMap #### OpenStreetMap
If this addon is activated on you friendica node, the content of the location field will be mathced with the identification service of OSM when you submit the event. If this addon is activated on you friendica node, the content of the location field will be matched with the identification service of OSM when you submit the event.
Should OSM find anything matching, a map for the location will be embedded automatically at the end of the events view. Should OSM find anything matching, a map for the location will be embedded automatically at the end of the events view.
#### Calendar Export #### Calendar Export

View file

@ -1,11 +0,0 @@
This is the global directory. If you get lost, you can <a href = "help/groupsandpages">click this link</a> to bring yourself back here.
On this page, you'll find a collection of groups, forums and celebrity pages. Groups are not real people. Connecting to them is similar to "liking" something on Facebook, or signing up for a new forum. You don't have to feel awkward about introducing yourself to a new person, because they're not people!
When you connect to a group, all messages to that group will start appearing in your network tab. You can comment on these posts, or post to the group yourself without ever having to add any of the groups members. This is a great way to make friends dynamically - you'll find people you like and add each other naturally instead of adding random strangers. Simply find a group you're interested in, and connect to it the same way you did with people in the last section. There are a lot of groups, and you're likely to get lost. Remember the link at the top of this page will bring you back here.
Once you've added some groups, <a href="help/andfinally">move on to the next section</a>.
<iframe src="http://dir.friendica.com/directory/forum" width="950" height="600"></iframe>

View file

@ -1,13 +0,0 @@
First things first, let's make sure you're logged in to your account. If you're not already logged in, do so in the frame below.
Once you've logged in (or if you are already logged in), you'll now be looking at your profile page.
This is a bit like your Facebook wall. It's where all your status messgages are kept, and where your friends come to post on your wall. To write your status, simply click in the box that says "share". When you do this, the box will expand. You can see some formatting options at the top such as Bold, Italics and Underline, as well as ways to add links and pictures. At the bottom you'll find some more links. You can use these to upload pictures and files from your computer, share websites with a bit of preview text, or embed video and audio files from elsewhere on the web. You can also set your post location here.
Once you've finished writing your post, click on the padlock icon to select who can see it. If you do not use the padlock icon, your post will be public. This means it will appear to anybody who views your profile, and in the community tab if your site has it enabled, as well as in the network tab of any of your contacts.
Play around with this a bit, then when you're ready to move on, we'll take a look at the <a href="help/network">Network Tab</a>
<iframe src="login" width="950" height="600"></iframe>

View file

@ -14,7 +14,7 @@ Especially don't do that with undocumented values.
The header of the section describes the category, the value is the parameter. The header of the section describes the category, the value is the parameter.
Example: To set the directory value please add this line to your .htconfig.php: Example: To set the directory value please add this line to your .htconfig.php:
$a->config['system']['directory'] = 'http://dir.friendi.ca'; $a->config['system']['directory'] = 'http://dir.friendica.social';
## jabber ## ## jabber ##
* **debug** (Boolean) - Enable debug level for the jabber account synchronisation. * **debug** (Boolean) - Enable debug level for the jabber account synchronisation.
@ -25,7 +25,7 @@ Example: To set the directory value please add this line to your .htconfig.php:
* **allowed_link_protocols** (Array) - Allowed protocols in links URLs, add at your own risk. http is always allowed. * **allowed_link_protocols** (Array) - Allowed protocols in links URLs, add at your own risk. http is always allowed.
* **birthday_input_format** - Default value is "ymd". * **birthday_input_format** - Default value is "ymd".
* **block_local_dir** (Boolean) - Blocks the access to the directory of the local users. * **block_local_dir** (Boolean) - Blocks the access to the directory of the local users.
* **auth_cookie_lifetime** (Integer) - Number of days that should pass without any activity from a before before the users who choosed "Remember me" when logging in from that browser is considered logged out. Defaults to 7. * **auth_cookie_lifetime** (Integer) - Number of days that should pass without any activity before a user who chose "Remember me" when logging in is considered logged out. Defaults to 7.
* **curl_range_bytes** - Maximum number of bytes that should be fetched. Default is 0, which mean "no limit". * **curl_range_bytes** - Maximum number of bytes that should be fetched. Default is 0, which mean "no limit".
* **db_log** - Name of a logfile to log slow database queries * **db_log** - Name of a logfile to log slow database queries
* **db_loglimit** - If a database call lasts longer than this value it is logged * **db_loglimit** - If a database call lasts longer than this value it is logged
@ -35,24 +35,27 @@ Example: To set the directory value please add this line to your .htconfig.php:
* **db_loglimit_index_high** - Number of index rows to be logged anyway (for any index) * **db_loglimit_index_high** - Number of index rows to be logged anyway (for any index)
* **db_log_index_blacklist** - Blacklist of indexes that shouldn't be watched * **db_log_index_blacklist** - Blacklist of indexes that shouldn't be watched
* **dbclean** (Boolean) - Enable the automatic database cleanup process * **dbclean** (Boolean) - Enable the automatic database cleanup process
* **dbclean-expire-days** (Integer) - Days after which remote items will be deleted. Own items, and marked or filed items are kept.
* **default_service_class** - * **default_service_class** -
* **delivery_batch_count** - Number of deliveries per process. Default value is 1. (Disabled when using the worker) * **delivery_batch_count** - Number of deliveries per process. Default value is 1. (Disabled when using the worker)
* **diaspora_test** (Boolean) - For development only. Disables the message transfer. * **diaspora_test** (Boolean) - For development only. Disables the message transfer.
* **directory** - The path to global directory. If not set then "http://dir.friendi.ca" is used. * **directory** - The path to global directory. If not set then "http://dir.friendica.social" is used.
* **disable_email_validation** (Boolean) - Disables the check if a mail address is in a valid format and can be resolved via DNS. * **disable_email_validation** (Boolean) - Disables the check if a mail address is in a valid format and can be resolved via DNS.
* **disable_url_validation** (Boolean) - Disables the DNS lookup of an URL. * **disable_url_validation** (Boolean) - Disables the DNS lookup of an URL.
* **dlogfile - location of the developer log file
* **event_input_format** - Default value is "ymd". * **event_input_format** - Default value is "ymd".
* **frontend_worker_timeout** - Value in minutes after we think that a frontend task was killed by the webserver. Default value is 10. * **frontend_worker_timeout** - Value in minutes after we think that a frontend task was killed by the webserver. Default value is 10.
* **ignore_cache** (Boolean) - For development only. Disables the item cache. * **ignore_cache** (Boolean) - For development only. Disables the item cache.
* **like_no_comment** (Boolean) - Don't update the "commented" value of an item when it is liked. * **like_no_comment** (Boolean) - Don't update the "commented" value of an item when it is liked.
* **local_block** (Boolean) - Used in conjunction with "block_public". * **local_block** (Boolean) - Used in conjunction with "block_public".
* **local_search** (Boolean) - Blocks the search for not logged in users to prevent crawlers from blocking your system. * **local_search** (Boolean) - Blocks search for users who are not logged in to prevent crawlers from blocking your system.
* **max_connections** - The poller process isn't started when the maximum level of the possible database connections are used. When the system can't detect the maximum numbers of connection then this value can be used. * **max_connections** - The maximum number of database connections which can be in use before the poller process is deferred to it's next interval. When the system can't detect the maximum numbers of connection then this value can be used.
* **max_connections_level** - The maximum level of connections that are allowed to let the poller start. It is a percentage value. Default value is 75. * **max_connections_level** - The maximum level of connections that are allowed to let the poller start. It is a percentage value. Default value is 75.
* **max_contact_queue** - Default value is 500. * **max_contact_queue** - Default value is 500.
* **max_batch_queue** - Default value is 1000. * **max_batch_queue** - Default value is 1000.
* **max_processes_backend** - Maximum number of concurrent database processes for background tasks. Default value is 5. * **max_processes_backend** - Maximum number of concurrent database processes for background tasks. Default value is 5.
* **max_processes_frontend** - Maximum number of concurrent database processes for foreground tasks. Default value is 20. * **max_processes_frontend** - Maximum number of concurrent database processes for foreground tasks. Default value is 20.
* **min_poll_interval** - minimal distance in minutes between two polls for a contact. Default is 1. Reasonable values are between 1 and 59.
* **memcache** (Boolean) - Use memcache. To use memcache the PECL extension "memcache" has to be installed and activated. * **memcache** (Boolean) - Use memcache. To use memcache the PECL extension "memcache" has to be installed and activated.
* **memcache_host** - Hostname of the memcache daemon. Default is '127.0.0.1'. * **memcache_host** - Hostname of the memcache daemon. Default is '127.0.0.1'.
* **memcache_port** - Portnumber of the memcache daemon. Default is 11211. * **memcache_port** - Portnumber of the memcache daemon. Default is 11211.

View file

@ -1,11 +0,0 @@
This is your Suggested Friends page. If you get lost, you can <a href="help/makenewfriends">click this link</a> to bring yourself back here.
This is a bit like the Friend Suggestions page of Facebook. Everybody on this list has agreed that they may be suggested as a friend. This means they're unlikely to refuse an introduction you send, and they want to meet new people too!
See somebody you like the look of? Click the connect button beneath their photograph. This will bring you to the introductions page. Fill in the form as instructed, and add a small note (optional). Now, wait a bit and they'll accept your request - note that these are real people, and it might take a while. Now you've added one, you're probably lost. Click the link at the top of this page to go back to the suggested friends list and add some more.
Feel uncomfortable adding people you don't know? Don't worry - that's where <a href="help/groupsandpages">Groups and Pages</a> come in!
<iframe src="suggest" width="950" height="600"></iframe>

View file

@ -1,14 +0,0 @@
This is your Network Tab.
If you get lost, you can <a href="help/network">click this link</a> to bring yourself back here.
This is a bit like the Newsfeed at Facebook or the Stream at Diaspora.
It's where all the posts from your contacts, groups, and feeds will appear.
If you're new, you won't see anything in this page, unless you posted your status in the last step.
If you've already added a few friends, you'll be able to see their posts.
Here, you can comment, like, or dislike posts, or click on somebody's name to visit their profile page where you can write on their wall.
Now we need to fill it up, the first step, is to <a href="help/makingnewfriends"> make some new friends</a>.
<iframe src="network" width="950" height="600"></iframe>

View file

@ -35,7 +35,7 @@ Form Templates
To guarantee a consistent look and feel for input forms, i.e. in the settings sections, there are templates for the basic form fields. They are initialized with an array of data, depending on the tyle of the field. To guarantee a consistent look and feel for input forms, i.e. in the settings sections, there are templates for the basic form fields. They are initialized with an array of data, depending on the tyle of the field.
All of these take an array for holding the values, i.e. for an one line text input field, which is required and should be used to type email addesses use something along All of these take an array for holding the values, eg,. for a one line text input field, which is required and should be used to type email addesses use something along the lines of:
'$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Your account email address must match this in order to use the web admin panel.'), 'required', '', 'email'), '$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Your account email address must match this in order to use the web admin panel.'), 'required', '', 'email'),

View file

@ -3,7 +3,7 @@
* [Home](help) * [Home](help)
To change the look of friendica you have to touch the themes. To change the look of friendica you have to touch the themes.
The current default theme is [duepunto zero](https://github.com/friendica/friendica/tree/master/view/theme/duepuntozero) but there are numerous others. The current default theme is [Vier](https://github.com/friendica/friendica/tree/master/view/theme/vier) but there are numerous others.
Have a look at [friendica-themes.com](http://friendica-themes.com) for an overview of the existing themes. Have a look at [friendica-themes.com](http://friendica-themes.com) for an overview of the existing themes.
In case none of them suits your needs, there are several ways to change a theme. In case none of them suits your needs, there are several ways to change a theme.
If you need help theming, there is a forum @[ftdevs@friendica.eu](https://friendica.eu/profile/ftdevs) where you can ask theme specific questions and present your themes. If you need help theming, there is a forum @[ftdevs@friendica.eu](https://friendica.eu/profile/ftdevs) where you can ask theme specific questions and present your themes.
@ -69,7 +69,7 @@ Many themes are more *theme families* then only one theme.
*duepunto zero* and *vier* allow easily to add new theme variation. *duepunto zero* and *vier* allow easily to add new theme variation.
We will go through the process of creating a new variation for *duepunto zero*. We will go through the process of creating a new variation for *duepunto zero*.
The same (well almost, some names change) procedure applies to the *vier* theme. The same (well almost, some names change) procedure applies to the *vier* theme.
And similar steps are needed for *quattro* but this theme is using [lessc](http://lesscss.org/#docs) to maintaine the CSS files.. And similar steps are needed for *quattro* but this theme is using [lessc](http://lesscss.org/#docs) to maintain the CSS files..
In In
@ -202,7 +202,7 @@ That done, you can select it in the settings like any other activated theme.
## Creating a Theme from Scratch ## Creating a Theme from Scratch
Keep patient. Keep patient.
Basically what you have to do is identifying which template you have to change so it looks more like what you want. Basically what you have to do is identify which template you have to change so it looks more like what you want.
Adopt the CSS of the theme accordingly. Adopt the CSS of the theme accordingly.
And iterate the process until you have the theme the way you want it. And iterate the process until you have the theme the way you want it.
@ -243,11 +243,11 @@ For example, have a look at the theme.php of the *quattro* theme:
*/ */
You see the definition of the themes name, it's version and the initial author of the theme. You see the definition of the themes name, it's version and the initial author of the theme.
These three information should be listed. These three pieces of information should be listed.
If the original author is not anymore working on the theme, but a maintainer has taken over, the maintainer should be listed as well. If the original author is no longer working on the theme, but a maintainer has taken over, the maintainer should be listed as well.
The information from the theme header will be displayed in the admin panelö. The information from the theme header will be displayed in the admin panelö.
Next crucial part of the theme.php file is a definition of an init function. The next crucial part of the theme.php file is a definition of an init function.
The name of the function is <theme-name>_init. The name of the function is <theme-name>_init.
So in the case of quattro it is So in the case of quattro it is
@ -256,7 +256,7 @@ So in the case of quattro it is
set_template_engine($a, 'smarty3'); set_template_engine($a, 'smarty3');
} }
Here we have set the basic theme information, in this case they are empthy. Here we have set the basic theme information, in this case they are empty.
But the array needs to be set. But the array needs to be set.
And we have set the template engine that should be used by friendica for this theme. And we have set the template engine that should be used by friendica for this theme.
At the moment you should use the *smarty3* engine. At the moment you should use the *smarty3* engine.

View file

@ -6,7 +6,7 @@ Friendica translations
Translation Process Translation Process
------------------- -------------------
The strings used in the UI of Friendica is translated at [Transifex] [1] and then included in the git repository at github. The strings used in the UI of Friendica are translated at [Transifex] [1] and then included in the git repository at github.
If you want to help with translation for any language, be it correcting terms or translating friendica to a currently not supported language, please register an account at transifex.com and contact the friendica translation team there. If you want to help with translation for any language, be it correcting terms or translating friendica to a currently not supported language, please register an account at transifex.com and contact the friendica translation team there.
Translating friendica is simple. Translating friendica is simple.
@ -22,7 +22,7 @@ If you want to help translating, please concentrate on the core messages.po file
We will only include translations with a sufficient translated messages.po file. We will only include translations with a sufficient translated messages.po file.
Translations of addons will only be included, when the core file is included as well. Translations of addons will only be included, when the core file is included as well.
If you want to get your work into the source tree yourself, feel free to do so and contact us with and question that arises. If you want to get your work into the source tree yourself, feel free to do so and contact us with and questions that arise.
The process is simple and friendica ships with all the tools necessary. The process is simple and friendica ships with all the tools necessary.
The location of the translated files in the source tree is The location of the translated files in the source tree is

View file

@ -4,10 +4,12 @@
* @brief Methods for read and write notifications from/to database * @brief Methods for read and write notifications from/to database
* or for formatting notifications * or for formatting notifications
*/ */
require_once 'include/html2plain.php'; require_once 'include/html2plain.php';
require_once 'include/probe.php'; require_once 'include/probe.php';
require_once 'include/datetime.php'; require_once 'include/datetime.php';
require_once 'include/bbcode.php'; require_once 'include/bbcode.php';
require_once 'include/Contact.php';
/** /**
* @brief Methods for read and write notifications from/to database * @brief Methods for read and write notifications from/to database
@ -720,10 +722,12 @@ class NotificationsManager {
$sql_extra = " AND `ignore` = 0 "; $sql_extra = " AND `ignore` = 0 ";
/// @todo Fetch contact details by "get_contact_details_by_url" instead of queries to contact, fcontact and gcontact /// @todo Fetch contact details by "get_contact_details_by_url" instead of queries to contact, fcontact and gcontact
$r = q("SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*, `fcontact`.`name` AS `fname`,`fcontact`.`url` AS `furl`,`fcontact`.`photo` AS `fphoto`,`fcontact`.`request` AS `frequest`, $r = q("SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*,
`fcontact`.`name` AS `fname`, `fcontact`.`url` AS `furl`,
`fcontact`.`photo` AS `fphoto`, `fcontact`.`request` AS `frequest`,
`gcontact`.`location` AS `glocation`, `gcontact`.`about` AS `gabout`, `gcontact`.`location` AS `glocation`, `gcontact`.`about` AS `gabout`,
`gcontact`.`keywords` AS `gkeywords`, `gcontact`.`gender` AS `ggender`, `gcontact`.`keywords` AS `gkeywords`, `gcontact`.`gender` AS `ggender`,
`gcontact`.`network` AS `gnetwork` `gcontact`.`network` AS `gnetwork`, `gcontact`.`addr` AS `gaddr`
FROM `intro` FROM `intro`
LEFT JOIN `contact` ON `contact`.`id` = `intro`.`contact-id` LEFT JOIN `contact` ON `contact`.`id` = `intro`.`contact-id`
LEFT JOIN `gcontact` ON `gcontact`.`nurl` = `contact`.`nurl` LEFT JOIN `gcontact` ON `gcontact`.`nurl` = `contact`.`nurl`
@ -786,11 +790,7 @@ class NotificationsManager {
// Normal connection requests // Normal connection requests
} else { } else {
// Probe the contact url to get missing data $it = $this->getMissingIntroData($it);
$ret = probe_url($it["url"]);
if ($it['gnetwork'] == "")
$it['gnetwork'] = $ret["network"];
// Don't show these data until you are connected. Diaspora is doing the same. // Don't show these data until you are connected. Diaspora is doing the same.
if($it['gnetwork'] === NETWORK_DIASPORA) { if($it['gnetwork'] === NETWORK_DIASPORA) {
@ -815,7 +815,7 @@ class NotificationsManager {
'post_newfriend' => (intval(get_pconfig(local_user(),'system','post_newfriend')) ? '1' : 0), 'post_newfriend' => (intval(get_pconfig(local_user(),'system','post_newfriend')) ? '1' : 0),
'url' => $it['url'], 'url' => $it['url'],
'zrl' => zrl($it['url']), 'zrl' => zrl($it['url']),
'addr' => $ret['addr'], 'addr' => $it['gaddr'],
'network' => $it['gnetwork'], 'network' => $it['gnetwork'],
'knowyou' => $it['knowyou'], 'knowyou' => $it['knowyou'],
'note' => $it['note'], 'note' => $it['note'],
@ -827,4 +827,38 @@ class NotificationsManager {
return $arr; return $arr;
} }
/**
* @brief Check for missing contact data and try to fetch the data from
* from other sources
*
* @param array $arr The input array with the intro data
*
* @return array The array with the intro data
*/
private function getMissingIntroData($arr) {
// If the network and the addr isn't available from the gcontact
// table entry, take the one of the contact table entry
if ($arr['gnetwork'] == "") {
$arr['gnetwork'] = $arr['network'];
}
if ($arr['gaddr'] == "") {
$arr['gaddr'] = $arr['addr'];
}
// If the network and addr is still not available
// get the missing data data from other sources
if ($arr['gnetwork'] == "" || $arr['gaddr'] == "") {
$ret = get_contact_details_by_url($arr['url']);
if ($arr['gnetwork'] == "" && $ret['network'] != "") {
$arr['gnetwork'] = $ret['network'];
}
if ($arr['gaddr'] == "" && $ret['addr'] != "") {
$arr['gaddr'] = $ret['addr'];
}
}
return $arr;
}
} }

View file

@ -778,8 +778,7 @@ function guess_image_type($filename, $fromcurl=false) {
* @return array Returns array of the different avatar sizes * @return array Returns array of the different avatar sizes
*/ */
function update_contact_avatar($avatar, $uid, $cid, $force = false) { function update_contact_avatar($avatar, $uid, $cid, $force = false) {
$r = q("SELECT `avatar`, `photo`, `thumb`, `micro`, `nurl` FROM `contact` WHERE `id` = %d LIMIT 1", intval($cid));
$r = q("SELECT `avatar`, `photo`, `thumb`, `micro` FROM `contact` WHERE `id` = %d LIMIT 1", intval($cid));
if (!dbm::is_result($r)) { if (!dbm::is_result($r)) {
return false; return false;
} else { } else {
@ -793,6 +792,15 @@ function update_contact_avatar($avatar, $uid, $cid, $force = false) {
q("UPDATE `contact` SET `avatar` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' WHERE `id` = %d", q("UPDATE `contact` SET `avatar` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s', `avatar-date` = '%s' WHERE `id` = %d",
dbesc($avatar), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc($avatar), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]),
dbesc(datetime_convert()), intval($cid)); dbesc(datetime_convert()), intval($cid));
// Update the public contact (contact id = 0)
if ($uid != 0) {
$pcontact = dba::select('contact', array('id'), array('nurl' => $r[0]['nurl']), array('limit' => 1));
if (dbm::is_result($pcontact)) {
update_contact_avatar($avatar, 0, $pcontact['id'], $force);
}
}
return $photos; return $photos;
} }
} }
@ -847,9 +855,30 @@ function import_profile_photo($photo, $uid, $cid, $quit_on_error = false) {
$photo_failure = true; $photo_failure = true;
} }
$photo = App::get_baseurl() . '/photo/' . $hash . '-4.' . $img->getExt(); $suffix = '?ts='.time();
$thumb = App::get_baseurl() . '/photo/' . $hash . '-5.' . $img->getExt();
$micro = App::get_baseurl() . '/photo/' . $hash . '-6.' . $img->getExt(); $photo = App::get_baseurl() . '/photo/' . $hash . '-4.' . $img->getExt() . $suffix;
$thumb = App::get_baseurl() . '/photo/' . $hash . '-5.' . $img->getExt() . $suffix;
$micro = App::get_baseurl() . '/photo/' . $hash . '-6.' . $img->getExt() . $suffix;
// Remove the cached photo
$a = get_app();
$basepath = $a->get_basepath();
if (is_dir($basepath."/photo")) {
$filename = $basepath.'/photo/'.$hash.'-4.'.$img->getExt();
if (file_exists($filename)) {
unlink($filename);
}
$filename = $basepath.'/photo/'.$hash.'-5.'.$img->getExt();
if (file_exists($filename)) {
unlink($filename);
}
$filename = $basepath.'/photo/'.$hash.'-6.'.$img->getExt();
if (file_exists($filename)) {
unlink($filename);
}
}
} else { } else {
$photo_failure = true; $photo_failure = true;
} }

View file

@ -456,10 +456,13 @@ $called_api = null;
* Contact url or False if contact id is unknown * Contact url or False if contact id is unknown
*/ */
function api_unique_id_to_url($id) { function api_unique_id_to_url($id) {
$r = q("SELECT `url` FROM `contact` WHERE `uid` = 0 AND `id` = %d LIMIT 1", $r = dba::select('contact', array('url'), array('uid' => 0, 'id' => $id), array('limit' => 1));
intval($id));
return (dbm::is_result($r) && $r[0]["url"]); if (dbm::is_result($r)) {
return $r["url"];
} else {
return false;
}
} }
/** /**
@ -2286,6 +2289,11 @@ $called_api = null;
$statushtml = "<h4>" . bbcode($item['title']) . "</h4>\n" . $statushtml; $statushtml = "<h4>" . bbcode($item['title']) . "</h4>\n" . $statushtml;
} }
// feeds without body should contain the link
if (($item['network'] == NETWORK_FEED) && (strlen($item['body']) == 0)) {
$statushtml .= bbcode($item['plink']);
}
$entities = api_get_entitities($statustext, $body); $entities = api_get_entitities($statustext, $body);
return array( return array(
@ -3027,8 +3035,9 @@ $called_api = null;
api_best_nickname($r); api_best_nickname($r);
$recipient = api_get_user($a, $r[0]['nurl']); $recipient = api_get_user($a, $r[0]['nurl']);
} else } else {
$recipient = api_get_user($a, $_POST['user_id']); $recipient = api_get_user($a, $_POST['user_id']);
}
$replyto = ''; $replyto = '';
$sub = ''; $sub = '';
@ -3740,8 +3749,7 @@ $called_api = null;
proc_run(PRIORITY_LOW, "include/directory.php", $url); proc_run(PRIORITY_LOW, "include/directory.php", $url);
} }
require_once 'include/profile_update.php'; proc_run(PRIORITY_LOW, 'include/profile_update.php', api_user());
profile_change();
// output for client // output for client
if ($data) { if ($data) {

View file

@ -122,6 +122,8 @@ function cron_poll_contacts($argc, $argv) {
$force = true; $force = true;
} }
$min_poll_interval = Config::get('system', 'min_poll_interval', 1);
$sql_extra = (($manual_id) ? " AND `id` = $manual_id " : ""); $sql_extra = (($manual_id) ? " AND `id` = $manual_id " : "");
reload_plugins(); reload_plugins();
@ -195,7 +197,7 @@ function cron_poll_contacts($argc, $argv) {
$contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3); $contact['priority'] = (($poll_interval !== false) ? intval($poll_interval) : 3);
} }
if ($contact['priority'] AND !$force) { if (($contact['priority'] >= 0) AND !$force) {
$update = false; $update = false;
$t = $contact['last-update']; $t = $contact['last-update'];
@ -225,11 +227,16 @@ function cron_poll_contacts($argc, $argv) {
} }
break; break;
case 1: case 1:
default:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 hour")) { if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + 1 hour")) {
$update = true; $update = true;
} }
break; break;
case 0:
default:
if (datetime_convert('UTC', 'UTC', 'now') > datetime_convert('UTC', 'UTC', $t . " + ".$min_poll_interval." minute")) {
$update = true;
}
break;
} }
if (!$update) { if (!$update) {
continue; continue;
@ -239,10 +246,11 @@ function cron_poll_contacts($argc, $argv) {
logger("Polling " . $contact["network"] . " " . $contact["id"] . " " . $contact["nick"] . " " . $contact["name"]); logger("Polling " . $contact["network"] . " " . $contact["id"] . " " . $contact["nick"] . " " . $contact["name"]);
if (($contact['network'] == NETWORK_FEED) AND ($contact['priority'] <= 3)) { if (($contact['network'] == NETWORK_FEED) AND ($contact['priority'] <= 3)) {
proc_run(PRIORITY_MEDIUM, 'include/onepoll.php', intval($contact['id'])); $priority = PRIORITY_MEDIUM;
} else { } else {
proc_run(PRIORITY_LOW, 'include/onepoll.php', intval($contact['id'])); $priority = PRIORITY_LOW;
} }
proc_run(array('priority' => $priority, 'dont_fork' => true), 'include/onepoll.php', intval($contact['id']));
} }
} }
} }

View file

@ -459,6 +459,27 @@ class dba {
return $sql; return $sql;
} }
/**
* @brief beautifies the query - useful for "SHOW PROCESSLIST"
*
* This is safe when we bind the parameters later.
* The parameter values aren't part of the SQL.
*
* @param string $sql An SQL string without the values
* @return string The input SQL string modified if necessary.
*/
public function clean_query($sql) {
$search = array("\t", "\n", "\r", " ");
$replace = array(' ', ' ', ' ', ' ');
do {
$oldsql = $sql;
$sql = str_replace($search, $replace, $sql);
} while ($oldsql != $sql);
return $sql;
}
/** /**
* @brief Replaces the ? placeholders with the parameters in the $args array * @brief Replaces the ? placeholders with the parameters in the $args array
* *
@ -521,6 +542,7 @@ class dba {
logger('Parameter mismatch. Query "'.$sql.'" - Parameters '.print_r($args, true), LOGGER_DEBUG); logger('Parameter mismatch. Query "'.$sql.'" - Parameters '.print_r($args, true), LOGGER_DEBUG);
} }
$sql = self::$dbo->clean_query($sql);
$sql = self::$dbo->any_value_fallback($sql); $sql = self::$dbo->any_value_fallback($sql);
if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) { if (x($a->config,'system') && x($a->config['system'], 'db_callstack')) {
@ -708,6 +730,9 @@ class dba {
* @return int Number of rows * @return int Number of rows
*/ */
static public function num_rows($stmt) { static public function num_rows($stmt) {
if (!is_object($stmt)) {
return 0;
}
switch (self::$dbo->driver) { switch (self::$dbo->driver) {
case 'pdo': case 'pdo':
return $stmt->rowCount(); return $stmt->rowCount();
@ -781,6 +806,41 @@ class dba {
return self::e($sql, $param); return self::e($sql, $param);
} }
/**
* @brief Locks a table for exclusive write access
*
* This function can be extended in the future to accept a table array as well.
*
* @param string $table Table name
*
* @return boolean was the lock successful?
*/
static public function lock($table) {
// See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html
self::e("SET autocommit=0");
$success = self::e("LOCK TABLES `".self::$dbo->escape($table)."` WRITE");
if (!$success) {
self::e("SET autocommit=1");
} else {
self::$in_transaction = true;
}
return $success;
}
/**
* @brief Unlocks all locked tables
*
* @return boolean was the unlock successful?
*/
static public function unlock() {
// See here: https://dev.mysql.com/doc/refman/5.7/en/lock-tables-and-transactions.html
self::e("COMMIT");
$success = self::e("UNLOCK TABLES");
self::e("SET autocommit=1");
self::$in_transaction = false;
return $success;
}
/** /**
* @brief Starts a transaction * @brief Starts a transaction
* *
@ -1200,6 +1260,7 @@ function q($sql) {
unset($args[0]); unset($args[0]);
if ($db && $db->connected) { if ($db && $db->connected) {
$sql = $db->clean_query($sql);
$sql = $db->any_value_fallback($sql); $sql = $db->any_value_fallback($sql);
$stmt = @vsprintf($sql,$args); // Disabled warnings $stmt = @vsprintf($sql,$args); // Disabled warnings
//logger("dba: q: $stmt", LOGGER_ALL); //logger("dba: q: $stmt", LOGGER_ALL);
@ -1237,6 +1298,7 @@ function qu($sql) {
unset($args[0]); unset($args[0]);
if ($db && $db->connected) { if ($db && $db->connected) {
$sql = $db->clean_query($sql);
$sql = $db->any_value_fallback($sql); $sql = $db->any_value_fallback($sql);
$stmt = @vsprintf($sql,$args); // Disabled warnings $stmt = @vsprintf($sql,$args); // Disabled warnings
if ($stmt === false) if ($stmt === false)

View file

@ -17,9 +17,14 @@ function dbclean_run(&$argv, &$argc) {
$stage = 0; $stage = 0;
} }
// Get the expire days for step 8 and 9
$days = Config::get('system', 'dbclean-expire-days', 0);
if ($stage == 0) { if ($stage == 0) {
for ($i = 1; $i <= 7; $i++) { for ($i = 1; $i <= 9; $i++) {
if (!Config::get('system', 'finished-dbclean-'.$i)) { // Execute the background script for a step when it isn't finished.
// Execute step 8 and 9 only when $days is defined.
if (!Config::get('system', 'finished-dbclean-'.$i, false) AND (($i < 8) OR ($days > 0))) {
proc_run(PRIORITY_LOW, 'include/dbclean.php', $i); proc_run(PRIORITY_LOW, 'include/dbclean.php', $i);
} }
} }
@ -30,6 +35,19 @@ function dbclean_run(&$argv, &$argc) {
/** /**
* @brief Remove orphaned database entries * @brief Remove orphaned database entries
* @param integer $stage What should be deleted?
*
* Values for $stage:
* ------------------
* 1: Old global item entries from item table without user copy.
* 2: Items without parents.
* 3: Orphaned data from thread table.
* 4: Orphaned data from notify table.
* 5: Orphaned data from notify-threads table.
* 6: Orphaned data from sign table.
* 7: Orphaned data from term table.
* 8: Expired threads.
* 9: Old global item entries from expired threads
*/ */
function remove_orphans($stage = 0) { function remove_orphans($stage = 0) {
global $db; global $db;
@ -39,141 +57,246 @@ function remove_orphans($stage = 0) {
// We split the deletion in many small tasks // We split the deletion in many small tasks
$limit = 1000; $limit = 1000;
// Get the expire days for step 8 and 9
$days = Config::get('system', 'dbclean-expire-days', 0);
if ($stage == 1) { if ($stage == 1) {
logger("Deleting old global item entries from item table without user copy"); $last_id = Config::get('system', 'dbclean-last-id-1', 0);
$r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0
AND NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) logger("Deleting old global item entries from item table without user copy. Last ID: ".$last_id);
AND `received` < UTC_TIMESTAMP() - INTERVAL 90 DAY LIMIT ".intval($limit)); $r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
`received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id);
$count = dba::num_rows($r); $count = dba::num_rows($r);
if ($count > 0) { if ($count > 0) {
logger("found global item orphans: ".$count); logger("found global item orphans: ".$count);
while ($orphan = dba::fetch($r)) { while ($orphan = dba::fetch($r)) {
$last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"])); dba::delete('item', array('id' => $orphan["id"]));
} }
} else { } else {
logger("No global item orphans found"); logger("No global item orphans found");
} }
dba::close($r); dba::close($r);
logger("Done deleting ".$count." old global item entries from item table without user copy"); logger("Done deleting ".$count." old global item entries from item table without user copy. Last ID: ".$last_id);
// We will eventually set this value when we found a good way to delete these items in another way. Config::set('system', 'dbclean-last-id-1', $last_id);
// if ($count < $limit) {
// Config::set('system', 'finished-dbclean-1', true);
// }
} elseif ($stage == 2) { } elseif ($stage == 2) {
logger("Deleting items without parents"); $last_id = Config::get('system', 'dbclean-last-id-2', 0);
$r = dba::p("SELECT `id` FROM `item` WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`) LIMIT ".intval($limit));
logger("Deleting items without parents. Last ID: ".$last_id);
$r = dba::p("SELECT `id` FROM `item`
WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`)
AND `id` >= ? ORDER BY `id` LIMIT ".intval($limit), $last_id);
$count = dba::num_rows($r); $count = dba::num_rows($r);
if ($count > 0) { if ($count > 0) {
logger("found item orphans without parents: ".$count); logger("found item orphans without parents: ".$count);
while ($orphan = dba::fetch($r)) { while ($orphan = dba::fetch($r)) {
$last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"])); dba::delete('item', array('id' => $orphan["id"]));
} }
} else { } else {
logger("No item orphans without parents found"); logger("No item orphans without parents found");
} }
dba::close($r); dba::close($r);
logger("Done deleting ".$count." items without parents"); logger("Done deleting ".$count." items without parents. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-2', $last_id);
if ($count < $limit) { if ($count < $limit) {
Config::set('system', 'finished-dbclean-2', true); Config::set('system', 'finished-dbclean-2', true);
} }
} elseif ($stage == 3) { } elseif ($stage == 3) {
logger("Deleting orphaned data from thread table"); $last_id = Config::get('system', 'dbclean-last-id-3', 0);
$r = dba::p("SELECT `iid` FROM `thread` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) LIMIT ".intval($limit));
logger("Deleting orphaned data from thread table. Last ID: ".$last_id);
$r = dba::p("SELECT `iid` FROM `thread`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) AND `iid` >= ?
ORDER BY `iid` LIMIT ".intval($limit), $last_id);
$count = dba::num_rows($r); $count = dba::num_rows($r);
if ($count > 0) { if ($count > 0) {
logger("found thread orphans: ".$count); logger("found thread orphans: ".$count);
while ($orphan = dba::fetch($r)) { while ($orphan = dba::fetch($r)) {
$last_id = $orphan["iid"];
dba::delete('thread', array('iid' => $orphan["iid"])); dba::delete('thread', array('iid' => $orphan["iid"]));
} }
} else { } else {
logger("No thread orphans found"); logger("No thread orphans found");
} }
dba::close($r); dba::close($r);
logger("Done deleting ".$count." orphaned data from thread table"); logger("Done deleting ".$count." orphaned data from thread table. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-3', $last_id);
if ($count < $limit) { if ($count < $limit) {
Config::set('system', 'finished-dbclean-3', true); Config::set('system', 'finished-dbclean-3', true);
} }
} elseif ($stage == 4) { } elseif ($stage == 4) {
logger("Deleting orphaned data from notify table"); $last_id = Config::get('system', 'dbclean-last-id-4', 0);
$r = dba::p("SELECT `iid` FROM `notify` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) LIMIT ".intval($limit));
logger("Deleting orphaned data from notify table. Last ID: ".$last_id);
$r = dba::p("SELECT `iid`, `id` FROM `notify`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id);
$count = dba::num_rows($r); $count = dba::num_rows($r);
if ($count > 0) { if ($count > 0) {
logger("found notify orphans: ".$count); logger("found notify orphans: ".$count);
while ($orphan = dba::fetch($r)) { while ($orphan = dba::fetch($r)) {
$last_id = $orphan["id"];
dba::delete('notify', array('iid' => $orphan["iid"])); dba::delete('notify', array('iid' => $orphan["iid"]));
} }
} else { } else {
logger("No notify orphans found"); logger("No notify orphans found");
} }
dba::close($r); dba::close($r);
logger("Done deleting ".$count." orphaned data from notify table"); logger("Done deleting ".$count." orphaned data from notify table. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-4', $last_id);
if ($count < $limit) { if ($count < $limit) {
Config::set('system', 'finished-dbclean-4', true); Config::set('system', 'finished-dbclean-4', true);
} }
} elseif ($stage == 5) { } elseif ($stage == 5) {
logger("Deleting orphaned data from notify-threads table"); $last_id = Config::get('system', 'dbclean-last-id-5', 0);
$r = dba::p("SELECT `id` FROM `notify-threads` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) LIMIT ".intval($limit));
logger("Deleting orphaned data from notify-threads table. Last ID: ".$last_id);
$r = dba::p("SELECT `id` FROM `notify-threads`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id);
$count = dba::num_rows($r); $count = dba::num_rows($r);
if ($count > 0) { if ($count > 0) {
logger("found notify-threads orphans: ".$count); logger("found notify-threads orphans: ".$count);
while ($orphan = dba::fetch($r)) { while ($orphan = dba::fetch($r)) {
$last_id = $orphan["id"];
dba::delete('notify-threads', array('id' => $orphan["id"])); dba::delete('notify-threads', array('id' => $orphan["id"]));
} }
} else { } else {
logger("No notify-threads orphans found"); logger("No notify-threads orphans found");
} }
dba::close($r); dba::close($r);
logger("Done deleting ".$count." orphaned data from notify-threads table"); logger("Done deleting ".$count." orphaned data from notify-threads table. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-5', $last_id);
if ($count < $limit) { if ($count < $limit) {
Config::set('system', 'finished-dbclean-5', true); Config::set('system', 'finished-dbclean-5', true);
} }
} elseif ($stage == 6) { } elseif ($stage == 6) {
logger("Deleting orphaned data from sign table"); $last_id = Config::get('system', 'dbclean-last-id-6', 0);
$r = dba::p("SELECT `iid` FROM `sign` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) LIMIT ".intval($limit));
logger("Deleting orphaned data from sign table. Last ID: ".$last_id);
$r = dba::p("SELECT `iid`, `id` FROM `sign`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id);
$count = dba::num_rows($r); $count = dba::num_rows($r);
if ($count > 0) { if ($count > 0) {
logger("found sign orphans: ".$count); logger("found sign orphans: ".$count);
while ($orphan = dba::fetch($r)) { while ($orphan = dba::fetch($r)) {
$last_id = $orphan["id"];
dba::delete('sign', array('iid' => $orphan["iid"])); dba::delete('sign', array('iid' => $orphan["iid"]));
} }
} else { } else {
logger("No sign orphans found"); logger("No sign orphans found");
} }
dba::close($r); dba::close($r);
logger("Done deleting ".$count." orphaned data from sign table"); logger("Done deleting ".$count." orphaned data from sign table. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-6', $last_id);
if ($count < $limit) { if ($count < $limit) {
Config::set('system', 'finished-dbclean-6', true); Config::set('system', 'finished-dbclean-6', true);
} }
} elseif ($stage == 7) { } elseif ($stage == 7) {
logger("Deleting orphaned data from term table"); $last_id = Config::get('system', 'dbclean-last-id-7', 0);
$r = dba::p("SELECT `oid` FROM `term` WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) LIMIT ".intval($limit));
logger("Deleting orphaned data from term table. Last ID: ".$last_id);
$r = dba::p("SELECT `oid`, `tid` FROM `term`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) AND `tid` >= ?
ORDER BY `tid` LIMIT ".intval($limit), $last_id);
$count = dba::num_rows($r); $count = dba::num_rows($r);
if ($count > 0) { if ($count > 0) {
logger("found term orphans: ".$count); logger("found term orphans: ".$count);
while ($orphan = dba::fetch($r)) { while ($orphan = dba::fetch($r)) {
$last_id = $orphan["tid"];
dba::delete('term', array('oid' => $orphan["oid"])); dba::delete('term', array('oid' => $orphan["oid"]));
} }
} else { } else {
logger("No term orphans found"); logger("No term orphans found");
} }
dba::close($r); dba::close($r);
logger("Done deleting ".$count." orphaned data from term table"); logger("Done deleting ".$count." orphaned data from term table. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-7', $last_id);
if ($count < $limit) { if ($count < $limit) {
Config::set('system', 'finished-dbclean-7', true); Config::set('system', 'finished-dbclean-7', true);
} }
} elseif ($stage == 8) {
if ($days <= 0) {
return;
}
$last_id = Config::get('system', 'dbclean-last-id-8', 0);
logger("Deleting expired threads. Last ID: ".$last_id);
$r = dba::p("SELECT `thread`.`iid` FROM `thread`
INNER JOIN `contact` ON `thread`.`contact-id` = `contact`.`id` AND NOT `notify_new_posts`
WHERE `thread`.`received` < UTC_TIMESTAMP() - INTERVAL ? DAY
AND NOT `thread`.`mention` AND NOT `thread`.`starred`
AND NOT `thread`.`wall` AND NOT `thread`.`origin`
AND `thread`.`uid` != 0 AND `thread`.`iid` >= ?
AND NOT `thread`.`iid` IN (SELECT `parent` FROM `item`
WHERE (`item`.`starred` OR (`item`.`resource-id` != '')
OR (`item`.`file` != '') OR (`item`.`event-id` != '')
OR (`item`.`attach` != '') OR `item`.`wall` OR `item`.`origin`)
AND `item`.`parent` = `thread`.`iid`)
ORDER BY `thread`.`iid` LIMIT 1000", $days, $last_id);
$count = dba::num_rows($r);
if ($count > 0) {
logger("found expired threads: ".$count);
while ($thread = dba::fetch($r)) {
$last_id = $thread["iid"];
dba::delete('thread', array('iid' => $thread["iid"]));
}
} else {
logger("No expired threads found");
}
dba::close($r);
logger("Done deleting ".$count." expired threads. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-8', $last_id);
} elseif ($stage == 9) {
if ($days <= 0) {
return;
}
$last_id = Config::get('system', 'dbclean-last-id-9', 0);
$till_id = Config::get('system', 'dbclean-last-id-8', 0);
logger("Deleting old global item entries from expired threads from ID ".$last_id." to ID ".$till_id);
$r = dba::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
`received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? AND `id` <= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id, $till_id);
$count = dba::num_rows($r);
if ($count > 0) {
logger("found global item entries from expired threads: ".$count);
while ($orphan = dba::fetch($r)) {
$last_id = $orphan["id"];
dba::delete('item', array('id' => $orphan["id"]));
}
} else {
logger("No global item entries from expired threads");
}
dba::close($r);
logger("Done deleting ".$count." old global item entries from expired threads. Last ID: ".$last_id);
Config::set('system', 'dbclean-last-id-9', $last_id);
} }
// Call it again if not all entries were purged // Call it again if not all entries were purged
if (($stage != 0) AND ($count > 0)) { if (($stage != 0) AND ($count > 0)) {
proc_run(PRIORITY_MEDIUM, 'include/dbclean.php'); proc_run(PRIORITY_MEDIUM, 'include/dbclean.php');
} }
} }

View file

@ -8,7 +8,11 @@ require_once "include/text.php";
define('NEW_UPDATE_ROUTINE_VERSION', 1170); define('NEW_UPDATE_ROUTINE_VERSION', 1170);
/** const DB_UPDATE_NOT_CHECKED = 0; // Database check wasn't executed before
const DB_UPDATE_SUCCESSFUL = 1; // Database check was successful
const DB_UPDATE_FAILED = 2; // Database check failed
/*
* Converts all tables from MyISAM to InnoDB * Converts all tables from MyISAM to InnoDB
*/ */
function convert_to_innodb() { function convert_to_innodb() {
@ -480,6 +484,12 @@ function update_structure($verbose, $action, $tables=null, $definition=null) {
Config::set('system', 'maintenance_reason', ''); Config::set('system', 'maintenance_reason', '');
} }
if ($errors) {
Config::set('system', 'dbupdate', DB_UPDATE_FAILED);
} else {
Config::set('system', 'dbupdate', DB_UPDATE_SUCCESSFUL);
}
return $errors; return $errors;
} }
@ -808,7 +818,7 @@ function db_definition() {
$database["conv"] = array( $database["conv"] = array(
"fields" => array( "fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), "id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"guid" => array("type" => "varchar(64)", "not null" => "1", "default" => ""), "guid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"recips" => array("type" => "text"), "recips" => array("type" => "text"),
"uid" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")), "uid" => array("type" => "int(11)", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")),
"creator" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), "creator" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@ -1195,7 +1205,7 @@ function db_definition() {
"id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), "id" => array("type" => "int(11)", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"name" => array("type" => "varchar(128)", "not null" => "1", "default" => ""), "name" => array("type" => "varchar(128)", "not null" => "1", "default" => ""),
"locked" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"), "locked" => array("type" => "tinyint(1)", "not null" => "1", "default" => "0"),
"created" => array("type" => "datetime", "default" => NULL_DATE), "pid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0"),
), ),
"indexes" => array( "indexes" => array(
"PRIMARY" => array("id"), "PRIMARY" => array("id"),
@ -1205,7 +1215,7 @@ function db_definition() {
"fields" => array( "fields" => array(
"id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"), "id" => array("type" => "int(10) unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1"),
"uid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")), "uid" => array("type" => "int(10) unsigned", "not null" => "1", "default" => "0", "relation" => array("user" => "uid")),
"guid" => array("type" => "varchar(64)", "not null" => "1", "default" => ""), "guid" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"from-name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), "from-name" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"from-photo" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), "from-photo" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
"from-url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""), "from-url" => array("type" => "varchar(255)", "not null" => "1", "default" => ""),
@ -1732,6 +1742,9 @@ function db_definition() {
), ),
"indexes" => array( "indexes" => array(
"PRIMARY" => array("id"), "PRIMARY" => array("id"),
"pid" => array("pid"),
"parameter" => array("parameter(192)"),
"priority_created" => array("priority", "created"),
) )
); );

View file

@ -1395,7 +1395,7 @@ class Diaspora {
$message_id = self::message_exists($importer["uid"], $guid); $message_id = self::message_exists($importer["uid"], $guid);
if ($message_id) { if ($message_id) {
return $message_id; return true;
} }
$parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact); $parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact);
@ -1454,6 +1454,10 @@ class Diaspora {
$message_id = item_store($datarray); $message_id = item_store($datarray);
if ($message_id <= 0) {
return false;
}
if ($message_id) { if ($message_id) {
logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
} }
@ -1472,7 +1476,7 @@ class Diaspora {
proc_run(PRIORITY_HIGH, "include/notifier.php", "comment-import", $message_id); proc_run(PRIORITY_HIGH, "include/notifier.php", "comment-import", $message_id);
} }
return $message_id; return true;
} }
/** /**
@ -1623,7 +1627,7 @@ class Diaspora {
} }
if (!$conversation) { if (!$conversation) {
logger("unable to create conversation."); logger("unable to create conversation.");
return; return false;
} }
foreach ($messages as $mesg) foreach ($messages as $mesg)
@ -1701,7 +1705,7 @@ class Diaspora {
$message_id = self::message_exists($importer["uid"], $guid); $message_id = self::message_exists($importer["uid"], $guid);
if ($message_id) if ($message_id)
return $message_id; return true;
$parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact); $parent_item = self::parent_item($importer["uid"], $parent_guid, $author, $contact);
if (!$parent_item) if (!$parent_item)
@ -1754,8 +1758,13 @@ class Diaspora {
$message_id = item_store($datarray); $message_id = item_store($datarray);
if ($message_id) if ($message_id <= 0) {
return false;
}
if ($message_id) {
logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
}
// If we are the origin of the parent we store the original data and notify our followers // If we are the origin of the parent we store the original data and notify our followers
if ($message_id AND $parent_item["origin"]) { if ($message_id AND $parent_item["origin"]) {
@ -1771,7 +1780,7 @@ class Diaspora {
proc_run(PRIORITY_HIGH, "include/notifier.php", "comment-import", $message_id); proc_run(PRIORITY_HIGH, "include/notifier.php", "comment-import", $message_id);
} }
return $message_id; return true;
} }
/** /**
@ -2348,7 +2357,7 @@ class Diaspora {
$message_id = self::message_exists($importer["uid"], $guid); $message_id = self::message_exists($importer["uid"], $guid);
if ($message_id) { if ($message_id) {
return $message_id; return true;
} }
$original_item = self::original_item($root_guid, $root_author, $author); $original_item = self::original_item($root_guid, $root_author, $author);
@ -2399,9 +2408,10 @@ class Diaspora {
if ($message_id) { if ($message_id) {
logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
return true;
} else {
return false;
} }
return $message_id;
} }
/** /**
@ -2532,7 +2542,7 @@ class Diaspora {
$message_id = self::message_exists($importer["uid"], $guid); $message_id = self::message_exists($importer["uid"], $guid);
if ($message_id) { if ($message_id) {
return $message_id; return true;
} }
$address = array(); $address = array();
@ -2616,9 +2626,10 @@ class Diaspora {
if ($message_id) { if ($message_id) {
logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
return true;
} else {
return false;
} }
return $message_id;
} }
/* ************************************************************************************** * /* ************************************************************************************** *

View file

@ -152,7 +152,9 @@ function get_profiledata_by_nick($nickname, $uid = 0, $profile = 0) {
if ($profile) { if ($profile) {
$profile_int = intval($profile); $profile_int = intval($profile);
$r = q("SELECT `contact`.`id` AS `contact_id`, `profile`.`uid` AS `profile_uid`, `profile`.*, $r = q("SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` AS `contact_photo`,
`contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`,
`profile`.`uid` AS `profile_uid`, `profile`.*,
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.*
FROM `profile` FROM `profile`
INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self` INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
@ -163,7 +165,9 @@ function get_profiledata_by_nick($nickname, $uid = 0, $profile = 0) {
); );
} }
if (!dbm::is_result($r)) { if (!dbm::is_result($r)) {
$r = q("SELECT `contact`.`id` AS `contact_id`, `profile`.`uid` AS `profile_uid`, `profile`.*, $r = q("SELECT `contact`.`id` AS `contact_id`, `contact`.`photo` as `contact_photo`,
`contact`.`thumb` AS `contact_thumb`, `contact`.`micro` AS `contact_micro`,
`profile`.`uid` AS `profile_uid`, `profile`.*,
`contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.* `contact`.`avatar-date` AS picdate, `contact`.`addr`, `user`.*
FROM `profile` FROM `profile`
INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` AND `contact`.`self` INNER JOIN `contact` ON `contact`.`uid` = `profile`.`uid` AND `contact`.`self`
@ -365,9 +369,9 @@ function profile_sidebar($profile, $block = 0) {
'fullname' => $profile['name'], 'fullname' => $profile['name'],
'firstname' => $firstname, 'firstname' => $firstname,
'lastname' => $lastname, 'lastname' => $lastname,
'photo300' => App::get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg', 'photo300' => $profile['contact_photo'],
'photo100' => App::get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg', 'photo100' => $profile['contact_thumb'],
'photo50' => App::get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg', 'photo50' => $profile['contact_micro'],
); );
else else
$diaspora = false; $diaspora = false;
@ -410,9 +414,9 @@ function profile_sidebar($profile, $block = 0) {
else else
$p["address"] = bbcode($p["location"]); $p["address"] = bbcode($p["location"]);
if (isset($p["photo"])) if (isset($p["photo"])) {
$p["photo"] = proxy_url($p["photo"], false, PROXY_SIZE_SMALL); $p["photo"] = proxy_url($p["photo"], false, PROXY_SIZE_SMALL);
}
if ($a->theme['template_engine'] === 'internal') if ($a->theme['template_engine'] === 'internal')
$location = template_escape($location); $location = template_escape($location);

View file

@ -2076,7 +2076,7 @@ function item_expire($uid, $days, $network = "", $force = false) {
drop_item($item['id'], false); drop_item($item['id'], false);
} }
proc_run(PRIORITY_HIGH, "include/notifier.php", "expire", $uid); proc_run(PRIORITY_LOW, "include/notifier.php", "expire", $uid);
} }
@ -2099,7 +2099,7 @@ function drop_items($items) {
// multiple threads may have been deleted, send an expire notification // multiple threads may have been deleted, send an expire notification
if ($uid) { if ($uid) {
proc_run(PRIORITY_HIGH, "include/notifier.php", "expire", $uid); proc_run(PRIORITY_LOW, "include/notifier.php", "expire", $uid);
} }
} }
@ -2290,11 +2290,12 @@ function drop_item($id, $interactive = true) {
} }
} }
// send the notification upstream/downstream
// The priority depends on how the deletion is done.
$drop_id = intval($item['id']); $drop_id = intval($item['id']);
$priority = ($interactive ? PRIORITY_HIGH : PRIORITY_LOW);
// send the notification upstream/downstream as the case may be proc_run($priority, "include/notifier.php", "drop", $drop_id);
proc_run(PRIORITY_HIGH, "include/notifier.php", "drop", $drop_id);
if (! $interactive) { if (! $interactive) {
return $owner; return $owner;

View file

@ -1,80 +0,0 @@
<?php
// Provide some ability to lock a PHP function so that multiple processes
// can't run the function concurrently
if (! function_exists('lock_function')) {
function lock_function($fn_name, $block = true, $wait_sec = 2, $timeout = 30) {
if ( $wait_sec == 0 )
$wait_sec = 2; // don't let the user pick a value that's likely to crash the system
$got_lock = false;
$start = time();
do {
q("LOCK TABLE `locks` WRITE");
$r = q("SELECT `locked`, `created` FROM `locks` WHERE `name` = '%s' LIMIT 1",
dbesc($fn_name)
);
if ((dbm::is_result($r)) AND (!$r[0]['locked'] OR (strtotime($r[0]['created']) < time() - 3600))) {
q("UPDATE `locks` SET `locked` = 1, `created` = '%s' WHERE `name` = '%s'",
dbesc(datetime_convert()),
dbesc($fn_name)
);
$got_lock = true;
}
elseif (! dbm::is_result($r)) {
/// @TODO the Boolean value for count($r) should be equivalent to the Boolean value of $r
q("INSERT INTO `locks` (`name`, `created`, `locked`) VALUES ('%s', '%s', 1)",
dbesc($fn_name),
dbesc(datetime_convert())
);
$got_lock = true;
}
q("UNLOCK TABLES");
if (($block) && (! $got_lock))
sleep($wait_sec);
} while (($block) && (! $got_lock) && ((time() - $start) < $timeout));
logger('lock_function: function ' . $fn_name . ' with blocking = ' . $block . ' got_lock = ' . $got_lock . ' time = ' . (time() - $start), LOGGER_DEBUG);
return $got_lock;
}}
if (! function_exists('block_on_function_lock')) {
function block_on_function_lock($fn_name, $wait_sec = 2, $timeout = 30) {
if ( $wait_sec == 0 )
$wait_sec = 2; // don't let the user pick a value that's likely to crash the system
$start = time();
do {
$r = q("SELECT locked FROM locks WHERE name = '%s' LIMIT 1",
dbesc($fn_name)
);
if (dbm::is_result($r) && $r[0]['locked']) {
sleep($wait_sec);
}
} while (dbm::is_result($r) && $r[0]['locked'] && ((time() - $start) < $timeout));
return;
}}
if (! function_exists('unlock_function')) {
function unlock_function($fn_name) {
$r = q("UPDATE `locks` SET `locked` = 0, `created` = '%s' WHERE `name` = '%s'",
dbesc(NULL_DATE),
dbesc($fn_name)
);
logger('unlock_function: released lock for function ' . $fn_name, LOGGER_DEBUG);
return;
}}

View file

@ -55,6 +55,17 @@ function notifier_run(&$argv, &$argc){
return; return;
} }
// Inherit the priority
$queue = dba::select('workerqueue', array('priority'), array('pid' => getmypid()), array('limit' => 1));
if (dbm::is_result($queue)) {
$priority = (int)$queue['priority'];
logger('inherited priority: '.$priority);
} else {
// Normally this shouldn't happen.
$priority = PRIORITY_HIGH;
logger('no inherited priority! Something is wrong.');
}
logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG); logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
$cmd = $argv[1]; $cmd = $argv[1];
@ -348,7 +359,7 @@ function notifier_run(&$argv, &$argc){
// a delivery fork. private groups (forum_mode == 2) do not uplink // a delivery fork. private groups (forum_mode == 2) do not uplink
if ((intval($parent['forum_mode']) == 1) && (! $top_level) && ($cmd !== 'uplink')) { if ((intval($parent['forum_mode']) == 1) && (! $top_level) && ($cmd !== 'uplink')) {
proc_run(PRIORITY_HIGH,'include/notifier.php','uplink',$item_id); proc_run($priority, 'include/notifier.php', 'uplink', $item_id);
} }
$conversants = array(); $conversants = array();
@ -487,7 +498,7 @@ function notifier_run(&$argv, &$argc){
} }
logger("Deliver ".$target_item["guid"]." to ".$contact['url']." via network ".$contact['network'], LOGGER_DEBUG); logger("Deliver ".$target_item["guid"]." to ".$contact['url']." via network ".$contact['network'], LOGGER_DEBUG);
proc_run(PRIORITY_HIGH,'include/delivery.php', $cmd, $item_id, $contact['id']); proc_run(array('priority' => $priority, 'dont_fork' => true), 'include/delivery.php', $cmd, $item_id, $contact['id']);
} }
} }
@ -552,7 +563,7 @@ function notifier_run(&$argv, &$argc){
if ((! $mail) && (! $fsuggest) && (! $followup)) { if ((! $mail) && (! $fsuggest) && (! $followup)) {
logger('notifier: delivery agent: '.$rr['name'].' '.$rr['id'].' '.$rr['network'].' '.$target_item["guid"]); logger('notifier: delivery agent: '.$rr['name'].' '.$rr['id'].' '.$rr['network'].' '.$target_item["guid"]);
proc_run(PRIORITY_HIGH,'include/delivery.php',$cmd,$item_id,$rr['id']); proc_run(array('priority' => $priority, 'dont_fork' => true), 'include/delivery.php', $cmd, $item_id, $rr['id']);
} }
} }
} }
@ -592,7 +603,7 @@ function notifier_run(&$argv, &$argc){
} }
// Handling the pubsubhubbub requests // Handling the pubsubhubbub requests
proc_run(PRIORITY_HIGH,'include/pubsubpublish.php'); proc_run(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), 'include/pubsubpublish.php');
} }
logger('notifier: calling hooks', LOGGER_DEBUG); logger('notifier: calling hooks', LOGGER_DEBUG);

View file

@ -647,6 +647,9 @@ class ostatus {
$item_id = self::completion($conversation, $importer["uid"], $item, $self); $item_id = self::completion($conversation, $importer["uid"], $item, $self);
if (!$item_id) { if (!$item_id) {
// Store the conversation data. This is normally done in "item_store"
// but since something went wrong, we want to be sure to save the data.
store_conversation($item);
logger("Error storing item", LOGGER_DEBUG); logger("Error storing item", LOGGER_DEBUG);
continue; continue;
} }
@ -840,6 +843,30 @@ class ostatus {
return $base_url."/conversation/".$conversation_id; return $base_url."/conversation/".$conversation_id;
} }
/**
* @brief Fetches a shared object from a given conversation object
*
* Sometimes GNU Social seems to fail when returning shared objects.
* Then they don't contains all needed data.
* We then try to find this object in the conversation
*
* @param string $id Message id
* @param object $conversation Conversation object
*
* @return object The shared object
*/
private function shared_object($id, $conversation) {
if (!is_array($conversation->items)) {
return false;
}
foreach ($conversation->items AS $single_conv) {
if ($single_conv->id == $id) {
return $single_conv;
}
}
return false;
}
/** /**
* @brief Fetches actor details of a given actor and user id * @brief Fetches actor details of a given actor and user id
* *
@ -910,8 +937,6 @@ class ostatus {
($item["verb"] == ACTIVITY_LIKE) OR ($conversation_url == "")) { ($item["verb"] == ACTIVITY_LIKE) OR ($conversation_url == "")) {
$item_stored = item_store($item, $all_threads); $item_stored = item_store($item, $all_threads);
return $item_stored; return $item_stored;
} elseif (count($item) > 0) {
$item = store_conversation($item);
} }
// Get the parent // Get the parent
@ -921,14 +946,6 @@ class ostatus {
STRAIGHT_JOIN `item` ON `item`.`parent` = `thritem`.`parent` STRAIGHT_JOIN `item` ON `item`.`parent` = `thritem`.`parent`
WHERE `term`.`uid` = %d AND `term`.`otype` = %d AND `term`.`type` = %d AND `term`.`url` = '%s'", WHERE `term`.`uid` = %d AND `term`.`otype` = %d AND `term`.`type` = %d AND `term`.`url` = '%s'",
intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url)); intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
/* 2016-10-23: The old query will be kept until we are sure that the query above is a good and fast replacement
$parents = q("SELECT `id`, `parent`, `uri`, `contact-id`, `type`, `verb`, `visible` FROM `item` WHERE `id` IN
(SELECT `parent` FROM `item` WHERE `id` IN
(SELECT `oid` FROM `term` WHERE `uid` = %d AND `otype` = %d AND `type` = %d AND `url` = '%s'))",
intval($uid), intval(TERM_OBJ_POST), intval(TERM_CONVERSATION), dbesc($conversation_url));
*/
if ($parents) if ($parents)
$parent = $parents[0]; $parent = $parents[0];
elseif (count($item) > 0) { elseif (count($item) > 0) {
@ -1205,25 +1222,34 @@ class ostatus {
if (is_array($single_conv->object)) if (is_array($single_conv->object))
$single_conv->object = $single_conv->object[0]; $single_conv->object = $single_conv->object[0];
// Sometimes GNU Social doesn't returns a complete object
if (!isset($single_conv->object->actor->url)) {
$object = self::shared_object($single_conv->object->id, $conversation);
if (is_object($object)) {
$single_conv->object = $object;
}
}
if (isset($single_conv->object->actor->url)) {
logger("Found reshared item ".$single_conv->object->id); logger("Found reshared item ".$single_conv->object->id);
// $single_conv->object->context->conversation; // $single_conv->object->context->conversation;
if (isset($single_conv->object->object->id)) if (isset($single_conv->object->object->id)) {
$arr["uri"] = $single_conv->object->object->id; $arr["uri"] = $single_conv->object->object->id;
else } else {
$arr["uri"] = $single_conv->object->id; $arr["uri"] = $single_conv->object->id;
}
if (isset($single_conv->object->object->url)) if (isset($single_conv->object->object->url)) {
$plink = self::convert_href($single_conv->object->object->url); $plink = self::convert_href($single_conv->object->object->url);
else } else {
$plink = self::convert_href($single_conv->object->url); $plink = self::convert_href($single_conv->object->url);
}
if (isset($single_conv->object->object->content)) if (isset($single_conv->object->object->content)) {
$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->object->content)); $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->object->content));
else } else {
$arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content)); $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->object->content));
}
$arr["plink"] = $plink; $arr["plink"] = $plink;
$arr["created"] = $single_conv->object->published; $arr["created"] = $single_conv->object->published;
@ -1242,6 +1268,7 @@ class ostatus {
$arr["location"] = $single_conv->object->location->displayName; $arr["location"] = $single_conv->object->location->displayName;
$arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon); $arr["coord"] = trim($single_conv->object->location->lat." ".$single_conv->object->location->lon);
} }
}
if ($arr["location"] == "") if ($arr["location"] == "")
unset($arr["location"]); unset($arr["location"]);
@ -1251,26 +1278,19 @@ class ostatus {
// Copy fields from given item array // Copy fields from given item array
if (isset($item["uri"]) AND (($item["uri"] == $arr["uri"]) OR ($item["uri"] == $single_conv->id))) { if (isset($item["uri"]) AND (($item["uri"] == $arr["uri"]) OR ($item["uri"] == $single_conv->id))) {
$copy_fields = array("owner-name", "owner-link", "owner-avatar", "author-name", "author-link", "author-avatar", logger('Use stored item array for item with URI '.$item["uri"], LOGGER_DEBUG);
"gravity", "body", "object-type", "object", "verb", "created", "edited", "coord", "tag", $newitem = item_store($item);
"title", "attach", "app", "type", "location", "contact-id", "uri"); $item = array();
foreach ($copy_fields AS $field) $item_stored = $newitem;
if (isset($item[$field])) } else {
$arr[$field] = $item[$field]; $newitem = item_store($arr);
} }
$newitem = item_store($arr);
if (!$newitem) { if (!$newitem) {
logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG); logger("Item wasn't stored ".print_r($arr, true), LOGGER_DEBUG);
continue; continue;
} }
if (isset($item["uri"]) AND ($item["uri"] == $arr["uri"])) {
$item = array();
$item_stored = $newitem;
}
logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG); logger('Stored new item '.$plink.' for parent '.$arr["parent-uri"].' under id '.$newitem, LOGGER_DEBUG);
// Add the conversation entry (but don't fetch the whole conversation) // Add the conversation entry (but don't fetch the whole conversation)

View file

@ -2,13 +2,14 @@
use Friendica\App; use Friendica\App;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Util\Lock;
if (!file_exists("boot.php") AND (sizeof($_SERVER["argv"]) != 0)) { if (!file_exists("boot.php") AND (sizeof($_SERVER["argv"]) != 0)) {
$directory = dirname($_SERVER["argv"][0]); $directory = dirname($_SERVER["argv"][0]);
if (substr($directory, 0, 1) != "/") if (substr($directory, 0, 1) != "/") {
$directory = $_SERVER["PWD"]."/".$directory; $directory = $_SERVER["PWD"]."/".$directory;
}
$directory = realpath($directory."/.."); $directory = realpath($directory."/..");
chdir($directory); chdir($directory);
@ -19,16 +20,12 @@ require_once("boot.php");
function poller_run($argv, $argc){ function poller_run($argv, $argc){
global $a, $db; global $a, $db;
if (is_null($a)) {
$a = new App(dirname(__DIR__)); $a = new App(dirname(__DIR__));
}
if (is_null($db)) {
@include(".htconfig.php"); @include(".htconfig.php");
require_once("include/dba.php"); require_once("include/dba.php");
$db = new dba($db_host, $db_user, $db_pass, $db_data); $db = new dba($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
};
Config::load(); Config::load();
@ -41,56 +38,86 @@ function poller_run($argv, $argc){
load_hooks(); load_hooks();
// At first check the maximum load. We shouldn't continue with a high load
if ($a->maxload_reached()) {
logger('Pre check: maximum load reached, quitting.', LOGGER_DEBUG);
return;
}
// We now start the process. This is done after the load check since this could increase the load.
$a->start_process(); $a->start_process();
// At first we check the number of workers and quit if there are too much of them
// This is done at the top to avoid that too much code is executed without a need to do so,
// since the poller mostly quits here.
if (poller_too_much_workers()) {
poller_kill_stale_workers();
logger('Pre check: Active worker limit reached, quitting.', LOGGER_DEBUG);
return;
}
// Do we have too few memory?
if ($a->min_memory_reached()) { if ($a->min_memory_reached()) {
logger('Pre check: Memory limit reached, quitting.', LOGGER_DEBUG);
return; return;
} }
// Possibly there are too much database connections
if (poller_max_connections_reached()) { if (poller_max_connections_reached()) {
logger('Pre check: maximum connections reached, quitting.', LOGGER_DEBUG);
return; return;
} }
if ($a->maxload_reached()) { // Possibly there are too much database processes that block the system
if ($a->max_processes_reached()) {
logger('Pre check: maximum processes reached, quitting.', LOGGER_DEBUG);
return; return;
} }
// Now we start additional cron processes if we should do so
if (($argc <= 1) OR ($argv[1] != "no_cron")) { if (($argc <= 1) OR ($argv[1] != "no_cron")) {
poller_run_cron(); poller_run_cron();
} }
if ($a->max_processes_reached()) {
return;
}
// Checking the number of workers
if (poller_too_much_workers()) {
poller_kill_stale_workers();
return;
}
$starttime = time(); $starttime = time();
// We fetch the next queue entry that is about to be executed
while ($r = poller_worker_process()) { while ($r = poller_worker_process()) {
// If we got that queue entry we claim it for us
if (!poller_claim_process($r[0])) {
continue;
}
// To avoid the quitting of multiple pollers only one poller at a time will execute the check
if (Lock::set('poller_worker', 0)) {
// Count active workers and compare them with a maximum value that depends on the load
if (poller_too_much_workers()) {
logger('Active worker limit reached, quitting.', LOGGER_DEBUG);
return;
}
// Check free memory // Check free memory
if ($a->min_memory_reached()) { if ($a->min_memory_reached()) {
logger('Memory limit reached, quitting.', LOGGER_DEBUG);
return; return;
} }
Lock::remove('poller_worker');
// Count active workers and compare them with a maximum value that depends on the load
if (poller_too_much_workers()) {
return;
} }
// finally the work will be done
if (!poller_execute($r[0])) { if (!poller_execute($r[0])) {
logger('Process execution failed, quitting.', LOGGER_DEBUG);
return; return;
} }
// Quit the poller once every hour // Quit the poller once every hour
if (time() > ($starttime + 3600)) if (time() > ($starttime + 3600)) {
logger('Process lifetime reached, quitting.', LOGGER_DEBUG);
return; return;
} }
}
logger("Couldn't select a workerqueue entry, quitting.", LOGGER_DEBUG);
} }
/** /**
@ -108,43 +135,22 @@ function poller_execute($queue) {
// Quit when in maintenance // Quit when in maintenance
if (Config::get('system', 'maintenance', true)) { if (Config::get('system', 'maintenance', true)) {
logger("Maintenance mode - quit process ".$mypid, LOGGER_DEBUG);
return false; return false;
} }
// Constantly check the number of parallel database processes // Constantly check the number of parallel database processes
if ($a->max_processes_reached()) { if ($a->max_processes_reached()) {
logger("Max processes reached for process ".$mypid, LOGGER_DEBUG);
return false; return false;
} }
// Constantly check the number of available database connections to let the frontend be accessible at any time // Constantly check the number of available database connections to let the frontend be accessible at any time
if (poller_max_connections_reached()) { if (poller_max_connections_reached()) {
logger("Max connection reached for process ".$mypid, LOGGER_DEBUG);
return false; return false;
} }
if (!dba::update('workerqueue', array('executed' => datetime_convert(), 'pid' => $mypid),
array('id' => $queue["id"], 'pid' => 0))) {
logger("Couldn't update queue entry ".$queue["id"]." - skip this execution", LOGGER_DEBUG);
dba::commit();
return true;
}
// Assure that there are no tasks executed twice
$id = q("SELECT `pid`, `executed` FROM `workerqueue` WHERE `id` = %d", intval($queue["id"]));
if (!$id) {
logger("Queue item ".$queue["id"]." vanished - skip this execution", LOGGER_DEBUG);
dba::commit();
return true;
} elseif ((strtotime($id[0]["executed"]) <= 0) OR ($id[0]["pid"] == 0)) {
logger("Entry for queue item ".$queue["id"]." wasn't stored - skip this execution", LOGGER_DEBUG);
dba::commit();
return true;
} elseif ($id[0]["pid"] != $mypid) {
logger("Queue item ".$queue["id"]." is to be executed by process ".$id[0]["pid"]." and not by me (".$mypid.") - skip this execution", LOGGER_DEBUG);
dba::commit();
return true;
}
dba::commit();
$argv = json_decode($queue["parameter"]); $argv = json_decode($queue["parameter"]);
// Check for existance and validity of the include file // Check for existance and validity of the include file
@ -161,9 +167,7 @@ function poller_execute($queue) {
$funcname = str_replace(".php", "", basename($argv[0]))."_run"; $funcname = str_replace(".php", "", basename($argv[0]))."_run";
if (function_exists($funcname)) { if (function_exists($funcname)) {
poller_exec_function($queue, $funcname, $argv); poller_exec_function($queue, $funcname, $argv);
dba::delete('workerqueue', array('id' => $queue["id"])); dba::delete('workerqueue', array('id' => $queue["id"]));
} else { } else {
logger("Function ".$funcname." does not exist"); logger("Function ".$funcname." does not exist");
@ -238,26 +242,29 @@ function poller_exec_function($queue, $funcname, $argv) {
$o = "\nDatabase Read:\n"; $o = "\nDatabase Read:\n";
foreach ($a->callstack["database"] AS $func => $time) { foreach ($a->callstack["database"] AS $func => $time) {
$time = round($time, 3); $time = round($time, 3);
if ($time > 0) if ($time > 0) {
$o .= $func.": ".$time."\n"; $o .= $func.": ".$time."\n";
} }
} }
}
if (isset($a->callstack["database_write"])) { if (isset($a->callstack["database_write"])) {
$o .= "\nDatabase Write:\n"; $o .= "\nDatabase Write:\n";
foreach ($a->callstack["database_write"] AS $func => $time) { foreach ($a->callstack["database_write"] AS $func => $time) {
$time = round($time, 3); $time = round($time, 3);
if ($time > 0) if ($time > 0) {
$o .= $func.": ".$time."\n"; $o .= $func.": ".$time."\n";
} }
} }
}
if (isset($a->callstack["network"])) { if (isset($a->callstack["network"])) {
$o .= "\nNetwork:\n"; $o .= "\nNetwork:\n";
foreach ($a->callstack["network"] AS $func => $time) { foreach ($a->callstack["network"] AS $func => $time) {
$time = round($time, 3); $time = round($time, 3);
if ($time > 0) if ($time > 0) {
$o .= $func.": ".$time."\n"; $o .= $func.": ".$time."\n";
} }
} }
}
} else { } else {
$o = ''; $o = '';
} }
@ -296,27 +303,30 @@ function poller_max_connections_reached() {
if ($max == 0) { if ($max == 0) {
// the maximum number of possible user connections can be a system variable // the maximum number of possible user connections can be a system variable
$r = q("SHOW VARIABLES WHERE `variable_name` = 'max_user_connections'"); $r = q("SHOW VARIABLES WHERE `variable_name` = 'max_user_connections'");
if ($r) if (dbm::is_result($r)) {
$max = $r[0]["Value"]; $max = $r[0]["Value"];
}
// Or it can be granted. This overrides the system variable // Or it can be granted. This overrides the system variable
$r = q("SHOW GRANTS"); $r = q("SHOW GRANTS");
if ($r) if (dbm::is_result($r)) {
foreach ($r AS $grants) { foreach ($r AS $grants) {
$grant = array_pop($grants); $grant = array_pop($grants);
if (stristr($grant, "GRANT USAGE ON")) if (stristr($grant, "GRANT USAGE ON")) {
if (preg_match("/WITH MAX_USER_CONNECTIONS (\d*)/", $grant, $match)) if (preg_match("/WITH MAX_USER_CONNECTIONS (\d*)/", $grant, $match)) {
$max = $match[1]; $max = $match[1];
} }
} }
}
}
}
// If $max is set we will use the processlist to determine the current number of connections // If $max is set we will use the processlist to determine the current number of connections
// The processlist only shows entries of the current user // The processlist only shows entries of the current user
if ($max != 0) { if ($max != 0) {
$r = q("SHOW PROCESSLIST"); $r = q("SHOW PROCESSLIST");
if (!dbm::is_result($r)) if (!dbm::is_result($r)) {
return false; return false;
}
$used = count($r); $used = count($r);
logger("Connection usage (user values): ".$used."/".$max, LOGGER_DEBUG); logger("Connection usage (user values): ".$used."/".$max, LOGGER_DEBUG);
@ -332,28 +342,28 @@ function poller_max_connections_reached() {
// We will now check for the system values. // We will now check for the system values.
// This limit could be reached although the user limits are fine. // This limit could be reached although the user limits are fine.
$r = q("SHOW VARIABLES WHERE `variable_name` = 'max_connections'"); $r = q("SHOW VARIABLES WHERE `variable_name` = 'max_connections'");
if (!$r) if (!dbm::is_result($r)) {
return false; return false;
}
$max = intval($r[0]["Value"]); $max = intval($r[0]["Value"]);
if ($max == 0) if ($max == 0) {
return false; return false;
}
$r = q("SHOW STATUS WHERE `variable_name` = 'Threads_connected'"); $r = q("SHOW STATUS WHERE `variable_name` = 'Threads_connected'");
if (!$r) if (!dbm::is_result($r)) {
return false; return false;
}
$used = intval($r[0]["Value"]); $used = intval($r[0]["Value"]);
if ($used == 0) if ($used == 0) {
return false; return false;
}
logger("Connection usage (system values): ".$used."/".$max, LOGGER_DEBUG); logger("Connection usage (system values): ".$used."/".$max, LOGGER_DEBUG);
$level = $used / $max * 100; $level = $used / $max * 100;
if ($level < $maxlevel) if ($level < $maxlevel) {
return false; return false;
}
logger("Maximum level (".$level."%) of system connections reached: ".$used."/".$max); logger("Maximum level (".$level."%) of system connections reached: ".$used."/".$max);
return true; return true;
} }
@ -432,6 +442,28 @@ function poller_too_much_workers() {
$slope = $maxworkers / pow($maxsysload, $exponent); $slope = $maxworkers / pow($maxsysload, $exponent);
$queues = ceil($slope * pow(max(0, $maxsysload - $load), $exponent)); $queues = ceil($slope * pow(max(0, $maxsysload - $load), $exponent));
// Create a list of queue entries grouped by their priority
$listitem = array();
// Adding all processes with no workerqueue entry
$processes = dba::p("SELECT COUNT(*) AS `running` FROM `process` WHERE NOT EXISTS (SELECT id FROM `workerqueue` WHERE `workerqueue`.`pid` = `process`.`pid`)");
if ($process = dba::fetch($processes)) {
$listitem[0] = "0:".$process["running"];
}
dba::close($processes);
// Now adding all processes with workerqueue entries
$entries = dba::p("SELECT COUNT(*) AS `entries`, `priority` FROM `workerqueue` GROUP BY `priority`");
while ($entry = dba::fetch($entries)) {
$processes = dba::p("SELECT COUNT(*) AS `running` FROM `process` INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid` WHERE `priority` = ?", $entry["priority"]);
if ($process = dba::fetch($processes)) {
$listitem[$entry["priority"]] = $entry["priority"].":".$process["running"]."/".$entry["entries"];
}
dba::close($processes);
}
dba::close($entries);
$processlist = ' ('.implode(', ', $listitem).')';
$s = q("SELECT COUNT(*) AS `total` FROM `workerqueue` WHERE `executed` <= '%s'", dbesc(NULL_DATE)); $s = q("SELECT COUNT(*) AS `total` FROM `workerqueue` WHERE `executed` <= '%s'", dbesc(NULL_DATE));
$entries = $s[0]["total"]; $entries = $s[0]["total"];
@ -449,28 +481,7 @@ function poller_too_much_workers() {
} }
} }
// Create a list of queue entries grouped by their priority logger("Load: ".$load."/".$maxsysload." - processes: ".$active."/".$entries.$processlist." - maximum: ".$queues."/".$maxqueues, LOGGER_DEBUG);
$running = array(PRIORITY_CRITICAL => 0,
PRIORITY_HIGH => 0,
PRIORITY_MEDIUM => 0,
PRIORITY_LOW => 0,
PRIORITY_NEGLIGIBLE => 0);
$r = q("SELECT COUNT(*) AS `running`, `priority` FROM `process` INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid` GROUP BY `priority`");
if (dbm::is_result($r))
foreach ($r AS $process)
$running[$process["priority"]] = $process["running"];
$processlist = "";
$r = q("SELECT COUNT(*) AS `entries`, `priority` FROM `workerqueue` GROUP BY `priority`");
if (dbm::is_result($r))
foreach ($r as $entry) {
if ($processlist != "")
$processlist .= ", ";
$processlist .= $entry["priority"].":".$running[$entry["priority"]]."/".$entry["entries"];
}
logger("Load: ".$load."/".$maxsysload." - processes: ".$active."/".$entries." (".$processlist.") - maximum: ".$queues."/".$maxqueues, LOGGER_DEBUG);
// Are there fewer workers running as possible? Then fork a new one. // Are there fewer workers running as possible? Then fork a new one.
if (!Config::get("system", "worker_dont_fork") AND ($queues > ($active + 1)) AND ($entries > 1)) { if (!Config::get("system", "worker_dont_fork") AND ($queues > ($active + 1)) AND ($entries > 1)) {
@ -481,7 +492,7 @@ function poller_too_much_workers() {
} }
} }
return($active >= $queues); return $active >= $queues;
} }
/** /**
@ -492,7 +503,7 @@ function poller_too_much_workers() {
function poller_active_workers() { function poller_active_workers() {
$workers = q("SELECT COUNT(*) AS `processes` FROM `process` WHERE `command` = 'poller.php'"); $workers = q("SELECT COUNT(*) AS `processes` FROM `process` WHERE `command` = 'poller.php'");
return($workers[0]["processes"]); return $workers[0]["processes"];
} }
/** /**
@ -513,36 +524,37 @@ function poller_passing_slow(&$highest_priority) {
INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid`"); INNER JOIN `workerqueue` ON `workerqueue`.`pid` = `process`.`pid`");
// No active processes at all? Fine // No active processes at all? Fine
if (!dbm::is_result($r)) if (!dbm::is_result($r)) {
return(false); return false;
}
$priorities = array(); $priorities = array();
foreach ($r AS $line) foreach ($r AS $line) {
$priorities[] = $line["priority"]; $priorities[] = $line["priority"];
}
// Should not happen // Should not happen
if (count($priorities) == 0) if (count($priorities) == 0) {
return(false); return false;
}
$highest_priority = min($priorities); $highest_priority = min($priorities);
// The highest process is already the slowest one? // The highest process is already the slowest one?
// Then we quit // Then we quit
if ($highest_priority == PRIORITY_NEGLIGIBLE) if ($highest_priority == PRIORITY_NEGLIGIBLE) {
return(false); return false;
}
$high = 0; $high = 0;
foreach ($priorities AS $priority) foreach ($priorities AS $priority) {
if ($priority == $highest_priority) if ($priority == $highest_priority) {
++$high; ++$high;
}
}
logger("Highest priority: ".$highest_priority." Total processes: ".count($priorities)." Count high priority processes: ".$high, LOGGER_DEBUG); logger("Highest priority: ".$highest_priority." Total processes: ".count($priorities)." Count high priority processes: ".$high, LOGGER_DEBUG);
$passing_slow = (($high/count($priorities)) > (2/3)); $passing_slow = (($high/count($priorities)) > (2/3));
if ($passing_slow) if ($passing_slow) {
logger("Passing slower processes than priority ".$highest_priority, LOGGER_DEBUG); logger("Passing slower processes than priority ".$highest_priority, LOGGER_DEBUG);
}
return($passing_slow); return $passing_slow;
} }
/** /**
@ -552,12 +564,12 @@ function poller_passing_slow(&$highest_priority) {
*/ */
function poller_worker_process() { function poller_worker_process() {
dba::transaction();
// Check if we should pass some low priority process // Check if we should pass some low priority process
$highest_priority = 0; $highest_priority = 0;
if (poller_passing_slow($highest_priority)) { if (poller_passing_slow($highest_priority)) {
dba::lock('workerqueue');
// Are there waiting processes with a higher priority than the currently highest? // Are there waiting processes with a higher priority than the currently highest?
$r = q("SELECT * FROM `workerqueue` $r = q("SELECT * FROM `workerqueue`
WHERE `executed` <= '%s' AND `priority` < %d WHERE `executed` <= '%s' AND `priority` < %d
@ -573,15 +585,72 @@ function poller_worker_process() {
ORDER BY `priority`, `created` LIMIT 1", ORDER BY `priority`, `created` LIMIT 1",
dbesc(NULL_DATE), dbesc(NULL_DATE),
intval($highest_priority)); intval($highest_priority));
if (dbm::is_result($r)) {
return $r;
}
} else {
dba::lock('workerqueue');
} }
// If there is no result (or we shouldn't pass lower processes) we check without priority limit // If there is no result (or we shouldn't pass lower processes) we check without priority limit
if (($highest_priority == 0) OR !dbm::is_result($r)) { if (!dbm::is_result($r)) {
$r = q("SELECT * FROM `workerqueue` WHERE `executed` <= '%s' ORDER BY `priority`, `created` LIMIT 1", dbesc(NULL_DATE)); $r = q("SELECT * FROM `workerqueue` WHERE `executed` <= '%s' ORDER BY `priority`, `created` LIMIT 1", dbesc(NULL_DATE));
} }
// We only unlock the tables here, when we got no data
if (!dbm::is_result($r)) {
dba::unlock();
}
return $r; return $r;
} }
/**
* @brief Assigns a workerqueue entry to the current process
*
* When we are sure that the table locks are working correctly, we can remove the checks from here
*
* @param array $queue Workerqueue entry
*
* @return boolean "true" if the claiming was successful
*/
function poller_claim_process($queue) {
$mypid = getmypid();
$success = dba::update('workerqueue', array('executed' => datetime_convert(), 'pid' => $mypid),
array('id' => $queue["id"], 'pid' => 0));
dba::unlock();
if (!$success) {
logger("Couldn't update queue entry ".$queue["id"]." - skip this execution", LOGGER_DEBUG);
return false;
}
// Assure that there are no tasks executed twice
$id = q("SELECT `pid`, `executed` FROM `workerqueue` WHERE `id` = %d", intval($queue["id"]));
if (!$id) {
logger("Queue item ".$queue["id"]." vanished - skip this execution", LOGGER_DEBUG);
return false;
} elseif ((strtotime($id[0]["executed"]) <= 0) OR ($id[0]["pid"] == 0)) {
logger("Entry for queue item ".$queue["id"]." wasn't stored - skip this execution", LOGGER_DEBUG);
return false;
} elseif ($id[0]["pid"] != $mypid) {
logger("Queue item ".$queue["id"]." is to be executed by process ".$id[0]["pid"]." and not by me (".$mypid.") - skip this execution", LOGGER_DEBUG);
return false;
}
return true;
}
/**
* @brief Removes a workerqueue entry from the current process
*/
function poller_unclaim_process() {
$mypid = getmypid();
dba::update('workerqueue', array('executed' => NULL_DATE, 'pid' => 0), array('pid' => $mypid));
}
/** /**
* @brief Call the front end worker * @brief Call the front end worker
*/ */
@ -678,7 +747,11 @@ function poller_run_cron() {
if (array_search(__file__,get_included_files())===0){ if (array_search(__file__,get_included_files())===0){
poller_run($_SERVER["argv"],$_SERVER["argc"]); poller_run($_SERVER["argv"],$_SERVER["argc"]);
poller_unclaim_process();
get_app()->end_process(); get_app()->end_process();
Lock::remove('poller_worker');
killme(); killme();
} }

View file

@ -1,6 +1,12 @@
<?php <?php
require_once('include/diaspora.php'); require_once('include/diaspora.php');
function profile_change() { function profile_update_run(&$argv, &$argc) {
Diaspora::send_profile(local_user()); if ($argc != 2) {
return;
}
$uid = intval($argv[1]);
Diaspora::send_profile($uid);
} }

View file

@ -17,7 +17,7 @@ function pubsubpublish_run(&$argv, &$argc){
foreach ($r as $rr) { foreach ($r as $rr) {
logger("Publish feed to ".$rr["callback_url"], LOGGER_DEBUG); logger("Publish feed to ".$rr["callback_url"], LOGGER_DEBUG);
proc_run(PRIORITY_HIGH, 'include/pubsubpublish.php', $rr["id"]); proc_run(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), 'include/pubsubpublish.php', $rr["id"]);
} }
} }

View file

@ -27,7 +27,7 @@ function queue_run(&$argv, &$argc){
logger('queue: start'); logger('queue: start');
// Handling the pubsubhubbub requests // Handling the pubsubhubbub requests
proc_run(PRIORITY_HIGH,'include/pubsubpublish.php'); proc_run(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), 'include/pubsubpublish.php');
$r = q("SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue` $r = q("SELECT `queue`.*, `contact`.`name`, `contact`.`uid` FROM `queue`
INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id` INNER JOIN `contact` ON `queue`.`cid` = `contact`.`id`
@ -51,7 +51,7 @@ function queue_run(&$argv, &$argc){
if (dbm::is_result($r)) { if (dbm::is_result($r)) {
foreach ($r as $q_item) { foreach ($r as $q_item) {
logger('Call queue for id '.$q_item['id']); logger('Call queue for id '.$q_item['id']);
proc_run(PRIORITY_LOW, "include/queue.php", $q_item['id']); proc_run(array('priority' => PRIORITY_LOW, 'dont_fork' => true), "include/queue.php", $q_item['id']);
} }
} }
return; return;

View file

@ -1995,10 +1995,11 @@ function get_gcontact_id($contact) {
if (in_array($contact["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) if (in_array($contact["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS)))
$contact["url"] = clean_contact_url($contact["url"]); $contact["url"] = clean_contact_url($contact["url"]);
$r = q("SELECT `id`, `last_contact`, `last_failure`, `network` FROM `gcontact` WHERE `nurl` = '%s' LIMIT 2", dba::lock('gcontact');
$r = q("SELECT `id`, `last_contact`, `last_failure`, `network` FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
dbesc(normalise_link($contact["url"]))); dbesc(normalise_link($contact["url"])));
if ($r) { if (dbm::is_result($r)) {
$gcontact_id = $r[0]["id"]; $gcontact_id = $r[0]["id"];
// Update every 90 days // Update every 90 days
@ -2036,17 +2037,13 @@ function get_gcontact_id($contact) {
$doprobing = in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, "")); $doprobing = in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""));
} }
} }
dba::unlock();
if ($doprobing) { if ($doprobing) {
logger("Last Contact: ". $last_contact_str." - Last Failure: ".$last_failure_str." - Checking: ".$contact["url"], LOGGER_DEBUG); logger("Last Contact: ". $last_contact_str." - Last Failure: ".$last_failure_str." - Checking: ".$contact["url"], LOGGER_DEBUG);
proc_run(PRIORITY_LOW, 'include/gprobe.php', bin2hex($contact["url"])); proc_run(PRIORITY_LOW, 'include/gprobe.php', bin2hex($contact["url"]));
} }
if ((dbm::is_result($r)) AND (count($r) > 1) AND ($gcontact_id > 0) AND ($contact["url"] != ""))
q("DELETE FROM `gcontact` WHERE `nurl` = '%s' AND `id` != %d",
dbesc(normalise_link($contact["url"])),
intval($gcontact_id));
return $gcontact_id; return $gcontact_id;
} }

View file

@ -545,11 +545,16 @@ function admin_page_summary(App $a) {
$showwarning = true; $showwarning = true;
$warningtext[] = sprintf(t('Your DB still runs with MyISAM tables. You should change the engine type to InnoDB. As Friendica will use InnoDB only features in the future, you should change this! See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php include/dbstructure.php toinnodb</tt> of your Friendica installation for an automatic conversion.<br />'), 'https://dev.mysql.com/doc/refman/5.7/en/converting-tables-to-innodb.html'); $warningtext[] = sprintf(t('Your DB still runs with MyISAM tables. You should change the engine type to InnoDB. As Friendica will use InnoDB only features in the future, you should change this! See <a href="%s">here</a> for a guide that may be helpful converting the table engines. You may also use the command <tt>php include/dbstructure.php toinnodb</tt> of your Friendica installation for an automatic conversion.<br />'), 'https://dev.mysql.com/doc/refman/5.7/en/converting-tables-to-innodb.html');
} }
// MySQL >= 5.7.4 doesn't support the IGNORE keyword in ALTER TABLE statements
if ((version_compare($db->server_info(), '5.7.4') >= 0) AND if (Config::get('system', 'dbupdate', DB_UPDATE_NOT_CHECKED) == DB_UPDATE_NOT_CHECKED) {
!(strpos($db->server_info(), 'MariaDB') !== false)) { require_once("include/dbstructure.php");
$warningtext[] = t('You are using a MySQL version which does not support all features that Friendica uses. You should consider switching to MariaDB.'); update_structure(false, true);
} }
if (Config::get('system', 'dbupdate') == DB_UPDATE_FAILED) {
$showwarning = true;
$warningtext[] = t('The database update failed. Please run "php include/dbstructure.php update" from the command line and have a look at the errors that might appear.');
}
$r = q("SELECT `page-flags`, COUNT(`uid`) AS `count` FROM `user` GROUP BY `page-flags`"); $r = q("SELECT `page-flags`, COUNT(`uid`) AS `count` FROM `user` GROUP BY `page-flags`");
$accounts = array( $accounts = array(
array(t('Normal Account'), 0), array(t('Normal Account'), 0),

View file

@ -307,7 +307,7 @@ function _contact_update_profile($contact_id) {
); );
// Update the entry in the contact table // Update the entry in the contact table
update_contact_avatar($data['photo'], local_user(), $contact_id); update_contact_avatar($data['photo'], local_user(), $contact_id, true);
// Update the entry in the gcontact table // Update the entry in the gcontact table
update_gcontact_from_probe($data["url"]); update_gcontact_from_probe($data["url"]);

View file

@ -9,6 +9,7 @@ require_once('include/group.php');
require_once('mod/proxy.php'); require_once('mod/proxy.php');
require_once('include/xml.php'); require_once('include/xml.php');
require_once('include/cache.php'); require_once('include/cache.php');
require_once('include/enotify.php');
/** /**
* @brief Outputs the counts and the lists of various notifications * @brief Outputs the counts and the lists of various notifications

View file

@ -1,8 +1,7 @@
<?php <?php
use Friendica\App; use Friendica\App;
use Friendica\Network\Probe;
require_once 'include/probe.php';
function probe_content(App $a) { function probe_content(App $a) {
@ -22,7 +21,7 @@ function probe_content(App $a) {
if (x($_GET, 'addr')) { if (x($_GET, 'addr')) {
$addr = trim($_GET['addr']); $addr = trim($_GET['addr']);
$res = probe_url($addr); $res = Probe::uri($addr, "", 0, false);
$o .= '<pre>'; $o .= '<pre>';
$o .= str_replace("\n", '<br />', print_r($res, true)); $o .= str_replace("\n", '<br />', print_r($res, true));
$o .= '</pre>'; $o .= '</pre>';

View file

@ -131,8 +131,7 @@ function profile_photo_post(App $a) {
proc_run(PRIORITY_LOW, "include/directory.php", $url); proc_run(PRIORITY_LOW, "include/directory.php", $url);
} }
require_once('include/profile_update.php'); proc_run(PRIORITY_LOW, 'include/profile_update.php', local_user());
profile_change();
} else { } else {
notice( t('Unable to process image') . EOL); notice( t('Unable to process image') . EOL);
} }

View file

@ -4,6 +4,7 @@ use Friendica\App;
use Friendica\Network\Probe; use Friendica\Network\Probe;
require_once 'include/Contact.php'; require_once 'include/Contact.php';
require_once 'include/socgraph.php';
function profiles_init(App $a) { function profiles_init(App $a) {
@ -504,8 +505,7 @@ function profiles_post(App $a) {
proc_run(PRIORITY_LOW, "include/directory.php", $url); proc_run(PRIORITY_LOW, "include/directory.php", $url);
} }
require_once 'include/profile_update.php'; proc_run(PRIORITY_LOW, 'include/profile_update.php', local_user());
profile_change();
// Update the global contact for the user // Update the global contact for the user
update_gcontact_for_user(local_user()); update_gcontact_for_user(local_user());

View file

@ -63,14 +63,14 @@ function receive_post(App $a) {
logger('mod-diaspora: dispatching', LOGGER_DEBUG); logger('mod-diaspora: dispatching', LOGGER_DEBUG);
$ret = 0; $ret = true;
if ($public) { if ($public) {
Diaspora::dispatch_public($msg); Diaspora::dispatch_public($msg);
} else { } else {
$ret = Diaspora::dispatch($importer, $msg); $ret = Diaspora::dispatch($importer, $msg);
} }
http_status_exit(($ret) ? $ret : 200); http_status_exit(($ret) ? 200 : 500);
// NOTREACHED // NOTREACHED
} }

View file

@ -637,8 +637,7 @@ function settings_post(App $a) {
} }
} }
require_once('include/profile_update.php'); proc_run(PRIORITY_LOW, 'include/profile_update.php', local_user());
profile_change();
// Update the global contact for the user // Update the global contact for the user
update_gcontact_for_user(local_user()); update_gcontact_for_user(local_user());

View file

@ -41,11 +41,15 @@ function worker_init($a){
// But since it doesn't destroy anything, we just try to get more execution time in any way. // But since it doesn't destroy anything, we just try to get more execution time in any way.
set_time_limit(0); set_time_limit(0);
if (poller_claim_process($r[0])) {
poller_execute($r[0]); poller_execute($r[0]);
} }
}
call_worker(); call_worker();
poller_unclaim_process();
$a->end_process(); $a->end_process();
logger("Front end worker ended: ".getmypid()); logger("Front end worker ended: ".getmypid());

View file

@ -23,10 +23,10 @@
## ##
# This configuration assumes your domain is example.net # This configuration assumes your domain is example.net
# You have a separate subdomain friendica.example.net # You have a separate subdomain friendica.example.net
# You want all Friendica traffic to be HTTPS # You want all Friendica traffic to be https
# You have an SSL certificate and key for your subdomain # You have an SSL certificate and key for your subdomain
# You have PHP FastCGI Process Manager (php5-fpm) running on localhost # You have PHP FastCGI Process Manager (php5-fpm) running on localhost
# You have Friendica installed in /mnt/friendica/www # You have Friendica installed in /var/www/friendica
## ##
server { server {
@ -34,7 +34,7 @@ server {
server_name friendica.example.net; server_name friendica.example.net;
index index.php; index index.php;
root /mnt/friendica/www; root /var/www/friendica;
rewrite ^ https://friendica.example.net$request_uri? permanent; rewrite ^ https://friendica.example.net$request_uri? permanent;
} }
@ -52,31 +52,47 @@ server {
server_name friendica.example.net; server_name friendica.example.net;
ssl on; ssl on;
#Traditional SSL
ssl_certificate /etc/nginx/ssl/friendica.example.net.chain.pem; ssl_certificate /etc/nginx/ssl/friendica.example.net.chain.pem;
ssl_certificate_key /etc/nginx/ssl/example.net.key; ssl_certificate_key /etc/nginx/ssl/example.net.key;
# If you have used letsencrypt as your SSL provider, remove the previous two lines, and uncomment the following two (adjusting the path) instead.
# ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_timeout 5m; ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP; ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
fastcgi_param HTTPS on;
index index.php; index index.php;
charset utf-8; charset utf-8;
root /mnt/friendica/www; root /var/www/friendica;
access_log /var/log/nginx/friendica.log; access_log /var/log/nginx/friendica.log;
#Uncomment the following line to include a standard configuration file
#Note that the most specific rule wins and your standard configuration
#will therefore *add* to this file, but not override it.
#include standard.conf
# allow uploads up to 20MB in size # allow uploads up to 20MB in size
client_max_body_size 20m; client_max_body_size 20m;
client_body_buffer_size 128k; client_body_buffer_size 128k;
# rewrite to front controller as default rule # rewrite to front controller as default rule
location / { location / {
rewrite ^/(.*) /index.php?q=$uri&$args last; if ($is_args != "") {
rewrite ^/(.*) /index.php?pagename=$uri&$args last;
}
rewrite ^/(.*) /index.php?pagename=$uri last;
} }
# make sure webfinger and other well known services aren't blocked # make sure webfinger and other well known services aren't blocked
# by denying dot files and rewrite request to the front controller # by denying dot files and rewrite request to the front controller
location ^~ /.well-known/ { location ^~ /.well-known/ {
allow all; allow all;
rewrite ^/(.*) /index.php?q=$uri&$args last; rewrite ^/(.*) /index.php?pagename=$uri&$args last;
} }
# statically serve these file types when possible # statically serve these file types when possible
@ -85,7 +101,7 @@ server {
# added .htm for advanced source code editor library # added .htm for advanced source code editor library
location ~* \.(jpg|jpeg|gif|png|ico|css|js|htm|html|ttf|woff|svg)$ { location ~* \.(jpg|jpeg|gif|png|ico|css|js|htm|html|ttf|woff|svg)$ {
expires 30d; expires 30d;
try_files $uri /index.php?q=$uri&$args; try_files $uri /index.php?pagename=$uri&$args;
} }
# block these file types # block these file types
@ -123,4 +139,3 @@ server {
deny all; deny all;
} }
} }

View file

@ -797,6 +797,8 @@ class App {
* @return bool Is the limit reached? * @return bool Is the limit reached?
*/ */
function max_processes_reached() { function max_processes_reached() {
// Deactivated, needs more investigating if this check really makes sense
return false;
if ($this->is_backend()) { if ($this->is_backend()) {
$process = 'backend'; $process = 'backend';
@ -900,12 +902,12 @@ class App {
return; return;
} }
// If the last worker fork was less than 10 seconds before then don't fork another one. // If the last worker fork was less than 2 seconds before then don't fork another one.
// This should prevent the forking of masses of workers. // This should prevent the forking of masses of workers.
$cachekey = 'app:proc_run:started'; $cachekey = 'app:proc_run:started';
$result = Cache::get($cachekey); $result = Cache::get($cachekey);
if (!is_null($result) AND ( time() - $result) < 10) { if (!is_null($result) AND ( time() - $result) < 2) {
return; return;
} }

View file

@ -58,6 +58,28 @@ class Probe {
return $newdata; return $newdata;
} }
/**
* @brief Check if the hostname belongs to the own server
*
* @param string $host The hostname that is to be checked
*
* @return bool Does the testes hostname belongs to the own server?
*/
private function ownHost($host) {
$own_host = get_app()->get_hostname();
$parts = parse_url($host);
if (!isset($parts['scheme'])) {
$parts = parse_url('http://'.$host);
}
if (!isset($parts['host'])) {
return false;
}
return $parts['host'] == $own_host;
}
/** /**
* @brief Probes for XRD data * @brief Probes for XRD data
* *
@ -79,8 +101,11 @@ class Probe {
$xrd_timeout = Config::get('system', 'xrd_timeout', 20); $xrd_timeout = Config::get('system', 'xrd_timeout', 20);
$redirects = 0; $redirects = 0;
logger("Probing for ".$host, LOGGER_DEBUG);
$ret = z_fetch_url($ssl_url, false, $redirects, array('timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml')); $ret = z_fetch_url($ssl_url, false, $redirects, array('timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml'));
if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { if (($ret['errno'] == CURLE_OPERATION_TIMEDOUT) AND !self::ownHost($ssl_url)) {
logger("Probing timeout for ".$ssl_url, LOGGER_DEBUG);
return false; return false;
} }
$xml = $ret['body']; $xml = $ret['body'];
@ -90,18 +115,21 @@ class Probe {
if (!is_object($xrd)) { if (!is_object($xrd)) {
$ret = z_fetch_url($url, false, $redirects, array('timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml')); $ret = z_fetch_url($url, false, $redirects, array('timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml'));
if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) {
logger("Probing timeout for ".$url, LOGGER_DEBUG);
return false; return false;
} }
$xml = $ret['body']; $xml = $ret['body'];
$xrd = parse_xml_string($xml, false); $xrd = parse_xml_string($xml, false);
} }
if (!is_object($xrd)) { if (!is_object($xrd)) {
return false; logger("No xrd object found for ".$host, LOGGER_DEBUG);
return array();
} }
$links = xml::element_to_array($xrd); $links = xml::element_to_array($xrd);
if (!isset($links["xrd"]["link"])) { if (!isset($links["xrd"]["link"])) {
return false; logger("No xrd data found for ".$host, LOGGER_DEBUG);
return array();
} }
$xrd_data = array(); $xrd_data = array();
@ -130,6 +158,8 @@ class Probe {
self::$baseurl = "http://".$host; self::$baseurl = "http://".$host;
logger("Probing successful for ".$host, LOGGER_DEBUG);
return $xrd_data; return $xrd_data;
} }
@ -192,6 +222,10 @@ class Probe {
$lrdd = self::xrd($uri); $lrdd = self::xrd($uri);
$webfinger = null; $webfinger = null;
if (is_bool($lrdd)) {
return array();
}
if (!$lrdd) { if (!$lrdd) {
$parts = @parse_url($uri); $parts = @parse_url($uri);
if (!$parts) { if (!$parts) {
@ -214,6 +248,7 @@ class Probe {
} }
if (!$lrdd) { if (!$lrdd) {
logger("No lrdd data found for ".$uri, LOGGER_DEBUG);
return array(); return array();
} }
@ -249,6 +284,7 @@ class Probe {
} }
if (!is_array($webfinger["links"])) { if (!is_array($webfinger["links"])) {
logger("No webfinger links found for ".$uri, LOGGER_DEBUG);
return false; return false;
} }
@ -392,6 +428,10 @@ class Probe {
} }
$lrdd = self::xrd($host); $lrdd = self::xrd($host);
if (is_bool($lrdd)) {
return array();
}
$path_parts = explode("/", trim($parts["path"], "/")); $path_parts = explode("/", trim($parts["path"], "/"));
while (!$lrdd AND (sizeof($path_parts) > 1)) { while (!$lrdd AND (sizeof($path_parts) > 1)) {
@ -399,6 +439,7 @@ class Probe {
$lrdd = self::xrd($host); $lrdd = self::xrd($host);
} }
if (!$lrdd) { if (!$lrdd) {
logger('No XRD data was found for '.$uri, LOGGER_DEBUG);
return self::feed($uri); return self::feed($uri);
} }
$nick = array_pop($path_parts); $nick = array_pop($path_parts);
@ -429,12 +470,18 @@ class Probe {
} }
$lrdd = self::xrd($host); $lrdd = self::xrd($host);
if (is_bool($lrdd)) {
return array();
}
if (!$lrdd) { if (!$lrdd) {
logger('No XRD data was found for '.$uri, LOGGER_DEBUG);
return self::mail($uri, $uid); return self::mail($uri, $uid);
} }
$addr = $uri; $addr = $uri;
} else { } else {
logger("Uri ".$uri." was not detectable", LOGGER_DEBUG);
return false; return false;
} }
@ -544,6 +591,7 @@ class Probe {
$webfinger = json_decode($data, true); $webfinger = json_decode($data, true);
if (!isset($webfinger["links"])) { if (!isset($webfinger["links"])) {
logger("No json webfinger links for ".$url, LOGGER_DEBUG);
return false; return false;
} }
@ -552,6 +600,7 @@ class Probe {
$xrd_arr = xml::element_to_array($xrd); $xrd_arr = xml::element_to_array($xrd);
if (!isset($xrd_arr["xrd"]["link"])) { if (!isset($xrd_arr["xrd"]["link"])) {
logger("No XML webfinger links for ".$url, LOGGER_DEBUG);
return false; return false;
} }
@ -599,11 +648,13 @@ class Probe {
} }
$content = $ret['body']; $content = $ret['body'];
if (!$content) { if (!$content) {
logger("Empty body for ".$noscrape_url, LOGGER_DEBUG);
return false; return false;
} }
$json = json_decode($content, true); $json = json_decode($content, true);
if (!is_array($json)) { if (!is_array($json)) {
logger("No json data for ".$noscrape_url, LOGGER_DEBUG);
return false; return false;
} }

View file

@ -155,6 +155,12 @@ class ParseUrl {
@curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); @curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
} }
$range = intval(Config::get('system', 'curl_range_bytes', 0));
if ($range > 0) {
curl_setopt($ch, CURLOPT_RANGE, '0-' . $range);
}
$header = curl_exec($ch); $header = curl_exec($ch);
$curl_info = @curl_getinfo($ch); $curl_info = @curl_getinfo($ch);
curl_close($ch); curl_close($ch);

159
src/Util/Lock.php Normal file
View file

@ -0,0 +1,159 @@
<?php
namespace Friendica\Util;
/**
* @file src/Util/Lock.php
* @brief Functions for preventing parallel execution of functions
*
*/
use Friendica\Core\Config;
use Memcache;
use dba;
use dbm;
/**
* @brief This class contain Functions for preventing parallel execution of functions
*/
class Lock {
/**
* @brief Check for memcache and open a connection if configured
*
* @return object|boolean The memcache object - or "false" if not successful
*/
private static function connectMemcache() {
if (!function_exists('memcache_connect')) {
return false;
}
if (!Config::get('system', 'memcache')) {
return false;
}
$memcache_host = Config::get('system', 'memcache_host', '127.0.0.1');
$memcache_port = Config::get('system', 'memcache_port', 11211);
$memcache = new Memcache;
if (!$memcache->connect($memcache_host, $memcache_port)) {
return false;
}
return $memcache;
}
/**
* @brief Sets a lock for a given name
*
* @param string $fn_name Name of the lock
* @param integer $timeout Seconds until we give up
*
* @return boolean Was the lock successful?
*/
public static function set($fn_name, $timeout = 120) {
$got_lock = false;
$start = time();
$memcache = self::connectMemcache();
if (is_object($memcache)) {
$wait_sec = 0.2;
$cachekey = get_app()->get_hostname().";lock:".$fn_name;
do {
$lock = $memcache->get($cachekey);
if (!is_bool($lock)) {
$pid = (int)$lock;
// When the process id isn't used anymore, we can safely claim the lock for us.
// Or we do want to lock something that was already locked by us.
if (!posix_kill($pid, 0) OR ($pid == getmypid())) {
$lock = false;
}
}
if (is_bool($lock)) {
$memcache->set($cachekey, getmypid(), MEMCACHE_COMPRESSED, 300);
$got_lock = true;
}
if (!$got_lock AND ($timeout > 0)) {
usleep($wait_sec * 1000000);
}
} while (!$got_lock AND ((time() - $start) < $timeout));
return $got_lock;
}
$wait_sec = 2;
do {
dba::lock('locks');
$lock = dba::select('locks', array('locked', 'pid'), array('name' => $fn_name), array('limit' => 1));
if (dbm::is_result($lock)) {
if ($lock['locked']) {
// When the process id isn't used anymore, we can safely claim the lock for us.
if (!posix_kill($lock['pid'], 0)) {
$lock['locked'] = false;
}
// We want to lock something that was already locked by us? So we got the lock.
if ($lock['pid'] == getmypid()) {
$got_lock = true;
}
}
if (!$lock['locked']) {
dba::update('locks', array('locked' => true, 'pid' => getmypid()), array('name' => $fn_name));
$got_lock = true;
}
} elseif (!dbm::is_result($lock)) {
dba::insert('locks', array('name' => $fn_name, 'locked' => true, 'pid' => getmypid()));
$got_lock = true;
}
dba::unlock();
if (!$got_lock AND ($timeout > 0)) {
sleep($wait_sec);
}
} while (!$got_lock AND ((time() - $start) < $timeout));
return $got_lock;
}
/**
* @brief Removes a lock if it was set by us
*
* @param string $fn_name Name of the lock
*/
public static function remove($fn_name) {
$memcache = self::connectMemcache();
if (is_object($memcache)) {
$cachekey = get_app()->get_hostname().";lock:".$fn_name;
$lock = $memcache->get($cachekey);
if (!is_bool($lock)) {
if ((int)$lock == getmypid()) {
$memcache->delete($cachekey);
}
}
return;
}
dba::update('locks', array('locked' => false, 'pid' => 0), array('name' => $fn_name, 'pid' => getmypid()));
return;
}
/**
* @brief Removes all lock that were set by us
*/
public static function removeAll() {
$memcache = self::connectMemcache();
if (is_object($memcache)) {
// We cannot delete all cache entries, but this doesn't matter with memcache
return;
}
dba::update('locks', array('locked' => false, 'pid' => 0), array('pid' => getmypid()));
return;
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
define('UPDATE_VERSION' , 1224); define('UPDATE_VERSION' , 1228);
/** /**
* *

View file

@ -1,4 +1,4 @@
INPUT = README.md index.php boot.php testargs.php update.php mod/ object/ include/ js/ util/ view/ version.inc INPUT = README.md index.php boot.php testargs.php update.php mod/ object/ include/ js/ util/ view/ src/ version.inc
RECURSIVE = YES RECURSIVE = YES
PROJECT_NAME = "Friendica" PROJECT_NAME = "Friendica"
PROJECT_LOGO = images/friendica-64.jpg PROJECT_LOGO = images/friendica-64.jpg

View file

@ -13,6 +13,7 @@ Andreas H.
Andrej Stieben Andrej Stieben
André Alves André Alves
André Lohan André Lohan
Andy H3
Anthronaut Anthronaut
Arian - Cazare Muncitori Arian - Cazare Muncitori
Athalbert Athalbert

View file

@ -69,7 +69,7 @@ $a->config['system']['no_regfullname'] = true;
//$a->config['system']['block_local_dir'] = false; //$a->config['system']['block_local_dir'] = false;
// Location of the global directory // Location of the global directory
$a->config['system']['directory'] = 'http://dir.friendi.ca'; $a->config['system']['directory'] = 'http://dir.friendica.social';
// turn on friendica's log // turn on friendica's log
$a->config['system']['debugging'] = true; $a->config['system']['debugging'] = true;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

8944
view/lang/en-gb/messages.po Normal file

File diff suppressed because it is too large Load diff

2062
view/lang/en-gb/strings.php Normal file

File diff suppressed because it is too large Load diff

8943
view/lang/en-us/messages.po Normal file

File diff suppressed because it is too large Load diff

2062
view/lang/en-us/strings.php Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -98,7 +98,7 @@ $a->config['system']['no_regfullname'] = true;
//$a->config['system']['block_local_dir'] = false; //$a->config['system']['block_local_dir'] = false;
// Location of the global directory // Location of the global directory
$a->config['system']['directory'] = 'http://dir.friendi.ca'; $a->config['system']['directory'] = 'http://dir.friendica.social';
// Authentication cookie lifetime, in days // Authentication cookie lifetime, in days
$a->config['system']['auth_cookie_lifetime'] = 7; $a->config['system']['auth_cookie_lifetime'] = 7;

View file

@ -37,20 +37,12 @@ function insertFormatting(BBcode, id) {
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") {
selected.text = "["+BBcode+"]" + "http://" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]"; selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + "http://" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length); textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} }
}
return true; return true;
} }

View file

@ -13,11 +13,11 @@ I conentrated on 3 topics:
* if you update the theme you should disable and enable the theme again from the admin panel (to apply possible new hooks) * if you update the theme you should disable and enable the theme again from the admin panel (to apply possible new hooks)
**Note:** **Note:**
This theme is marked as experimental. While it is doing its job very well in the most cases there still much work to do to get it marked as stable. So some important templates are still missing and will be added in future versions. While Frio is doing its job very well in most cases, there still is some work to do. Some templates are still missing and will be added in future versions.
Some insights into my motivation for starting coding this theme: Some insights into my motivation for starting coding this theme:
This theme should be the start of a discussion in the friendica community (users and developers) about UI/UX in friendica. This theme should be the start of a discussion in the friendica community (users and developers) about UI/UX in friendica.
What frameworks do we want to use? How should default friendica look like? And how do we want to use friendica? What do we need in the core code (At the present time some stuff in this is done with ugly javascript hacks and own php code)? What frameworks do we want to use? How should default friendica look like? And how do we want to use friendica? What do we need in the core code (At the present time some stuff this is done with ugly javascript hacks and own php code)?
Coding a theme is much work but you will get a really good insight of the limitations of friendica and can start a discussion about doing things differently. Coding a theme is much work but you will get a really good insight of the limitations of friendica and can start a discussion about doing things differently.
So join the discussion at the friendica forums ;-) So join the discussion at the friendica forums ;-)

View file

@ -22,7 +22,7 @@
#fc-header-right { #fc-header-right {
margin-top: -4px; margin-top: -4px;
} }
#fc-header-right button { #fc-header-right .dropdown > button {
color: inherit; color: inherit;
} }
#event-calendar-title { #event-calendar-title {

View file

@ -4,9 +4,8 @@
// Catch the GUID from the URL // Catch the GUID from the URL
var itemGuid = window.location.pathname.split("/").pop(); var itemGuid = window.location.pathname.split("/").pop();
var itemGuidSafe = itemGuid.replace(/%.*/, '');
$(window).load(function(){ $(window).load(function(){
// Scroll to the Item by its GUID // Scroll to the Item by its GUID
scrollToItem('item-' + itemGuidSafe); scrollToItem('item-' + itemGuid);
}); });

View file

@ -3,7 +3,7 @@
*/ */
function insertFormatting(BBcode,id) { function insertFormatting(BBcode, id) {
var tmpStr = $("#comment-edit-text-" + id).val(); var tmpStr = $("#comment-edit-text-" + id).val();
if (tmpStr == '') { if (tmpStr == '') {
$("#comment-edit-text-" + id).addClass("comment-edit-text-full"); $("#comment-edit-text-" + id).addClass("comment-edit-text-full");
@ -11,23 +11,15 @@ function insertFormatting(BBcode,id) {
openMenu("comment-edit-submit-wrapper-" + id); openMenu("comment-edit-submit-wrapper-" + id);
} }
textarea = document.getElementById("comment-edit-text-" +id); textarea = document.getElementById("comment-edit-text-" + id);
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") { selected.text = "[" + BBcode + "]" + selected.text + "[/" + BBcode + "]";
selected.text = "["+BBcode+"]" + "http://" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") { textarea.value = textarea.value.substring(0, start) + "[" + BBcode + "]" + textarea.value.substring(start, end) + "[/" + BBcode + "]" + textarea.value.substring(end, textarea.value.length);
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + "http://" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
}
} }
$(textarea).trigger('change'); $(textarea).trigger('change');
@ -62,7 +54,7 @@ function commentExpand(id) {
return true; return true;
} }
function commentClose(obj,id) { function commentClose(obj, id) {
if (obj.value == '') { if (obj.value == '') {
$("#comment-edit-text-" + id).removeClass("comment-edit-text-full"); $("#comment-edit-text-" + id).removeClass("comment-edit-text-full");
$("#comment-edit-text-" + id).addClass("comment-edit-text-empty"); $("#comment-edit-text-" + id).addClass("comment-edit-text-empty");
@ -74,10 +66,9 @@ function commentClose(obj,id) {
} }
function showHideCommentBox(id) { function showHideCommentBox(id) {
if( $('#comment-edit-form-' + id).is(':visible')) { if ($('#comment-edit-form-' + id).is(':visible')) {
$('#comment-edit-form-' + id).hide(); $('#comment-edit-form-' + id).hide();
} } else {
else {
$('#comment-edit-form-' + id).show(); $('#comment-edit-form-' + id).show();
} }
} }
@ -86,8 +77,8 @@ function commentOpenUI(obj, id) {
$("#comment-edit-text-" + id).addClass("comment-edit-text-full").removeClass("comment-edit-text-empty"); $("#comment-edit-text-" + id).addClass("comment-edit-text-full").removeClass("comment-edit-text-empty");
// Choose an arbitrary tab index that's greater than what we're using in jot (3 of them) // Choose an arbitrary tab index that's greater than what we're using in jot (3 of them)
// The submit button gets tabindex + 1 // The submit button gets tabindex + 1
$("#comment-edit-text-" + id).attr('tabindex','9'); $("#comment-edit-text-" + id).attr('tabindex', '9');
$("#comment-edit-submit-" + id).attr('tabindex','10'); $("#comment-edit-submit-" + id).attr('tabindex', '10');
$("#comment-edit-submit-wrapper-" + id).show(); $("#comment-edit-submit-wrapper-" + id).show();
// initialize autosize for this comment // initialize autosize for this comment
autosize($("#comment-edit-text-" + id + ".text-autosize")); autosize($("#comment-edit-text-" + id + ".text-autosize"));
@ -120,7 +111,7 @@ function jotTextCloseUI(obj) {
} }
} }
function commentOpen(obj,id) { function commentOpen(obj, id) {
if (obj.value == '') { if (obj.value == '') {
$("#comment-edit-text-" + id).addClass("comment-edit-text-full"); $("#comment-edit-text-" + id).addClass("comment-edit-text-full");
$("#comment-edit-text-" + id).removeClass("comment-edit-text-empty"); $("#comment-edit-text-" + id).removeClass("comment-edit-text-empty");
@ -131,7 +122,7 @@ function commentOpen(obj,id) {
return false; return false;
} }
function commentInsert(obj,id) { function commentInsert(obj, id) {
var tmpStr = $("#comment-edit-text-" + id).val(); var tmpStr = $("#comment-edit-text-" + id).val();
if (tmpStr == '') { if (tmpStr == '') {
$("#comment-edit-text-" + id).addClass("comment-edit-text-full"); $("#comment-edit-text-" + id).addClass("comment-edit-text-full");
@ -139,14 +130,14 @@ function commentInsert(obj,id) {
openMenu("comment-edit-submit-wrapper-" + id); openMenu("comment-edit-submit-wrapper-" + id);
} }
var ins = $(obj).html(); var ins = $(obj).html();
ins = ins.replace('&lt;','<'); ins = ins.replace('&lt;', '<');
ins = ins.replace('&gt;','>'); ins = ins.replace('&gt;', '>');
ins = ins.replace('&amp;','&'); ins = ins.replace('&amp;', '&');
ins = ins.replace('&quot;','"'); ins = ins.replace('&quot;', '"');
$("#comment-edit-text-" + id).val(tmpStr + ins); $("#comment-edit-text-" + id).val(tmpStr + ins);
} }
function qCommentInsert(obj,id) { function qCommentInsert(obj, id) {
var tmpStr = $("#comment-edit-text-" + id).val(); var tmpStr = $("#comment-edit-text-" + id).val();
if (tmpStr == '') { if (tmpStr == '') {
$("#comment-edit-text-" + id).addClass("comment-edit-text-full"); $("#comment-edit-text-" + id).addClass("comment-edit-text-full");
@ -154,15 +145,17 @@ function qCommentInsert(obj,id) {
openMenu("comment-edit-submit-wrapper-" + id); openMenu("comment-edit-submit-wrapper-" + id);
} }
var ins = $(obj).val(); var ins = $(obj).val();
ins = ins.replace('&lt;','<'); ins = ins.replace('&lt;', '<');
ins = ins.replace('&gt;','>'); ins = ins.replace('&gt;', '>');
ins = ins.replace('&amp;','&'); ins = ins.replace('&amp;', '&');
ins = ins.replace('&quot;','"'); ins = ins.replace('&quot;', '"');
$("#comment-edit-text-" + id).val(tmpStr + ins); $("#comment-edit-text-" + id).val(tmpStr + ins);
$(obj).val(''); $(obj).val('');
} }
function confirmDelete() { return confirm(aStr.delitem); } function confirmDelete() {
return confirm(aStr.delitem);
}
/** /**
* Hide and removes an item element from the DOM after the deletion url is * Hide and removes an item element from the DOM after the deletion url is

View file

@ -2,7 +2,7 @@
/* /*
* Name: frio * Name: frio
* Description: Bootstrap V3 theme. The theme is currently under construction, so it is far from finished. For further information have a look at the <a href="https://github.com/friendica/friendica/tree/develop/view/theme/frio/README.md">ReadMe</a>. * Description: Bootstrap V3 theme. The theme is currently under construction, so it is far from finished. For further information have a look at the <a href="https://github.com/friendica/friendica/tree/develop/view/theme/frio/README.md">ReadMe</a>.
* Version: V.0.7 * Version: V.0.8
* Author: Rabuzarus <https://friendica.kommune4.de/profile/rabuzarus> * Author: Rabuzarus <https://friendica.kommune4.de/profile/rabuzarus>
* *
*/ */

View file

@ -423,20 +423,12 @@ function insertFormatting(BBcode, id) {
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") {
selected.text = "["+BBcode+"=http://]" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]"; selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"=http://]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length); textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} }
}
return true; return true;
} }

View file

@ -603,20 +603,12 @@ function insertFormatting(BBcode, id) {
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") {
selected.text = "["+BBcode+"=http://]" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]"; selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"=http://]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length); textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} }
}
return true; return true;
} }

View file

@ -71,20 +71,12 @@ function insertFormatting(BBcode, id) {
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") {
selected.text = "["+BBcode+"]" + "http://" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]"; selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + "http://" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length); textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} }
}
return true; return true;
} }

View file

@ -20,24 +20,14 @@ function insertFormatting(BBcode, id) {
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") {
selected.text = "["+BBcode+"]" + "http://" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]"; selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]"
+ "http://" + textarea.value.substring(start, end)
+ "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) textarea.value = textarea.value.substring(0, start)
+ "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]"
+ textarea.value.substring(end, textarea.value.length); + textarea.value.substring(end, textarea.value.length);
} }
}
return true; return true;
} }

View file

@ -33,20 +33,12 @@ function insertFormatting(BBcode, id) {
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") {
selected.text = "["+BBcode+"]" + "http://" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]"; selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + "http://" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length); textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} }
}
return true; return true;
} }

View file

@ -50,20 +50,12 @@ function insertFormatting(BBcode, id) {
if (document.selection) { if (document.selection) {
textarea.focus(); textarea.focus();
selected = document.selection.createRange(); selected = document.selection.createRange();
if (BBcode == "url") {
selected.text = "["+BBcode+"]" + "http://" + selected.text + "[/"+BBcode+"]";
} else {
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]"; selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
}
} else if (textarea.selectionStart || textarea.selectionStart == "0") { } else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart; var start = textarea.selectionStart;
var end = textarea.selectionEnd; var end = textarea.selectionEnd;
if (BBcode == "url") {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + "http://" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else {
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length); textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} }
}
return true; return true;
} }