Merge branch 'develop' of https://github.com/friendica/friendica into develop

This commit is contained in:
Ralf Thees 2018-09-05 20:08:56 +02:00
commit 7edbef9bdc
55 changed files with 41619 additions and 40385 deletions

View File

@ -41,7 +41,7 @@ define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily');
define('FRIENDICA_VERSION', '2018.08-dev');
define('DFRN_PROTOCOL_VERSION', '2.23');
define('DB_UPDATE_VERSION', 1282);
define('DB_UPDATE_VERSION', 1283);
define('NEW_UPDATE_ROUTINE_VERSION', 1170);
/**

View File

@ -74,7 +74,8 @@
"require-dev": {
"phpunit/dbunit": "^2.0",
"phpdocumentor/reflection-docblock": "^3.0.2",
"phpunit/php-token-stream": "^1.4.2"
"phpunit/php-token-stream": "^1.4.2",
"mikey179/vfsStream": "^1.6"
},
"scripts": {
"test": "phpunit"

48
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "9e24971ae9340c5d9d4d4ca477d4ec29",
"content-hash": "d62c3e3d6971ee63a862a22ff3cd3768",
"packages": [
{
"name": "asika/simple-console",
@ -2252,6 +2252,52 @@
],
"time": "2015-06-14T21:17:01+00:00"
},
{
"name": "mikey179/vfsStream",
"version": "v1.6.5",
"source": {
"type": "git",
"url": "https://github.com/mikey179/vfsStream.git",
"reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
"reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-0": {
"org\\bovigo\\vfs\\": "src/main/php"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Frank Kleine",
"homepage": "http://frankkleine.de/",
"role": "Developer"
}
],
"description": "Virtual file system to mock the real file system in unit tests.",
"homepage": "http://vfs.bovigo.org/",
"time": "2017-08-01T08:02:14+00:00"
},
{
"name": "myclabs/deep-copy",
"version": "1.7.0",

View File

@ -1224,6 +1224,19 @@
"username": ["username(32)"]
}
},
"user-contact": {
"comment": "User specific public contact data",
"fields": {
"cid": {"type": "int unsigned", "not null": "1", "default": "0", "primary": "1", "relation": {"contact": "id"}, "comment": "Contact id of the linked public contact"},
"uid": {"type": "mediumint unsigned", "not null": "1", "default": "0", "primary": "1", "relation": {"user": "uid"}, "comment": "User id"},
"blocked": {"type": "boolean", "comment": "Contact is completely blocked for this user"},
"ignored": {"type": "boolean", "comment": "Posts from this contact are ignored"},
"collapsed": {"type": "boolean", "comment": "Posts from this contact are collapsed"}
},
"indexes": {
"PRIMARY": ["uid", "cid"]
}
},
"user-item": {
"comment": "User specific item data",
"fields": {

View File

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2018.08-dev (The Tazmans Flax-lily)
-- DB_UPDATE_VERSION 1282
-- DB_UPDATE_VERSION 1283
-- ------------------------------------------
@ -1173,6 +1173,18 @@ CREATE TABLE IF NOT EXISTS `userd` (
INDEX `username` (`username`(32))
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Deleted usernames';
--
-- TABLE user-contact
--
CREATE TABLE IF NOT EXISTS `user-contact` (
`cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Contact id of the linked public contact',
`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id',
`blocked` boolean COMMENT 'Contact is completely blocked for this user',
`ignored` boolean COMMENT 'Posts from this contact are ignored',
`collapsed` boolean COMMENT 'Posts from this contact are collapsed',
PRIMARY KEY(`uid`,`cid`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='User specific public contact data';
--
-- TABLE user-item
--

View File

@ -111,30 +111,86 @@ You might wish to move/rename `config/local.ini.php` to another name and empty (
### Option B: Run the automatic install script
Open the file htconfig.php in the main Friendica directory with a text editor.
Remove the `die('...');` line and edit the lines to suit your installation (MySQL, language, theme etc.).
Then save the file (do not rename it).
You have the following options to automatically install Friendica:
- creating a prepared config file (f.e. `prepared.ini.php`)
- using environment variables (f.e. `MYSQL_HOST`)
- using options (f.e. `--dbhost <host>`)
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall
Or if you wish to include all optional checks, execute this statement instead:
bin/console autoinstall -a
At this point visit your website again, and register your personal account.
*If* the automatic installation fails for any reason, check the following:
* Does "config/local.ini.php" already exist? If yes, the automatic installation won't start
* Are the settings inside "htconfig.php" correct? If not, edit the file again.
* Is the empty MySQL-database created? If not, create it.
You can combine environment variables and options, but be aware that options are prioritized over environment variables.
For more information during the installation, you can use this command line option
bin/console autoinstall -v
If you wish to include all optional checks, use `-a` like this statement:
bin/console autoinstall -a
*If* the automatic installation fails for any reason, check the following:
* Does `config/local.ini.php` already exist? If yes, the automatic installation won't start
* Are the options in the `config/local.ini.php` correct? If not, edit them directly.
* Is the empty MySQL-database created? If not, create it.
#### B.1: Config file
You can use a prepared config file like [local-sample.ini.php](config/local-sample.ini.php).
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall -f <prepared.ini.php>
#### B.2: Environment variables
There are two types of environment variables.
- those you can use in normal mode too (Currently just **database credentials**)
- those you can only use during installation (because Friendica will normally ignore it)
You can use the options during installation too and skip some of the environment variables.
**Database credentials**
if you don't use the option `--savedb` during installation, the DB credentials will **not** be saved in the `config/local.ini.php`.
- `MYSQL_HOST` The host of the mysql/mariadb database
- `MYSQL_PORT` The port of the mysql/mariadb database
- `MYSQL_USERNAME` The username of the mysql database login (used for mysql)
- `MYSQL_USER` The username of the mysql database login (used for mariadb)
- `MYSQL_PASSWORD` The password of the mysql/mariadb database login
- `MYSQL_DATABASE` The name of the mysql/mariadb database
**Friendica settings**
This variables wont be used at normal Friendica runtime.
Instead, they get saved into `config/local.ini.php`.
- `FRIENDICA_PHP_PATH` The path of the PHP binary
- `FRIENDICA_ADMIN_MAIL` The admin email address of Friendica (this email will be used for admin access)
- `FRIENDICA_TZ` The timezone of Friendica
- `FRIENDICA_LANG` The langauge of Friendica
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall [--savedb]
#### B.3: Execution options
All options will be saved in the `config/local.ini.php` and are overruling the associated environment variables.
- `-H|--dbhost <host>` The host of the mysql/mariadb database (env `MYSQL_HOST`)
- `-p|--dbport <port>` The port of the mysql/mariadb database (env `MYSQL_PORT`)
- `-U|--dbuser <username>` The username of the mysql/mariadb database login (env `MYSQL_USER` or `MYSQL_USERNAME`)
- `-P|--dbpass <password>` The password of the mysql/mariadb database login (env `MYSQL_PASSWORD`)
- `-d|--dbdata <database>` The name of the mysql/mariadb database (env `MYSQL_DATABASE`)
- `-b|--phppath <path>` The path of the PHP binary (env `FRIENDICA_PHP_PATH`)
- `-A|--admin <mail>` The admin email address of Friendica (env `FRIENDICA_ADMIN_MAIL`)
- `-T|--tz <timezone>` The timezone of Friendica (env `FRIENDICA_TZ`)
- `-L|--land <language>` The language of Friendica (env `FRIENDICA_LANG`)
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall [options]
### Prepare .htaccess file
Copy .htaccess-dist to .htaccess (be careful under Windows) to have working mod-rewrite again. If you have installed Friendica into a sub directory, like /friendica/ set this path in RewriteBase accordingly.
@ -145,6 +201,23 @@ Example:
*Note*: Do **not** rename the .htaccess-dist file as it is tracked by GIT and renaming will cause a dirty working directory.
### Verify the "host-meta" page is working
Friendica should respond automatically to important addresses under the /.well-known/ rewrite path.
One critical URL would look like, for example, https://example.com/.well-known/host-meta
It must be visible to the public and must respond with an XML file that is automatically customized to your site.
If that URL is not working, it is possible that some other software is using the /.well-known/ path.
Other symptoms may include an error message in the Admin settings that says "host-meta is not reachable on your system.
This is a severe configuration issue that prevents server to server communication."
Another common error related to host-meta is the "Invalid profile URL."
Check for a .well-known directory that did not come with Friendica.
The preferred configuration is to remove the directory, however this is not always possible.
If there is any /.well-known/.htaccess file, it could interfere with this Friendica core requirement.
You should remove any RewriteRules from that file, or remove that whole file if appropriate.
It may be necessary to chmod the /.well-known/.htaccess file if you were not given write permissions by default.
### Set up the worker
Set up a cron job or scheduled task to run the worker once every 5-10 minutes in order to perform background processing.

View File

@ -1,31 +1,31 @@
How to move your account between servers
============
* [Home](help)
! **This is an experimental feature**
* Go to "Settings" -> "[Export personal data](uexport)"
* Click on "Export account" to save your account data.
* **Save the file in a secure place!** It contains your details, your contacts, groups, and personal settings. It also contains your secret keys to authenticate yourself to your contacts.
* Go to your new server, and open *http://newserver.com/uimport* (there is not a direct link to this page at the moment).
* Do NOT create a new account prior to importing your old settings - uimport should be used *instead* of register.
* Load your saved account file and click "Import".
* After the move, the account on the old server will not work reliably anymore, and should be not used.
Friendica contacts
---
Friendica will recreate your account on the new server, with your contacts and groups.
A message is sent to Friendica contacts, to inform them about your move:
If your contacts are runnning on an updated server, your details on their side will be automatically updated.
GNU Social contacts
---
Contacts on GNU Social will be archived, as we can't inform them about your move.
You should ask them to remove your contact from their lists and re-add you, and you should do the same with their contact.
Diaspora contacts
---
Newer Diaspora servers are able to process "account migration" messages.
How to move your account between servers
============
* [Home](help)
! **This is an experimental feature**
* Go to "Settings" -> "[Export personal data](uexport)"
* Click on "Export account" to save your account data.
* **Save the file in a secure place!** It contains your details, your contacts, groups, and personal settings. It also contains your secret keys to authenticate yourself to your contacts.
* Go to your new server, and open *http://newserver.com/uimport* (there is not a direct link to this page at the moment). Please consider that this is only possible on servers with open registration. On other systems only the administrator can add accounts with an uploaded file.
* Do NOT create a new account prior to importing your old settings - uimport should be used *instead* of register.
* Load your saved account file and click "Import".
* After the move, the account on the old server will not work reliably anymore, and should be not used.
Friendica contacts
---
Friendica will recreate your account on the new server, with your contacts and groups.
A message is sent to Friendica contacts, to inform them about your move:
If your contacts are runnning on an updated server, your details on their side will be automatically updated.
GNU Social contacts
---
Contacts on GNU Social will be archived, as we can't inform them about your move.
You should ask them to remove your contact from their lists and re-add you, and you should do the same with their contact.
Diaspora contacts
---
Newer Diaspora servers are able to process "account migration" messages.

View File

@ -112,29 +112,88 @@ Alle Registrierungsprobleme sollten automatisch behebbar sein.
Wenn du irgendwelche **kritischen** Fehler zu diesen Zeitpunkt erhalten solltest, deutet das darauf hin, dass die Datenbank nicht korrekt installiert wurde.
Du kannst bei Bedarf die Datei config/local.ini.php verschieben/umbenennen und die Datenbank leeren (als „Dropping“ bezeichnet), so dass du mit einem sauberen System neu starten kannst.
### Option B: Starte das manuelle Installationsscript
### Option B: Starte das automatische Installationsscript
Öffne die Datei htconfig.php im Friendica-Hauptordner mit einem Text-Editor.
Entferne die `die('...');` Zeile und bearbeite die Einstellungen so, das sie zu deinem System passen (MySQL, Sprache, Theme etc.).
Dann speichere die Datei (jedoch nicht umbenennen).
Es existieren folgende Varianten zur automatischen Installation von Friendica:
- Eine vorgefertigte Konfigurationsdatei erstellen (z.B. `prepared.ini.php`)
- Verwendung von Umgebungsvariablen (z.B. `MYSQL_HOST`)
- Verwendung von Optionen (z.B. `--dbhost <host>`)
Gehe in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus:
bin/console autoinstall
Oder falls du alle optionalen Checks ausfürehn lassen möchtest, benutze diese Option:
bin/console autoinstall -a
*Wenn* die automatisierte Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende:
* Existiert die `config/local.ini.php`? Falls ja, wird die automatisierte Installation nicht gestartet.
* Sind Einstellungen in der `config/local.ini.php` korrekt? Falls nicht, bitte bearbeite diese Datei erneut.
* Ist die leere MySQL-Datenbank erstellt? Falls nicht, erstelle diese.
Umgebungsvariablen und Optionen können auch kombiniert werden.
Dabei ist jedoch darauf zu achten, dass etwaige Optionen immer die zugehörigen Umgebungsvariablen überschreiben.
Für mehr Informationen kannst du diese Option verwenden:
bin/console autoinstall -v
Falls du alle optionalen Checks ausfürehn lassen möchtest, benutze diese Option:
bin/console autoinstall -a
*Wenn* die automatisierte Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende:
* Existiert die `config/local.ini.php`? Falls ja, wird die automatisierte Installation nicht gestartet.
* Sind Einstellungen in der `config/local.ini.php` korrekt? Falls nicht, bitte bearbeite diese Datei erneut.
* Ist die leere MySQL-Datenbank erstellt? Falls nicht, erstelle diese.
#### B.1: Konfigurationsdatei
Für diese Variante muss ein Konfigurationsdatei bereits vor der Installation fertig definiert sein (z.B. [local-sample.ini.php](config/local-sample.ini.php).
Gehe im Anschluss in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus:
bin/console autoinstall -f <prepared.ini.php>
#### B.2: Umgebungsvariablen
Es existieren Zwei Arten von Umgebungsvariablen in Friendica:
- Jene, die auch im normalen Betrieb verwendet werden können (derzeit ausschließlich **Datenbank Einstellungen**)
- Jene, die nur während der Installation verwedent werden können (im normalen Betrieb werden sie ignoriert)
Umgebungsvariablen können auch durch adäquate Optionen (z.B. `--dbhost <hostname>`)übersteuert werden.
**Datenbank Einstellungen**
Nur wenn die Option `--savedb` gesetzt ist, werden diese Umgebungsvariablen auch in `config/local.ini.php` gespeichert!
- `MYSQL_HOST` Der Host der MySQL/MariaDB Datenbank
- `MYSQL_PORT` Der Port der MySQL/MariaDB Datenbank
- `MYSQL_USERNAME` Der Benutzername des MySQL Datenbanklogins (MySql - Variante)
- `MYSQL_USER` Der Benutzername des MariaDB Datenbanklogins (MariaDB-Variante)
- `MYSQL_PASSWORD` Das Passwort der MySQL/MariaDB Datenbanklogins
- `MYSQL_DATABASE` Der Name der MySQL/MariaDB Datenbank
**Friendica Einstellungen**
Diese Umgebungsvariablen können nicht während des normalen Friendica Betriebs verwendet werden.
Sie werden stattdessen direkt in `config/local.ini.php` gespeichert.
- `FRIENDICA_PHP_PATH` Der Pfad zur PHP-Datei
- `FRIENDICA_ADMIN_MAIL` Die Admin E-Mail Adresse dieses Friendica Knotens (wird auch für den Admin-Zugang benötigt)
- `FRIENDICA_TZ` Die Zeitzone von Friendica
- `FRIENDICA_LANG` Die Sprache von Friendica
Gehe im Anschluss in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus:
bin/console autoinstall [--savedb]
#### B.3: Optionen
Alle Optionen werden in `config/local.ini.php` gespeichert und überschreiben etwaige, zugehörige Umgebungsvariablen.
- `-H|--dbhost <host>` Der Host der MySQL/MariaDB Datenbank (env `MYSQL_HOST`)
- `-p|--dbport <port>` Der Port der MySQL/MariaDB Datenbank (env `MYSQL_PORT`)
- `-U|--dbuser <username>` Der Benutzername des MySQL/MariaDB Datenbanklogins (env `MYSQL_USER` or `MYSQL_USERNAME`)
- `-P|--dbpass <password>` Das Passwort der MySQL/MariaDB Datenbanklogins (env `MYSQL_PASSWORD`)
- `-d|--dbdata <database>` Der Name der MySQL/MariaDB Datenbank (env `MYSQL_DATABASE`)
- `-b|--phppath <path>` Der Pfad zur PHP-Datei (env `FRIENDICA_PHP_PATH`)
- `-A|--admin <mail>` Die Admin E-Mail Adresse dieses Friendica Knotens (env `FRIENDICA_ADMIN_MAIL`)
- `-T|--tz <timezone>` Die Zeitzone von Friendica (env `FRIENDICA_TZ`)
- `-L|--land <language>` Die Sprache von Friendica (env `FRIENDICA_LANG`)
Gehe in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus:
bin/console autoinstall [options]
### Einen Worker einrichten
Erstelle einen Cron job oder einen regelmäßigen Task, um den Poller alle 5-10 Minuten im Hintergrund ablaufen zu lassen.

View File

@ -1,34 +1,38 @@
Accounts Umziehen
=================
* [Zur Startseite der Hilfe](help)
! **Dies ist ein experimentelles Feature**
**Wie man einen Account von einem Server zu einem anderen umzieht.**
Unter "Einstellungen" -> "[Persönliche Daten exportieren](uexport)" aufrufen.
"Account exportieren" anklicken und die Daten speichern.
Diese Datei enthält Details über dich, deine Kontakte, Gruppen und persönliche Einstellungen.
Außerdem enthält sie deinen geheimen Schlüssel mit dem du dich deinen Kontakten gegenüber ausweist.
**Speichere diese Datei an einem sicheren Ort**!
Rufe nun dem neuen Server die Seite *http://newserver.com/uimport* auf (es gibt derzeit keinen direkten Link auf diese Seite).
Lege auf dem neuen Server auf keinen Fall einen gleichnamigen Account an!
uimport muss anstelle des Registrierens verwendet werden.
Wähle die gesicherte Account Datei aus und klicke "Importieren".
Friendica wird nun deinen Account auf dem neuen Server wiederherstellen, mit all deinen Friendica Kontakten und Gruppen.
An deine Friendica Kontakte wird außerdem eine Nachricht gesendet um sie über deine neue Adresse zu informieren.
Wenn deine Kontakte ihren Account auf einem aktuellen Server haben werden deine Kontaktdetails automatisch aktualisiert.
Neuere Diaspora Server unterstützen ebenfalls eine Umzugsbenachrichtigung.
Kontakte auf GNU Social werden archiviert, da wir ihnen keine Information über deinen Umzug zukommen lassen können.
Du solltest sie persönlich anschreiben deinen Eintrag aus ihren Kontaktlisten zu entfernen und dich neu hinzuzufügen, anschließend solltest du da gleiche mit ihren Accounts tun.
Nach dem Umzug wird dein Account auf dem alten Server nicht mehr zuverlässig funktionieren und sollte deshalb gelöscht werden.
Accounts Umziehen
=================
* [Zur Startseite der Hilfe](help)
! **Dies ist ein experimentelles Feature**
**Wie man einen Account von einem Server zu einem anderen umzieht.**
Unter "Einstellungen" -> "[Persönliche Daten exportieren](uexport)" aufrufen.
"Account exportieren" anklicken und die Daten speichern.
Diese Datei enthält Details über dich, deine Kontakte, Gruppen und persönliche Einstellungen.
Außerdem enthält sie deinen geheimen Schlüssel mit dem du dich deinen Kontakten gegenüber ausweist.
**Speichere diese Datei an einem sicheren Ort**!
Rufe nun dem neuen Server die Seite *http://newserver.com/uimport* auf (es gibt derzeit keinen direkten Link auf diese Seite).
Bitte beachte, dass dies nur auf Servern möglich ist, an denen man sich offen anmelden kann.
Bei Servern, bei denen der Administrator Accounts freigeben muss, ist das Hochladen nicht möglich.
Hier kann dies nur der Administrator selber durchführen.
Lege auf dem neuen Server auf keinen Fall einen gleichnamigen Account an!
uimport muss anstelle des Registrierens verwendet werden.
Wähle die gesicherte Account Datei aus und klicke "Importieren".
Friendica wird nun deinen Account auf dem neuen Server wiederherstellen, mit all deinen Friendica Kontakten und Gruppen.
An deine Friendica Kontakte wird außerdem eine Nachricht gesendet um sie über deine neue Adresse zu informieren.
Wenn deine Kontakte ihren Account auf einem aktuellen Server haben werden deine Kontaktdetails automatisch aktualisiert.
Neuere Diaspora Server unterstützen ebenfalls eine Umzugsbenachrichtigung.
Kontakte auf GNU Social werden archiviert, da wir ihnen keine Information über deinen Umzug zukommen lassen können.
Du solltest sie persönlich anschreiben deinen Eintrag aus ihren Kontaktlisten zu entfernen und dich neu hinzuzufügen, anschließend solltest du da gleiche mit ihren Accounts tun.
Nach dem Umzug wird dein Account auf dem alten Server nicht mehr zuverlässig funktionieren und sollte deshalb gelöscht werden.

View File

@ -517,6 +517,15 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
. "<script> var profile_uid = -1; var netargs = '" . substr($a->cmd, 10)
."/?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n";
}
} elseif ($mode === 'contacts') {
$items = conversation_add_children($items, true, $order, $uid);
$profile_owner = 0;
if (!$update) {
$live_update_div = '<div id="live-contacts"></div>' . "\r\n"
. "<script> var profile_uid = -1; var netargs = '" . substr($a->cmd, 9)
."/?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n";
}
} elseif ($mode === 'search') {
$live_update_div = '<div id="live-search"></div>' . "\r\n";
}
@ -544,7 +553,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
$page_template = get_markup_template("conversation.tpl");
if (!empty($items)) {
if ($mode === 'community') {
if (in_array($mode, ['community', 'contacts'])) {
$writable = true;
} else {
$writable = ($items[0]['uid'] == 0) && in_array($items[0]['network'], [Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN]);

View File

@ -24,6 +24,7 @@ use Friendica\Module\Tos;
use Friendica\Util\Arrays;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Temporal;
use Friendica\Util\Network;
require_once 'include/enotify.php';
require_once 'include/text.php';
@ -868,6 +869,14 @@ function admin_page_summary(App $a)
$warningtext[] = L10n::t('Friendica\'s configuration now is stored in config/local.ini.php, please copy config/local-sample.ini.php and move your config from <code>.htconfig.php</code>. See <a href="%s">the Config help page</a> for help with the transition.', $a->get_baseurl() . '/help/Config');
}
// Check server vitality
if (!admin_page_server_vital()) {
$showwarning = true;
$well_known = $a->get_baseurl() . '/.well-known/host-meta';
$warningtext[] = L10n::t('<a href="%s">%s</a> is not reachable on your system. This is a severe configuration issue that prevents server to server communication. See <a href="%s">the installation page</a> for help.',
$well_known, $well_known, $a->get_baseurl() . '/help/Install');
}
$r = q("SELECT `page-flags`, COUNT(`uid`) AS `count` FROM `user` GROUP BY `page-flags`");
$accounts = [
[L10n::t('Normal Account'), 0],
@ -2544,3 +2553,10 @@ function admin_page_features(App $a)
return $o;
}
}
function admin_page_server_vital()
{
// Fetch the host-meta to check if this really is a vital server
$serverret = Network::curl(System::baseUrl() . '/.well-known/host-meta');
return $serverret["success"];
}

View File

@ -35,7 +35,7 @@ function allfriends_content(App $a)
$uid = $a->user['uid'];
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo'], ['id' => $cid, 'uid' => local_user()]);
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo', 'uid', 'id'], ['id' => $cid, 'uid' => local_user()]);
if (!DBA::isResult($contact)) {
return;
@ -96,7 +96,7 @@ function allfriends_content(App $a)
$entries[] = $entry;
}
$tab_str = contacts_tab($a, $cid, 3);
$tab_str = contacts_tab($a, $contact, 4);
$tpl = get_markup_template('viewcontact_template.tpl');

View File

@ -38,14 +38,14 @@ function common_content(App $a)
}
if ($cmd === 'loc' && $cid) {
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo'], ['id' => $cid, 'uid' => $uid]);
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo', 'uid', 'id'], ['id' => $cid, 'uid' => $uid]);
if (DBA::isResult($contact)) {
$a->page['aside'] = "";
Profile::load($a, "", 0, Contact::getDetailsByURL($contact["url"]));
}
} else {
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo'], ['self' => true, 'uid' => $uid]);
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo', 'uid', 'id'], ['self' => true, 'uid' => $uid]);
if (DBA::isResult($contact)) {
$vcard_widget = replace_macros(get_markup_template("vcard-widget.tpl"), [
@ -137,7 +137,7 @@ function common_content(App $a)
$title = '';
$tab_str = '';
if ($cmd === 'loc' && $cid && local_user() == $uid) {
$tab_str = contacts_tab($a, $cid, 4);
$tab_str = contacts_tab($a, $contact, 4);
} else {
$title = L10n::t('Common Friends');
}

View File

@ -21,6 +21,7 @@ use Friendica\Model\Profile;
use Friendica\Network\Probe;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Core\ACL;
function contacts_init(App $a)
{
@ -39,14 +40,18 @@ function contacts_init(App $a)
$contact_id = null;
$contact = null;
if ((($a->argc == 2) && intval($a->argv[1])) || (($a->argc == 3) && intval($a->argv[1]) && ($a->argv[2] == "posts"))) {
if ((($a->argc == 2) && intval($a->argv[1])) || (($a->argc == 3) && intval($a->argv[1]) && in_array($a->argv[2], ['posts', 'conversations']))) {
$contact_id = intval($a->argv[1]);
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
if (!DBA::isResult($contact)) {
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => 0]);
}
}
if (DBA::isResult($contact)) {
if ($contact['self']) {
if (($a->argc == 3) && intval($a->argv[1]) && ($a->argv[2] == "posts")) {
if (($a->argc == 3) && intval($a->argv[1]) && in_array($a->argv[2], ['posts', 'conversations'])) {
goaway('profile/' . $contact['nick']);
} else {
goaway('profile/' . $contact['nick'] . '?tab=profile');
@ -87,7 +92,11 @@ function contacts_init(App $a)
$findpeople_widget = Widget::findPeople();
}
$groups_widget = Group::sidebarWidget('contacts', 'group', 'full', 'everyone', $contact_id);
if ($contact['uid'] != 0) {
$groups_widget = Group::sidebarWidget('contacts', 'group', 'full', 'everyone', $contact_id);
} else {
$groups_widget = null;
}
$a->page['aside'] .= replace_macros(get_markup_template("contacts-widget-sidebar.tpl"), [
'$vcard_widget' => $vcard_widget,
@ -131,16 +140,12 @@ function contacts_batch_actions(App $a)
$count_actions++;
}
if (x($_POST, 'contacts_batch_block')) {
$r = _contact_block($contact_id, $orig_record);
if ($r) {
$count_actions++;
}
_contact_block($contact_id);
$count_actions++;
}
if (x($_POST, 'contacts_batch_ignore')) {
$r = _contact_ignore($contact_id, $orig_record);
if ($r) {
$count_actions++;
}
_contact_ignore($contact_id);
$count_actions++;
}
if (x($_POST, 'contacts_batch_archive')) {
$r = _contact_archive($contact_id, $orig_record);
@ -327,26 +332,16 @@ function _contact_update_profile($contact_id)
GContact::updateFromProbe($data["url"]);
}
function _contact_block($contact_id, $orig_record)
function _contact_block($contact_id)
{
$blocked = (($orig_record['blocked']) ? 0 : 1);
$r = q("UPDATE `contact` SET `blocked` = %d WHERE `id` = %d AND `uid` = %d",
intval($blocked),
intval($contact_id),
intval(local_user())
);
return DBA::isResult($r);
$blocked = !Contact::isBlockedByUser($contact_id, local_user());
Contact::setBlockedForUser($contact_id, local_user(), $blocked);
}
function _contact_ignore($contact_id, $orig_record)
function _contact_ignore($contact_id)
{
$readonly = (($orig_record['readonly']) ? 0 : 1);
$r = q("UPDATE `contact` SET `readonly` = %d WHERE `id` = %d AND `uid` = %d",
intval($readonly),
intval($contact_id),
intval(local_user())
);
return DBA::isResult($r);
$ignored = !Contact::isIgnoredByUser($contact_id, local_user());
Contact::setIgnoredForUser($contact_id, local_user(), $ignored);
}
function _contact_archive($contact_id, $orig_record)
@ -376,7 +371,7 @@ function _contact_drop($orig_record)
Contact::remove($orig_record['id']);
}
function contacts_content(App $a)
function contacts_content(App $a, $update = 0)
{
$sort_type = 0;
$o = '';
@ -395,48 +390,46 @@ function contacts_content(App $a)
$cmd = $a->argv[2];
$orig_record = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user(), 'self' => false]);
$orig_record = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => [0, local_user()], 'self' => false]);
if (!DBA::isResult($orig_record)) {
notice(L10n::t('Could not access contact record.') . EOL);
goaway('contacts');
return; // NOTREACHED
}
if ($cmd === 'update') {
if ($cmd === 'update' && ($orig_record['uid'] != 0)) {
_contact_update($contact_id);
goaway('contacts/' . $contact_id);
// NOTREACHED
}
if ($cmd === 'updateprofile') {
if ($cmd === 'updateprofile' && ($orig_record['uid'] != 0)) {
_contact_update_profile($contact_id);
goaway('crepair/' . $contact_id);
// NOTREACHED
}
if ($cmd === 'block') {
$r = _contact_block($contact_id, $orig_record);
if ($r) {
$blocked = (($orig_record['blocked']) ? 0 : 1);
info((($blocked) ? L10n::t('Contact has been blocked') : L10n::t('Contact has been unblocked')) . EOL);
}
_contact_block($contact_id);
$blocked = Contact::isBlockedByUser($contact_id, local_user());
info(($blocked ? L10n::t('Contact has been blocked') : L10n::t('Contact has been unblocked')) . EOL);
goaway('contacts/' . $contact_id);
return; // NOTREACHED
}
if ($cmd === 'ignore') {
$r = _contact_ignore($contact_id, $orig_record);
if ($r) {
$readonly = (($orig_record['readonly']) ? 0 : 1);
info((($readonly) ? L10n::t('Contact has been ignored') : L10n::t('Contact has been unignored')) . EOL);
}
_contact_ignore($contact_id);
$ignored = Contact::isIgnoredByUser($contact_id, local_user());
info(($ignored ? L10n::t('Contact has been ignored') : L10n::t('Contact has been unignored')) . EOL);
goaway('contacts/' . $contact_id);
return; // NOTREACHED
}
if ($cmd === 'archive') {
if ($cmd === 'archive' && ($orig_record['uid'] != 0)) {
$r = _contact_archive($contact_id, $orig_record);
if ($r) {
$archived = (($orig_record['archive']) ? 0 : 1);
@ -447,7 +440,7 @@ function contacts_content(App $a)
return; // NOTREACHED
}
if ($cmd === 'drop') {
if ($cmd === 'drop' && ($orig_record['uid'] != 0)) {
// Check if we should do HTML-based delete confirmation
if (x($_REQUEST, 'confirm')) {
// <form> can't take arguments in its "action" parameter
@ -496,6 +489,9 @@ function contacts_content(App $a)
if ($cmd === 'posts') {
return contact_posts($a, $contact_id);
}
if ($cmd === 'conversations') {
return contact_conversations($a, $contact_id, $update);
}
}
$_SESSION['return_url'] = $a->query_string;
@ -511,6 +507,9 @@ function contacts_content(App $a)
'$baseurl' => System::baseUrl(true),
]);
$contact['blocked'] = Contact::isBlockedByUser($contact['id'], local_user());
$contact['readonly'] = Contact::isIgnoredByUser($contact['id'], local_user());
$dir_icon = '';
$relation_text = '';
switch ($contact['rel']) {
@ -533,6 +532,10 @@ function contacts_content(App $a)
break;
}
if ($contact['uid'] == 0) {
$relation_text = '';
}
if (!in_array($contact['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::DIASPORA])) {
$relation_text = "";
}
@ -560,7 +563,7 @@ function contacts_content(App $a)
$nettype = L10n::t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact["url"]));
// tabs
$tab_str = contacts_tab($a, $contact_id, 2);
$tab_str = contacts_tab($a, $contact, 3);
$lost_contact = (($contact['archive'] && $contact['term-date'] > NULL_DATE && $contact['term-date'] < DateTimeFormat::utcNow()) ? L10n::t('Communications lost with this contact!') : '');
@ -593,26 +596,41 @@ function contacts_content(App $a)
$follow = '';
$follow_text = '';
if (in_array($contact['network'], [Protocol::DIASPORA, Protocol::OSTATUS, Protocol::DFRN])) {
if ($contact['rel'] == Contact::FOLLOWER) {
$follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
$follow_text = L10n::t("Connect/Follow");
} elseif ($contact['rel'] == Contact::FRIEND) {
if (in_array($contact['rel'], [Contact::FRIEND, Contact::SHARING])) {
$follow = System::baseUrl(true) . "/unfollow?url=" . urlencode($contact["url"]);
$follow_text = L10n::t("Disconnect/Unfollow");
} else {
$follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
$follow_text = L10n::t("Connect/Follow");
}
}
if ($contact['uid'] == 0) {
$follow = System::baseUrl(true) . "/follow?url=" . urlencode($contact["url"]);
$follow_text = L10n::t("Connect/Follow");
}
// Load contactact related actions like hide, suggest, delete and others
$contact_actions = contact_actions($contact);
if ($contact['uid'] != 0) {
$lbl_vis1 = L10n::t('Profile Visibility');
$lbl_info1 = L10n::t('Contact Information / Notes');
$contact_settings_label = L10n::t('Contact Settings');
} else {
$lbl_vis1 = null;
$lbl_info1 = null;
$contact_settings_label = null;
}
$tpl = get_markup_template("contact_edit.tpl");
$o .= replace_macros($tpl, [
'$header' => L10n::t("Contact"),
'$tab_str' => $tab_str,
'$submit' => L10n::t('Submit'),
'$lbl_vis1' => L10n::t('Profile Visibility'),
'$lbl_vis1' => $lbl_vis1,
'$lbl_vis2' => L10n::t('Please choose the profile you would like to display to %s when viewing your profile securely.', $contact['name']),
'$lbl_info1' => L10n::t('Contact Information / Notes'),
'$lbl_info1' => $lbl_info1,
'$lbl_info2' => L10n::t('Their personal note'),
'$reason' => trim(notags($contact['reason'])),
'$infedit' => L10n::t('Edit contact notes'),
@ -669,7 +687,7 @@ function contacts_content(App $a)
'$contact_action_button' => L10n::t("Actions"),
'$contact_actions' => $contact_actions,
'$contact_status' => L10n::t("Status"),
'$contact_settings_label' => L10n::t('Contact Settings'),
'$contact_settings_label' => $contact_settings_label,
'$contact_profile_label' => L10n::t("Profile"),
]);
@ -806,6 +824,8 @@ function contacts_content(App $a)
);
if (DBA::isResult($r)) {
foreach ($r as $rr) {
$rr['blocked'] = Contact::isBlockedByUser($rr['id'], local_user());
$rr['readonly'] = Contact::isIgnoredByUser($rr['id'], local_user());
$contacts[] = _contact_detail_for_template($rr);
}
}
@ -844,27 +864,35 @@ function contacts_content(App $a)
* Available Pages are 'Status', 'Profile', 'Contacts' and 'Common Friends'
*
* @param App $a
* @param int $contact_id The ID of the contact
* @param array $contact The contact array
* @param int $active_tab 1 if tab should be marked as active
*
* @return string
*/
function contacts_tab($a, $contact_id, $active_tab)
function contacts_tab($a, $contact, $active_tab)
{
// tabs
$tabs = [
[
'label' => L10n::t('Status'),
'url' => "contacts/" . $contact_id . "/posts",
'url' => "contacts/" . $contact['id'] . "/conversations",
'sel' => (($active_tab == 1) ? 'active' : ''),
'title' => L10n::t('Status Messages and Posts'),
'title' => L10n::t('Conversations started by this contact'),
'id' => 'status-tab',
'accesskey' => 'm',
],
[
'label' => L10n::t('Profile'),
'url' => "contacts/" . $contact_id,
'label' => L10n::t('Posts and Comments'),
'url' => "contacts/" . $contact['id'] . "/posts",
'sel' => (($active_tab == 2) ? 'active' : ''),
'title' => L10n::t('Status Messages and Posts'),
'id' => 'posts-tab',
'accesskey' => 'p',
],
[
'label' => L10n::t('Profile'),
'url' => "contacts/" . $contact['id'],
'sel' => (($active_tab == 3) ? 'active' : ''),
'title' => L10n::t('Profile Details'),
'id' => 'profile-tab',
'accesskey' => 'o',
@ -872,35 +900,37 @@ function contacts_tab($a, $contact_id, $active_tab)
];
// Show this tab only if there is visible friend list
$x = GContact::countAllFriends(local_user(), $contact_id);
$x = GContact::countAllFriends(local_user(), $contact['id']);
if ($x) {
$tabs[] = ['label' => L10n::t('Contacts'),
'url' => "allfriends/" . $contact_id,
'sel' => (($active_tab == 3) ? 'active' : ''),
'url' => "allfriends/" . $contact['id'],
'sel' => (($active_tab == 4) ? 'active' : ''),
'title' => L10n::t('View all contacts'),
'id' => 'allfriends-tab',
'accesskey' => 't'];
}
// Show this tab only if there is visible common friend list
$common = GContact::countCommonFriends(local_user(), $contact_id);
$common = GContact::countCommonFriends(local_user(), $contact['id']);
if ($common) {
$tabs[] = ['label' => L10n::t('Common Friends'),
'url' => "common/loc/" . local_user() . "/" . $contact_id,
'sel' => (($active_tab == 4) ? 'active' : ''),
'url' => "common/loc/" . local_user() . "/" . $contact['id'],
'sel' => (($active_tab == 5) ? 'active' : ''),
'title' => L10n::t('View all common friends'),
'id' => 'common-loc-tab',
'accesskey' => 'd'
];
}
$tabs[] = ['label' => L10n::t('Advanced'),
'url' => 'crepair/' . $contact_id,
'sel' => (($active_tab == 5) ? 'active' : ''),
'title' => L10n::t('Advanced Contact Settings'),
'id' => 'advanced-tab',
'accesskey' => 'r'
];
if (!empty($contact['uid'])) {
$tabs[] = ['label' => L10n::t('Advanced'),
'url' => 'crepair/' . $contact['id'],
'sel' => (($active_tab == 6) ? 'active' : ''),
'title' => L10n::t('Advanced Contact Settings'),
'id' => 'advanced-tab',
'accesskey' => 'r'
];
}
$tab_tpl = get_markup_template('common_tabs.tpl');
$tab_str = replace_macros($tab_tpl, ['$tabs' => $tabs]);
@ -908,15 +938,70 @@ function contacts_tab($a, $contact_id, $active_tab)
return $tab_str;
}
function contact_posts(App $a, $contact_id)
function contact_conversations(App $a, $contact_id, $update)
{
$o = contacts_tab($a, $contact_id, 1);
$o = '';
$contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id]);
if (!$update) {
// We need the editor here to be able to reshare an item.
if (local_user()) {
$x = [
'is_owner' => true,
'allow_location' => $a->user['allow_location'],
'default_location' => $a->user['default-location'],
'nickname' => $a->user['nickname'],
'lockstate' => (is_array($a->user) && (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) || strlen($a->user['deny_cid']) || strlen($a->user['deny_gid'])) ? 'lock' : 'unlock'),
'acl' => ACL::getFullSelectorHTML($a->user, true),
'bang' => '',
'visitor' => 'block',
'profile_uid' => local_user(),
];
$o = status_editor($a, $x, 0, true);
}
}
$contact = DBA::selectFirst('contact', ['uid', 'url', 'id'], ['id' => $contact_id]);
if (!$update) {
$o .= contacts_tab($a, $contact, 1);
}
if (DBA::isResult($contact)) {
$a->page['aside'] = "";
Profile::load($a, "", 0, Contact::getDetailsByURL($contact["url"]));
$profiledata = Contact::getDetailsByURL($contact["url"]);
if (local_user()) {
if (in_array($profiledata["network"], [Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS])) {
$profiledata["remoteconnect"] = System::baseUrl()."/follow?url=".urlencode($profiledata["url"]);
}
}
Profile::load($a, "", 0, $profiledata, true);
$o .= Contact::getPostsFromUrl($contact["url"], true, $update);
}
return $o;
}
function contact_posts(App $a, $contact_id)
{
$contact = DBA::selectFirst('contact', ['uid', 'url', 'id'], ['id' => $contact_id]);
$o = contacts_tab($a, $contact, 2);
if (DBA::isResult($contact)) {
$a->page['aside'] = "";
$profiledata = Contact::getDetailsByURL($contact["url"]);
if (local_user()) {
if (in_array($profiledata["network"], [Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS])) {
$profiledata["remoteconnect"] = System::baseUrl()."/follow?url=".urlencode($profiledata["url"]);
}
}
Profile::load($a, "", 0, $profiledata, true);
$o .= Contact::getPostsFromUrl($contact["url"]);
}
@ -1032,21 +1117,23 @@ function contact_actions($contact)
'id' => 'toggle-ignore',
];
$contact_actions['archive'] = [
'label' => (intval($contact['archive']) ? L10n::t('Unarchive') : L10n::t('Archive') ),
'url' => 'contacts/' . $contact['id'] . '/archive',
'title' => L10n::t('Toggle Archive status'),
'sel' => (intval($contact['archive']) ? 'active' : ''),
'id' => 'toggle-archive',
];
if ($contact['uid'] != 0) {
$contact_actions['archive'] = [
'label' => (intval($contact['archive']) ? L10n::t('Unarchive') : L10n::t('Archive') ),
'url' => 'contacts/' . $contact['id'] . '/archive',
'title' => L10n::t('Toggle Archive status'),
'sel' => (intval($contact['archive']) ? 'active' : ''),
'id' => 'toggle-archive',
];
$contact_actions['delete'] = [
'label' => L10n::t('Delete'),
'url' => 'contacts/' . $contact['id'] . '/drop',
'title' => L10n::t('Delete contact'),
'sel' => '',
'id' => 'delete',
];
$contact_actions['delete'] = [
'label' => L10n::t('Delete'),
'url' => 'contacts/' . $contact['id'] . '/drop',
'title' => L10n::t('Delete contact'),
'sel' => '',
'id' => 'delete',
];
}
return $contact_actions;
}

View File

@ -103,7 +103,7 @@ function crepair_content(App $a)
$cid = (($a->argc > 1) ? intval($a->argv[1]) : 0);
$contact = null;
$contact = null;
if ($cid) {
$contact = DBA::selectFirst('contact', [], ['id' => $cid, 'uid' => local_user()]);
}
@ -135,7 +135,7 @@ function crepair_content(App $a)
$update_profile = in_array($contact['network'], [Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS]);
$tab_str = contacts_tab($a, $contact['id'], 5);
$tab_str = contacts_tab($a, $contact, 5);
$tpl = get_markup_template('crepair.tpl');
$o = replace_macros($tpl, [

View File

@ -85,6 +85,7 @@ function dirfind_content(App $a, $prefix = "") {
$contact = Contact::getDetailsByURL($user_data["url"], local_user());
$objresult->cid = $contact["cid"];
$objresult->pcid = $contact["zid"];
$j->results[] = $objresult;
@ -163,6 +164,7 @@ function dirfind_content(App $a, $prefix = "") {
$objresult = new stdClass();
$objresult->cid = $result["cid"];
$objresult->pcid = $result["zid"];
$objresult->name = $result["name"];
$objresult->addr = $result["addr"];
$objresult->url = $result["url"];
@ -217,10 +219,16 @@ function dirfind_content(App $a, $prefix = "") {
} else {
$connlnk = System::baseUrl().'/follow/?url='.(!empty($jj->connect) ? $jj->connect : $jj->url);
$conntxt = L10n::t('Connect');
$photo_menu = [
'profile' => [L10n::t("View Profile"), Contact::magicLink($jj->url)],
'follow' => [L10n::t("Connect/Follow"), $connlnk]
];
$contact = DBA::selectFirst('contact', [], ['id' => $jj->pcid]);
if (DBA::isResult($contact)) {
$photo_menu = Contact::photoMenu($contact);
} else {
$photo_menu = [];
}
$photo_menu['profile'] = [L10n::t("View Profile"), Contact::magicLink($jj->url)];
$photo_menu['follow'] = [L10n::t("Connect/Follow"), $connlnk];
}
$jj->photo = str_replace("http:///photo/", get_server()."/photo/", $jj->photo);

View File

@ -542,16 +542,14 @@ function events_content(App $a) {
// Remove an event from the calendar and its related items
if ($mode === 'drop' && $event_id) {
$del = 0;
$ev = Event::getListById(local_user(), $event_id);
// Delete only real events (no birthdays)
if (DBA::isResult($ev) && $ev[0]['type'] == 'event') {
$del = Item::deleteForUser(['id' => $ev[0]['itemid']], local_user());
Item::deleteForUser(['id' => $ev[0]['itemid']], local_user());
}
if ($del == 0) {
if (Item::exists(['id' => $ev[0]['itemid']])) {
notice(L10n::t('Failed to remove event') . EOL);
} else {
info(L10n::t('Event removed') . EOL);

View File

@ -84,12 +84,12 @@ function group_content(App $a) {
return;
}
// Switch to text mode interface if we have more than 'n' contacts or group members
// With no group number provided we jump to the unassigned contacts as a starting point
if ($a->argc == 1) {
goaway(System::baseUrl() . '/contacts');
goaway('group/none');
}
// Switch to text mode interface if we have more than 'n' contacts or group members
$switchtotext = PConfig::get(local_user(), 'system', 'groupedit_image_limit');
if (is_null($switchtotext)) {
$switchtotext = Config::get('system', 'groupedit_image_limit', 400);

View File

@ -26,8 +26,6 @@ function install_init(App $a) {
$a->setConfigValue('system', 'value', '../install');
$a->theme['stylesheet'] = System::baseUrl()."/view/install/style.css";
Install::setInstallMode();
global $install_wizard_pass;
if (x($_POST, 'pass')) {
$install_wizard_pass = intval($_POST['pass']);

View File

@ -11,39 +11,21 @@ use Friendica\Core\UserImport;
function uimport_post(App $a)
{
switch (Config::get('config', 'register_policy')) {
case REGISTER_OPEN:
$blocked = 0;
$verified = 1;
break;
case REGISTER_APPROVE:
$blocked = 1;
$verified = 0;
break;
default:
case REGISTER_CLOSED:
if ((!x($_SESSION, 'authenticated') && (!x($_SESSION, 'administrator')))) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
$blocked = 1;
$verified = 0;
break;
if ((Config::get('config', 'register_policy') != REGISTER_OPEN) && !is_site_admin()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
if (x($_FILES, 'accountfile')) {
/// @TODO Pass $blocked / $verified, send email to admin on REGISTER_APPROVE
if (!empty($_FILES['accountfile'])) {
UserImport::importAccount($a, $_FILES['accountfile']);
return;
}
}
function uimport_content(App $a) {
if ((!local_user()) && (intval(Config::get('config', 'register_policy')) === REGISTER_CLOSED)) {
notice("Permission denied." . EOL);
function uimport_content(App $a)
{
if ((Config::get('config', 'register_policy') != REGISTER_OPEN) && !is_site_admin()) {
notice(L10n::t('User imports on closed servers can only be done by an administrator.') . EOL);
return;
}

View File

@ -174,40 +174,7 @@ class App
$this->callstack['rendering'] = [];
$this->callstack['parser'] = [];
// The order of the following calls is important to ensure proper initialization
$this->loadConfigFiles();
$this->loadDatabase();
$this->determineMode();
$this->determineUrlPath();
Config::load();
if ($this->mode & self::MODE_DBAVAILABLE) {
Core\Addon::loadHooks();
$this->loadAddonConfig();
}
$this->loadDefaultTimezone();
$this->page = [
'aside' => '',
'bottom' => '',
'content' => '',
'end' => '',
'footer' => '',
'htmlhead' => '',
'nav' => '',
'page_title' => '',
'right_aside' => '',
'template' => '',
'title' => ''
];
$this->process_id = System::processID('log');
$this->reload();
set_time_limit(0);
@ -314,6 +281,47 @@ class App
$this->register_template_engine('Friendica\Render\FriendicaSmartyEngine');
}
/**
* Reloads the whole app instance
*/
public function reload()
{
// The order of the following calls is important to ensure proper initialization
$this->loadConfigFiles();
$this->loadDatabase();
$this->determineMode();
$this->determineUrlPath();
Config::load();
if ($this->mode & self::MODE_DBAVAILABLE) {
Core\Addon::loadHooks();
$this->loadAddonConfig();
}
$this->loadDefaultTimezone();
$this->page = [
'aside' => '',
'bottom' => '',
'content' => '',
'end' => '',
'footer' => '',
'htmlhead' => '',
'nav' => '',
'page_title' => '',
'right_aside' => '',
'template' => '',
'title' => ''
];
$this->process_id = System::processID('log');
}
/**
* Load the configuration files
*

View File

@ -5,6 +5,7 @@
*/
namespace Friendica\Content;
use Friendica\Core\Protocol;
use Friendica\Content\Feature;
use Friendica\Core\L10n;
use Friendica\Core\System;
@ -36,25 +37,29 @@ class ForumManager
*/
public static function getList($uid, $lastitem, $showhidden = true, $showprivate = false)
{
$forumlist = [];
$order = (($showhidden) ? '' : ' AND NOT `hidden` ');
$order .= (($lastitem) ? ' ORDER BY `last-item` DESC ' : ' ORDER BY `name` ASC ');
$select = '`forum` ';
if ($showprivate) {
$select = '(`forum` OR `prv`)';
if ($lastitem) {
$params = ['order' => ['last-item' => true]];
} else {
$params = ['order' => ['name']];
}
$contacts = DBA::p(
"SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro`, `contact`.`thumb`
FROM `contact`
WHERE `network`= 'dfrn' AND $select AND `uid` = ?
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` > `failure_update`
$order ",
$uid
);
$condition_str = "`network` = ? AND `uid` = ? AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `success_update` > `failure_update` AND ";
if ($showprivate) {
$condition_str .= '(`forum` OR `prv`)';
} else {
$condition_str .= '`forum`';
}
if (!$showhidden) {
$condition_str .= ' AND NOT `hidden`';
}
$forumlist = [];
$fields = ['id', 'url', 'name', 'micro', 'thumb'];
$condition = [$condition_str, Protocol::DFRN, $uid];
$contacts = DBA::select('contact', $fields, $condition, $params);
if (!$contacts) {
return($forumlist);
}

View File

@ -49,7 +49,7 @@ class Widget
if (Config::get('system', 'invitation_only')) {
$x = PConfig::get(local_user(), 'system', 'invites_remaining');
if ($x || is_site_admin()) {
$a->page['aside'] .= '<div class="side-link" id="side-invite-remain">'
$a->page['aside'] .= '<div class="side-link widget" id="side-invite-remain">'
. L10n::tt('%d invitation available', '%d invitations available', $x)
. '</div>';
}

View File

@ -35,24 +35,24 @@ Options
-a All setup checks are required (except .htaccess)
-f|--file <config> prepared config file (e.g. "config/local.ini.php" itself) which will override every other config option - except the environment variables)
-s|--savedb Save the DB credentials to the file (if environment variables is used)
-h|--dbhost <host> The host of the mysql database (env MYSQL_HOST)
-p|--dbport <port> The port of the mysql database (env MYSQL_PORT)
-d|--dbdata <database> The name of the mysql database (env MYSQL_DATABASE)
-U|--dbuser <username> The username of the mysql database login (env MYSQL_USER or MYSQL_USERNAME)
-P|--dbpass <password> The password of the mysql database login (env MYSQL_PASSWORD)
-H|--dbhost <host> The host of the mysql/mariadb database (env MYSQL_HOST)
-p|--dbport <port> The port of the mysql/mariadb database (env MYSQL_PORT)
-d|--dbdata <database> The name of the mysql/mariadb database (env MYSQL_DATABASE)
-U|--dbuser <username> The username of the mysql/mariadb database login (env MYSQL_USER or MYSQL_USERNAME)
-P|--dbpass <password> The password of the mysql/mariadb database login (env MYSQL_PASSWORD)
-b|--phppath <path> The path of the PHP binary (env FRIENDICA_PHP_PATH)
-A|--admin <mail> The admin email address of Friendica (env FRIENDICA_ADMIN_MAIL)
-T|--tz <timezone> The timezone of Friendica (env FRIENDICA_TZ)
-L|--lang <language> The language of Friendica (env FRIENDICA_LANG)
Environment variables
MYSQL_HOST The host of the mysql database (mandatory if mysql and environment is used)
MYSQL_PORT The port of the mysql database
MYSQL_USERNAME|MYSQL_USER The username of the mysql database login (MYSQL_USERNAME is for mysql, MYSQL_USER for mariadb)
MYSQL_PASSWORD The password of the mysql database login
MYSQL_DATABASE The name of the mysql database
MYSQL_HOST The host of the mysql/mariadb database (mandatory if mysql and environment is used)
MYSQL_PORT The port of the mysql/mariadb database
MYSQL_USERNAME|MYSQL_USER The username of the mysql/mariadb database login (MYSQL_USERNAME is for mysql, MYSQL_USER for mariadb)
MYSQL_PASSWORD The password of the mysql/mariadb database login
MYSQL_DATABASE The name of the mysql/mariadb database
FRIENDICA_PHP_PATH The path of the PHP binary
FRIENDICA_ADMIN_MAIL The admin email address of Friendica
FRIENDICA_ADMIN_MAIL The admin email address of Friendica (this email will be used for admin access)
FRIENDICA_TZ The timezone of Friendica
FRIENDICA_LANG The langauge of Friendica
@ -64,8 +64,7 @@ Examples
Installs Friendica with environment variables and saves them to the 'config/local.ini.php' file
bin/console autoinstall -h localhost -p 3365 -U user -P passwort1234 -d friendica
Installs Friendica with a local mysql database with credentials
Installs Friendica with a local mysql database with credentials
HELP;
}
@ -74,21 +73,20 @@ HELP;
// Initialise the app
$this->out("Initializing setup...\n");
$a = BaseObject::getApp();
// if a config file is set,
$config_file = $this->getOption(['f', 'file']);
if (!empty($config_file)) {
if ($config_file != 'config/local.ini.php') {
if ($config_file != 'config' . DIRECTORY_SEPARATOR . 'local.ini.php') {
// Copy config file
$this->out("Copying config file...\n");
if (!copy($config_file, 'config/local.ini.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to 'config/local.ini.php' manually.\n");
if (!copy($a->basepath . DIRECTORY_SEPARATOR . $config_file, $a->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '$a->basepath" . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "local.ini.php' manually.\n");
}
}
// load the app after copying the file
$a = BaseObject::getApp();
$db_host = $a->getConfigValue('database', 'hostname');
$db_user = $a->getConfigValue('database', 'username');
$db_pass = $a->getConfigValue('database', 'password');
@ -97,12 +95,9 @@ HELP;
// Creating config file
$this->out("Creating config file...\n");
// load the app first (for the template engine)
$a = BaseObject::getApp();
$save_db = $this->getOption(['s', 'savedb'], false);
$db_host = $this->getOption(['h', 'dbhost'], ($save_db) ? getenv('MYSQL_HOST') : '');
$db_host = $this->getOption(['H', 'dbhost'], ($save_db) ? getenv('MYSQL_HOST') : '');
$db_port = $this->getOption(['p', 'dbport'], ($save_db) ? getenv('MYSQL_PORT') : null);
$db_data = $this->getOption(['d', 'dbdata'], ($save_db) ? getenv('MYSQL_DATABASE') : '');
$db_user = $this->getOption(['U', 'dbuser'], ($save_db) ? getenv('MYSQL_USER') . getenv('MYSQL_USERNAME') : '');
@ -112,12 +107,9 @@ HELP;
$tz = $this->getOption(['T', 'tz'], (!empty('FRIENDICA_TZ')) ? getenv('FRIENDICA_TZ') : '');
$lang = $this->getOption(['L', 'lang'], (!empty('FRIENDICA_LANG')) ? getenv('FRIENDICA_LANG') : '');
// creating config file
$this->out("Creating config file...\n");
Install::createConfig(
$php_path,
$db_host,
((!empty($db_port)) ? $db_host . ':' . $db_port : $db_host),
$db_user,
$db_pass,
$db_data,

View File

@ -84,11 +84,12 @@ class Install extends BaseObject
'$adminmail' => $adminmail,
]);
$result = file_put_contents('config/local.ini.php', $txt);
if (!$result) {
self::getApp()->data['txt'] = $txt;
}
$app = self::getApp();
$result = file_put_contents($app->basepath . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'local.ini.php', $txt);
if (!$result) {
$app->data['txt'] = $txt;
}
}
/**

View File

@ -345,8 +345,20 @@ class NotificationsManager extends BaseObject
case ACTIVITY_FRIEND:
if (!isset($it['object'])) {
logger('Incomplete data: ' . json_encode($it) . ' - ' . System::callstack(20), LOGGER_DEBUG);
$notif = [
'label' => 'friend',
'link' => $default_item_link,
'image' => $default_item_image,
'url' => $default_item_url,
'text' => $default_item_text,
'when' => $default_item_when,
'ago' => $default_item_ago,
'seen' => $it['seen']
];
break;
}
/// @todo Check if this part here is used at all
logger('Complete data: ' . json_encode($it) . ' - ' . System::callstack(20), LOGGER_DEBUG);
$xmlhead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">";
$obj = XML::parseString($xmlhead . $it['object']);
@ -645,6 +657,10 @@ class NotificationsManager extends BaseObject
} else {
$it = $this->getMissingIntroData($it);
if (empty($it['url'])) {
continue;
}
// Don't show these data until you are connected. Diaspora is doing the same.
if ($it['gnetwork'] === Protocol::DIASPORA) {
$it['glocation'] = "";
@ -693,22 +709,22 @@ class NotificationsManager extends BaseObject
{
// 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'] == "") {
if (empty($arr['gnetwork']) && !empty($arr['network'])) {
$arr['gnetwork'] = $arr['network'];
}
if ($arr['gaddr'] == "") {
if (empty($arr['gaddr']) && !empty($arr['addr'])) {
$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'] == "") {
if (empty($arr['gnetwork']) || empty($arr['gaddr'])) {
$ret = Contact::getDetailsByURL($arr['url']);
if ($arr['gnetwork'] == "" && $ret['network'] != "") {
if (empty($arr['gnetwork']) && !empty($ret['network'])) {
$arr['gnetwork'] = $ret['network'];
}
if ($arr['gaddr'] == "" && $ret['addr'] != "") {
if (empty($arr['gaddr']) && !empty($ret['addr'])) {
$arr['gaddr'] = $ret['addr'];
}
}

View File

@ -94,6 +94,210 @@ class Contact extends BaseObject
* @}
*/
/**
* @brief Returns the contact id for the user and the public contact id for a given contact id
*
* @param int $cid Either public contact id or user's contact id
* @param int $uid User ID
*
* @return array with public and user's contact id
*/
private static function getPublicAndUserContacID($cid, $uid)
{
if (empty($uid) || empty($cid)) {
return [];
}
$contact = DBA::selectFirst('contact', ['id', 'uid', 'url'], ['id' => $cid]);
if (!DBA::isResult($contact)) {
return [];
}
// We quit when the user id don't match the user id of the provided contact
if (($contact['uid'] != $uid) && ($contact['uid'] != 0)) {
return [];
}
if ($contact['uid'] != 0) {
$pcid = Contact::getIdForURL($contact['url'], 0, true, ['url' => $contact['url']]);
if (empty($pcid)) {
return [];
}
$ucid = $contact['id'];
} else {
$pcid = $contact['id'];
$ucid = Contact::getIdForURL($contact['url'], $uid, true);
}
return ['public' => $pcid, 'user' => $ucid];
}
/**
* @brief Block contact id for user id
*
* @param int $cid Either public contact id or user's contact id
* @param int $uid User ID
* @param boolean $blocked Is the contact blocked or unblocked?
*/
public static function setBlockedForUser($cid, $uid, $blocked)
{
$cdata = self::getPublicAndUserContacID($cid, $uid);
if (empty($cdata)) {
return;
}
if ($cdata['user'] != 0) {
DBA::update('contact', ['blocked' => $blocked], ['id' => $cdata['user'], 'pending' => false]);
}
DBA::update('user-contact', ['blocked' => $blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
}
/**
* @brief Returns "block" state for contact id and user id
*
* @param int $cid Either public contact id or user's contact id
* @param int $uid User ID
*
* @return boolean is the contact id blocked for the given user?
*/
public static function isBlockedByUser($cid, $uid)
{
$cdata = self::getPublicAndUserContacID($cid, $uid);
if (empty($cdata)) {
return;
}
$public_blocked = false;
if (!empty($cdata['public'])) {
$public_contact = DBA::selectFirst('user-contact', ['blocked'], ['cid' => $cdata['public'], 'uid' => $uid]);
if (DBA::isResult($public_contact)) {
$public_blocked = $public_contact['blocked'];
}
}
$user_blocked = $public_blocked;
if (!empty($cdata['user'])) {
$user_contact = DBA::selectFirst('contact', ['blocked'], ['id' => $cdata['user'], 'pending' => false]);
if (DBA::isResult($user_contact)) {
$user_blocked = $user_contact['blocked'];
}
}
if ($user_blocked != $public_blocked) {
DBA::update('user-contact', ['blocked' => $user_blocked], ['cid' => $cdata['public'], 'uid' => $uid], true);
}
return $user_blocked;
}
/**
* @brief Ignore contact id for user id
*
* @param int $cid Either public contact id or user's contact id
* @param int $uid User ID
* @param boolean $ignored Is the contact ignored or unignored?
*/
public static function setIgnoredForUser($cid, $uid, $ignored)
{
$cdata = self::getPublicAndUserContacID($cid, $uid);
if (empty($cdata)) {
return;
}
if ($cdata['user'] != 0) {
DBA::update('contact', ['readonly' => $ignored], ['id' => $cdata['user'], 'pending' => false]);
}
DBA::update('user-contact', ['ignored' => $ignored], ['cid' => $cdata['public'], 'uid' => $uid], true);
}
/**
* @brief Returns "ignore" state for contact id and user id
*
* @param int $cid Either public contact id or user's contact id
* @param int $uid User ID
*
* @return boolean is the contact id ignored for the given user?
*/
public static function isIgnoredByUser($cid, $uid)
{
$cdata = self::getPublicAndUserContacID($cid, $uid);
if (empty($cdata)) {
return;
}
$public_ignored = false;
if (!empty($cdata['public'])) {
$public_contact = DBA::selectFirst('user-contact', ['ignored'], ['cid' => $cdata['public'], 'uid' => $uid]);
if (DBA::isResult($public_contact)) {
$public_ignored = $public_contact['ignored'];
}
}
$user_ignored = $public_ignored;
if (!empty($cdata['user'])) {
$user_contact = DBA::selectFirst('contact', ['readonly'], ['id' => $cdata['user'], 'pending' => false]);
if (DBA::isResult($user_contact)) {
$user_ignored = $user_contact['readonly'];
}
}
if ($user_ignored != $public_ignored) {
DBA::update('user-contact', ['ignored' => $user_ignored], ['cid' => $cdata['public'], 'uid' => $uid], true);
}
return $user_ignored;
}
/**
* @brief Set "collapsed" for contact id and user id
*
* @param int $cid Either public contact id or user's contact id
* @param int $uid User ID
* @param boolean $collapsed are the contact's posts collapsed or uncollapsed?
*/
public static function setCollapsedForUser($cid, $uid, $collapsed)
{
$cdata = self::getPublicAndUserContacID($cid, $uid);
if (empty($cdata)) {
return;
}
DBA::update('user-contact', ['collapsed' => $collapsed], ['cid' => $cdata['public'], 'uid' => $uid], true);
}
/**
* @brief Returns "collapsed" state for contact id and user id
*
* @param int $cid Either public contact id or user's contact id
* @param int $uid User ID
*
* @return boolean is the contact id blocked for the given user?
*/
public static function isCollapsedByUser($cid, $uid)
{
$cdata = self::getPublicAndUserContacID($cid, $uid);
if (empty($cdata)) {
return;
}
$collapsed = false;
if (!empty($cdata['public'])) {
$public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $cdata['public'], 'uid' => $uid]);
if (DBA::isResult($public_contact)) {
$collapsed = $public_contact['collapsed'];
}
}
return $collapsed;
}
/**
* @brief Returns a list of contacts belonging in a group
*
@ -679,15 +883,6 @@ class Contact extends BaseObject
$contact_own = DBA::selectFirst('contact', [], ['nurl' => $contact['nurl'], 'network' => $contact['network'], 'uid' => $uid]);
if (DBA::isResult($contact_own)) {
return self::photoMenu($contact_own, $uid);
} else {
$profile_link = self::magicLink($contact['url']);
$connlnk = 'follow/?url=' . $contact['url'];
$menu = [
'profile' => [L10n::t('View Profile'), $profile_link, true],
'follow' => [L10n::t('Connect/Follow'), $connlnk, true]
];
return $menu;
}
}
@ -719,7 +914,7 @@ class Contact extends BaseObject
$contact_url = System::baseUrl() . '/contacts/' . $contact['id'];
$posts_link = System::baseUrl() . '/contacts/' . $contact['id'] . '/posts';
$posts_link = System::baseUrl() . '/contacts/' . $contact['id'] . '/conversations';
if (!$contact['self']) {
$contact_drop_link = System::baseUrl() . '/contacts/' . $contact['id'] . '/drop?confirm=1';
@ -729,16 +924,26 @@ class Contact extends BaseObject
* Menu array:
* "name" => [ "Label", "link", (bool)Should the link opened in a new tab? ]
*/
$menu = [
'status' => [L10n::t("View Status") , $status_link , true],
'profile' => [L10n::t("View Profile") , $profile_link , true],
'photos' => [L10n::t("View Photos") , $photos_link , true],
'network' => [L10n::t("Network Posts"), $posts_link , false],
'edit' => [L10n::t("View Contact") , $contact_url , false],
'drop' => [L10n::t("Drop Contact") , $contact_drop_link, false],
'pm' => [L10n::t("Send PM") , $pm_url , false],
'poke' => [L10n::t("Poke") , $poke_link , false],
];
if (empty($contact['uid'])) {
$connlnk = 'follow/?url=' . $contact['url'];
$menu = [
'profile' => [L10n::t('View Profile'), $profile_link, true],
'network' => [L10n::t('Network Posts'), $posts_link, false],
'edit' => [L10n::t('View Contact'), $contact_url, false],
'follow' => [L10n::t('Connect/Follow'), $connlnk, true],
];
} else {
$menu = [
'status' => [L10n::t('View Status'), $status_link, true],
'profile' => [L10n::t('View Profile'), $profile_link, true],
'photos' => [L10n::t('View Photos'), $photos_link, true],
'network' => [L10n::t('Network Posts'), $posts_link, false],
'edit' => [L10n::t('View Contact'), $contact_url, false],
'drop' => [L10n::t('Drop Contact'), $contact_drop_link, false],
'pm' => [L10n::t('Send PM'), $pm_url, false],
'poke' => [L10n::t('Poke'), $poke_link, false],
];
}
$args = ['contact' => $contact, 'menu' => &$menu];
@ -1096,7 +1301,7 @@ class Contact extends BaseObject
*
* @return string posts in HTML
*/
public static function getPostsFromUrl($contact_url)
public static function getPostsFromUrl($contact_url, $thread_mode = false, $update = 0)
{
$a = self::getApp();
@ -1123,17 +1328,34 @@ class Contact extends BaseObject
$contact = ($r[0]["contact-type"] == self::ACCOUNT_TYPE_COMMUNITY ? 'owner-id' : 'author-id');
$condition = ["`$contact` = ? AND `gravity` IN (?, ?) AND " . $sql,
$author_id, GRAVITY_PARENT, GRAVITY_COMMENT, local_user()];
if ($thread_mode) {
$condition = ["`$contact` = ? AND `gravity` = ? AND " . $sql,
$author_id, GRAVITY_PARENT, local_user()];
} else {
$condition = ["`$contact` = ? AND `gravity` IN (?, ?) AND " . $sql,
$author_id, GRAVITY_PARENT, GRAVITY_COMMENT, local_user()];
}
$params = ['order' => ['created' => true],
'limit' => [$a->pager['start'], $a->pager['itemspage']]];
$r = Item::selectForUser(local_user(), [], $condition, $params);
$items = Item::inArray($r);
if ($thread_mode) {
$r = Item::selectThreadForUser(local_user(), ['uri'], $condition, $params);
$o = conversation($a, $items, 'contact-posts', false);
$items = Item::inArray($r);
$o .= alt_pager($a, count($items));
$o = conversation($a, $items, 'contacts', $update);
} else {
$r = Item::selectForUser(local_user(), [], $condition, $params);
$items = Item::inArray($r);
$o = conversation($a, $items, 'contact-posts', false);
}
if (!$update) {
$o .= alt_pager($a, count($items));
}
return $o;
}

View File

@ -584,7 +584,13 @@ class Item extends BaseObject
} else {
$master_table = "`item`";
}
return "$master_table.`visible` AND NOT $master_table.`deleted` AND NOT $master_table.`moderated` AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`) ";
return sprintf("$master_table.`visible` AND NOT $master_table.`deleted` AND NOT $master_table.`moderated`
AND (`user-item`.`hidden` IS NULL OR NOT `user-item`.`hidden`)
AND (`user-author`.`blocked` IS NULL OR NOT `user-author`.`blocked`)
AND (`user-author`.`ignored` IS NULL OR NOT `user-author`.`ignored` OR `item`.`gravity` != %d)
AND (`user-owner`.`blocked` IS NULL OR NOT `user-owner`.`blocked`)
AND (`user-owner`.`ignored` IS NULL OR NOT `user-owner`.`ignored` OR `item`.`gravity` != %d) ",
GRAVITY_PARENT, GRAVITY_PARENT);
}
/**
@ -615,8 +621,10 @@ class Item extends BaseObject
OR `contact`.`self` OR `item`.`gravity` != %d OR `contact`.`uid` = 0)
STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = $master_table.`author-id` AND NOT `author`.`blocked`
STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = $master_table.`owner-id` AND NOT `owner`.`blocked`
LEFT JOIN `user-item` ON `user-item`.`iid` = $master_table_key AND `user-item`.`uid` = %d",
Contact::SHARING, Contact::FRIEND, GRAVITY_PARENT, intval($uid));
LEFT JOIN `user-item` ON `user-item`.`iid` = $master_table_key AND `user-item`.`uid` = %d
LEFT JOIN `user-contact` AS `user-author` ON `user-author`.`cid` = $master_table.`author-id` AND `user-author`.`uid` = %d
LEFT JOIN `user-contact` AS `user-owner` ON `user-owner`.`cid` = $master_table.`owner-id` AND `user-owner`.`uid` = %d",
Contact::SHARING, Contact::FRIEND, GRAVITY_PARENT, intval($uid), intval($uid), intval($uid));
} else {
if (strpos($sql_commands, "`contact`.") !== false) {
$joins .= "LEFT JOIN `contact` ON `contact`.`id` = $master_table.`contact-id`";

View File

@ -730,13 +730,16 @@ class User
DBA::insert('userd', ['username' => $user['nickname']]);
// The user and related data will be deleted in "cron_expire_and_remove_users" (cronjobs.php)
DBA::update('user', ['account_removed' => true, 'account_expires_on' => DateTimeFormat::utcNow()], ['uid' => $uid]);
DBA::update('user', ['account_removed' => true, 'account_expires_on' => DateTimeFormat::utc($t . " + 7 day")], ['uid' => $uid]);
Worker::add(PRIORITY_HIGH, "Notifier", "removeme", $uid);
// Send an update to the directory
$self = DBA::selectFirst('contact', ['url'], ['uid' => $uid, 'self' => true]);
Worker::add(PRIORITY_LOW, "Directory", $self['url']);
// Remove the user relevant data
Worker::add(PRIORITY_LOW, "RemoveUser", $uid);
if ($uid == local_user()) {
unset($_SESSION['authenticated']);
unset($_SESSION['uid']);

View File

@ -45,7 +45,7 @@ class Proxy extends BaseModule
*
* Question: Do we really need these three methods?
*/
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
header('HTTP/1.1 304 Not Modified');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']);

View File

@ -934,9 +934,10 @@ class Probe
$prof_data = [];
if (empty($data["addr"])) {
if (empty($data["addr"]) || empty($data["nick"])) {
$probe_data = self::uri($profile_link);
$data["addr"] = $probe_data["addr"];
$data["addr"] = defaults($data, "addr", $probe_data["addr"]);
$data["nick"] = defaults($data, "nick", $probe_data["nick"]);
}
$prof_data["addr"] = $data["addr"];
@ -1604,7 +1605,8 @@ class Probe
$user = DBA::selectFirst('user', ['prvkey'], ['uid' => $uid]);
$condition = ["`uid` = ? AND `server` != ''", $uid];
$mailacct = DBA::selectFirst('mailacct', ['pass', 'user'], $condition);
$fields = ['pass', 'user', 'server', 'port', 'ssltype', 'mailbox'];
$mailacct = DBA::selectFirst('mailacct', $fields, $condition);
if (!DBA::isResult($user) || !DBA::isResult($mailacct)) {
return false;

View File

@ -71,6 +71,10 @@ class Thread extends BaseObject
$this->profile_owner = 0;
$this->writable = $writable;
break;
case 'contacts':
$this->profile_owner = 0;
$this->writable = $writable;
break;
default:
logger('[ERROR] Conversation::setMode : Unhandled mode ('. $mode .').', LOGGER_DEBUG);
return false;

View File

@ -1618,6 +1618,10 @@ class DFRN
}
}
if (empty($author['avatar'])) {
logger('Empty author: ' . $xml);
}
if (DBA::isResult($contact_old) && !$onlyfetch) {
logger("Check if contact details for contact " . $contact_old["id"] . " (" . $contact_old["nick"] . ") have to be updated.", LOGGER_DEBUG);
@ -1747,6 +1751,10 @@ class DFRN
// Update check for this field has to be done differently
$datefields = ["name-date", "uri-date"];
foreach ($datefields as $field) {
// The date fields arrives as '2018-07-17T10:44:45Z' - the database return '2018-07-17 10:44:45'
// The fields have to be in the same format to be comparable, since strtotime does add timezones.
$contact[$field] = DateTimeFormat::utc($contact[$field]);
if (strtotime($contact[$field]) > strtotime($contact_old[$field])) {
logger("Difference for contact " . $contact["id"] . " in field '" . $field . "'. New value: '" . $contact[$field] . "', old value '" . $contact_old[$field] . "'", LOGGER_DEBUG);
$update = true;
@ -2441,7 +2449,7 @@ class DFRN
}
// Fetch the owner
$owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true);
$owner = self::fetchauthor($xpath, $entry, $importer, "dfrn:owner", true, $xml);
$owner_unknown = (isset($owner["contact-unknown"]) && $owner["contact-unknown"]);
@ -2451,7 +2459,7 @@ class DFRN
$item["owner-id"] = Contact::getIdForURL($owner["link"], 0);
// fetch the author
$author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true);
$author = self::fetchauthor($xpath, $entry, $importer, "atom:author", true, $xml);
$item["author-name"] = $author["name"];
$item["author-link"] = $author["link"];

View File

@ -561,12 +561,12 @@ class Network
public static function isUrlBlocked($url)
{
$host = @parse_url($url, PHP_URL_HOST);
if (! $host) {
return true;
if (!$host) {
return false;
}
$domain_blocklist = Config::get('system', 'blocklist', []);
if (! $domain_blocklist) {
if (!$domain_blocklist) {
return false;
}

View File

@ -120,6 +120,12 @@ class CronJobs
// delete user records for recently removed accounts
$users = DBA::select('user', ['uid'], ["`account_removed` AND `account_expires_on` < UTC_TIMESTAMP() - INTERVAL 3 DAY"]);
while ($user = DBA::fetch($users)) {
// Delete the contacts of this user
$self = DBA::selectFirst('contact', ['nurl'], ['self' => true, 'uid' => $user['uid']]);
if (DBA::isResult($self)) {
DBA::delete('contact', ['nurl' => $self['nurl'], 'self' => false]);
}
DBA::delete('user', ['uid' => $user['uid']]);
}
}

25
src/Worker/RemoveUser.php Normal file
View File

@ -0,0 +1,25 @@
<?php
/**
* @file src/Worker/RemoveUser.php
* @brief Removes orphaned data from deleted users
*/
namespace Friendica\Worker;
use Friendica\Database\DBA;
use Friendica\Model\Item;
require_once 'include/dba.php';
class RemoveUser {
public static function execute($uid)
{
// Only delete if the user is archived
$condition = ['account_removed' => true, 'uid' => $uid];
if (!DBA::exists('user', $condition)) {
return;
}
// Now we delete all user items
Item::delete(['uid' => $uid], PRIORITY_LOW);
}
}

View File

@ -0,0 +1,333 @@
<?php
namespace Friendica\Test\src\Core\Console;
use org\bovigo\vfs\vfsStream;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @requires PHP 7.0
*/
class AutomaticInstallationConsoleTest extends ConsoleTest
{
private $db_host;
private $db_port;
private $db_data;
private $db_user;
private $db_pass;
public function setUp()
{
parent::setUp();
if ($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php')) {
$this->root->getChild('config')
->removeChild('local.ini.php');
}
$this->db_host = getenv('MYSQL_HOST');
$this->db_port = (!empty(getenv('MYSQL_PORT'))) ? getenv('MYSQL_PORT') : null;
$this->db_data = getenv('MYSQL_DATABASE');
$this->db_user = getenv('MYSQL_USERNAME') . getenv('MYSQL_USER');
$this->db_pass = getenv('MYSQL_PASSWORD');
}
private function assertConfig($family, $key, $value)
{
$config = $this->execute(['config', $family, $key]);
$this->assertEquals($family . "." . $key . " => " . $value . "\n", $config);
}
private function assertFinished($txt, $withconfig = false, $copyfile = false)
{
$cfg = '';
if ($withconfig) {
$cfg = <<<CFG
Creating config file...
CFG;
}
if ($copyfile) {
$cfg = <<<CFG
Copying config file...
CFG;
}
$finished = <<<FIN
Initializing setup...{$cfg}
Complete!
Checking basic setup...
NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.
Complete!
Checking database...
Complete!
Inserting data into database...
Complete!
Installing theme
Complete
Installation is finished
FIN;
$this->assertEquals($finished, $txt);
}
private function assertStuckDB($txt)
{
$finished = <<<FIN
Initializing setup...
Creating config file...
Complete!
Checking basic setup...
NOTICE: Not checking .htaccess/URL-Rewrite during CLI installation.
Complete!
Checking database...
[Error] --------
MySQL Connection: Failed, please check your MySQL settings and credentials.
FIN;
$this->assertEquals($finished, $txt);
}
/**
* @medium
*/
public function testWithConfig()
{
$config = <<<CONF
<?php return <<<INI
[database]
hostname =
username =
password =
database =
charset = utf8mb4
; ****************************************************************
; The configuration below will be overruled by the admin panel.
; Changes made below will only have an effect if the database does
; not contain any configuration for the friendica system.
; ****************************************************************
[config]
admin_email =
sitename = Friendica Social Network
register_policy = REGISTER_OPEN
register_text =
[system]
default_timezone = UTC
language = en
INI;
// Keep this line
CONF;
vfsStream::newFile('prepared.ini.php')
->at($this->root)
->setContent($config);
$txt = $this->execute(['autoinstall', '-f', 'prepared.ini.php']);
$this->assertFinished($txt, false, true);
$this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php'));
}
/**
* @medium
*/
public function testWithEnvironmentAndSave()
{
$this->assertTrue(putenv('FRIENDICA_ADMIN_MAIL=admin@friendica.local'));
$this->assertTrue(putenv('FRIENDICA_TZ=Europe/Berlin'));
$this->assertTrue(putenv('FRIENDICA_LANG=de'));
$txt = $this->execute(['autoinstall', '--savedb']);
$this->assertFinished($txt, true);
$this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php'));
$this->assertConfig('database', 'hostname', $this->db_host . (!empty($this->db_port) ? ':' . $this->db_port : ''));
$this->assertConfig('database', 'username', $this->db_user);
$this->assertConfig('database', 'database', $this->db_data);
$this->assertConfig('config', 'admin_email', 'admin@friendica.local');
$this->assertConfig('system', 'default_timezone', 'Europe/Berlin');
$this->assertConfig('system', 'language', 'de');
}
/**
* @medium
*/
public function testWithEnvironmentWithoutSave()
{
$this->assertTrue(putenv('FRIENDICA_ADMIN_MAIL=admin@friendica.local'));
$this->assertTrue(putenv('FRIENDICA_TZ=Europe/Berlin'));
$this->assertTrue(putenv('FRIENDICA_LANG=de'));
$txt = $this->execute(['autoinstall']);
$this->assertFinished($txt, true);
$this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php'));
$this->assertConfig('database', 'hostname', '');
$this->assertConfig('database', 'username', '');
$this->assertConfig('database', 'database', '');
$this->assertConfig('config', 'admin_email', 'admin@friendica.local');
$this->assertConfig('system', 'default_timezone', 'Europe/Berlin');
$this->assertConfig('system', 'language', 'de');
}
/**
* @medium
*/
public function testWithArguments()
{
$args = ['autoinstall'];
array_push($args, '--dbhost');
array_push($args, $this->db_host);
array_push($args, '--dbuser');
array_push($args, $this->db_user);
if (!empty($this->db_pass)) {
array_push($args, '--dbpass');
array_push($args, $this->db_pass);
}
if (!empty($this->db_port)) {
array_push($args, '--dbport');
array_push($args, $this->db_port);
}
array_push($args, '--dbdata');
array_push($args, $this->db_data);
array_push($args, '--admin');
array_push($args, 'admin@friendica.local');
array_push($args, '--tz');
array_push($args, 'Europe/Berlin');
array_push($args, '--lang');
array_push($args, 'de');
$txt = $this->execute($args);
$this->assertFinished($txt, true);
$this->assertTrue($this->root->hasChild('config' . DIRECTORY_SEPARATOR . 'local.ini.php'));
$this->assertConfig('database', 'hostname', $this->db_host . (!empty($this->db_port) ? ':' . $this->db_port : ''));
$this->assertConfig('database', 'username', $this->db_user);
$this->assertConfig('database', 'database', $this->db_data);
$this->assertConfig('config', 'admin_email', 'admin@friendica.local');
$this->assertConfig('system', 'default_timezone', 'Europe/Berlin');
$this->assertConfig('system', 'language', 'de');
}
public function testNoDatabaseConnection()
{
$this->assertTrue(putenv('MYSQL_USERNAME='));
$this->assertTrue(putenv('MYSQL_PASSWORD='));
$this->assertTrue(putenv('MYSQL_DATABASE='));
$txt = $this->execute(['autoinstall']);
$this->assertStuckDB($txt);
}
public function testGetHelp()
{
// Usable to purposely fail if new commands are added without taking tests into account
$theHelp = <<<HELP
Installation - Install Friendica automatically
Synopsis
bin/console autoinstall [-h|--help|-?] [-v] [-a] [-f]
Description
Installs Friendica with data based on the local.ini.php file or environment variables
Notes
Not checking .htaccess/URL-Rewrite during CLI installation.
Options
-h|--help|-? Show help information
-v Show more debug information.
-a All setup checks are required (except .htaccess)
-f|--file <config> prepared config file (e.g. "config/local.ini.php" itself) which will override every other config option - except the environment variables)
-s|--savedb Save the DB credentials to the file (if environment variables is used)
-H|--dbhost <host> The host of the mysql/mariadb database (env MYSQL_HOST)
-p|--dbport <port> The port of the mysql/mariadb database (env MYSQL_PORT)
-d|--dbdata <database> The name of the mysql/mariadb database (env MYSQL_DATABASE)
-U|--dbuser <username> The username of the mysql/mariadb database login (env MYSQL_USER or MYSQL_USERNAME)
-P|--dbpass <password> The password of the mysql/mariadb database login (env MYSQL_PASSWORD)
-b|--phppath <path> The path of the PHP binary (env FRIENDICA_PHP_PATH)
-A|--admin <mail> The admin email address of Friendica (env FRIENDICA_ADMIN_MAIL)
-T|--tz <timezone> The timezone of Friendica (env FRIENDICA_TZ)
-L|--lang <language> The language of Friendica (env FRIENDICA_LANG)
Environment variables
MYSQL_HOST The host of the mysql/mariadb database (mandatory if mysql and environment is used)
MYSQL_PORT The port of the mysql/mariadb database
MYSQL_USERNAME|MYSQL_USER The username of the mysql/mariadb database login (MYSQL_USERNAME is for mysql, MYSQL_USER for mariadb)
MYSQL_PASSWORD The password of the mysql/mariadb database login
MYSQL_DATABASE The name of the mysql/mariadb database
FRIENDICA_PHP_PATH The path of the PHP binary
FRIENDICA_ADMIN_MAIL The admin email address of Friendica (this email will be used for admin access)
FRIENDICA_TZ The timezone of Friendica
FRIENDICA_LANG The langauge of Friendica
Examples
bin/console autoinstall -f 'input.ini.php
Installs Friendica with the prepared 'input.ini.php' file
bin/console autoinstall --savedb
Installs Friendica with environment variables and saves them to the 'config/local.ini.php' file
bin/console autoinstall -h localhost -p 3365 -U user -P passwort1234 -d friendica
Installs Friendica with a local mysql database with credentials
HELP;
$txt = $this->execute(['autoinstall', '-h']);
$this->assertEquals($txt, $theHelp);
}
}

View File

@ -19,12 +19,12 @@ class ConfigConsoleTest extends ConsoleTest
}
private function assertGet($family, $key, $value) {
$config = $this->execute([__FILE__, 'config', $family, $key]);
$config = $this->execute(['config', $family, $key]);
$this->assertEquals($family . "." . $key . " => " . $value . "\n", $config);
}
private function assertSet($family, $key, $value) {
$config = $this->execute([__FILE__, 'config', $family, $key, $value]);
$config = $this->execute(['config', $family, $key, $value]);
$this->assertEquals($family . "." . $key . " <= " . $value . "\n", $config);
}
@ -41,13 +41,13 @@ class ConfigConsoleTest extends ConsoleTest
$testArray = [1, 2, 3];
DBA::insert('config', ['cat' => 'config', 'k' => 'test', 'v' => serialize($testArray)]);
$txt = $this->execute([__FILE__, 'config', 'config', 'test', 'now']);
$txt = $this->execute(['config', 'config', 'test', 'now']);
$this->assertEquals("[Error] config.test is an array and can't be set using this command.\n", $txt);
}
function testTooManyArguments() {
$txt = $this->execute([__FILE__, 'config', 'config', 'test', 'it', 'now']);
$txt = $this->execute(['config', 'config', 'test', 'it', 'now']);
$assertion = '[Warning] Too many arguments';
$firstline = substr($txt, 0, strlen($assertion));
@ -56,8 +56,9 @@ class ConfigConsoleTest extends ConsoleTest
function testVerbose() {
$this->assertSet('test', 'it', 'now');
$executable = $this->getExecutablePath();
$assertion = <<<CONF
Executable: {$this->app->basepath}/tests/src/Core/Console/ConfigConsoleTest.php
Executable: {$executable}
Arguments: array (
0 => 'config',
1 => 'test',
@ -66,7 +67,7 @@ Options: array (
'v' => 1,
)
Command: config
Executable: {$this->app->basepath}/tests/src/Core/Console/ConfigConsoleTest.php
Executable: {$executable}
Class: Friendica\Core\Console\Config
Arguments: array (
0 => 'test',
@ -78,7 +79,7 @@ Options: array (
it => now
CONF;
$txt = $this->execute([__FILE__, 'config', 'test', '-v']);
$txt = $this->execute(['config', 'test', '-v']);
$this->assertEquals($assertion, $txt);
}

View File

@ -4,7 +4,10 @@ namespace Friendica\Test\src\Core\Console;
use Friendica\App;
use Friendica\BaseObject;
use Friendica\Database\DBA;
use Friendica\Test\Util\Intercept;
use org\bovigo\vfs\vfsStream;
use org\bovigo\vfs\vfsStreamDirectory;
use PHPUnit\Framework\TestCase;
abstract class ConsoleTest extends TestCase
@ -18,6 +21,11 @@ abstract class ConsoleTest extends TestCase
*/
protected $app;
/**
* @var vfsStreamDirectory The Stream Directory
*/
protected $root;
protected $stdout;
protected function setUp()
@ -30,12 +38,19 @@ abstract class ConsoleTest extends TestCase
$this->markTestSkipped('Please set the MYSQL_* environment variables to your test database credentials.');
}
$this->setUpVfsDir();
// Reusable App object
$this->app = BaseObject::getApp();
$this->app = new App($this->root->url());
BaseObject::setApp($this->app);
$this->console = new MultiUseConsole();
}
public function execute($args) {
DBA::disconnect();
$this->app->reload();
array_unshift($args, $this->getExecutablePath());
Intercept::reset();
$this->console->reset();
$this->console->parseTestArgv($args);
@ -45,4 +60,48 @@ abstract class ConsoleTest extends TestCase
Intercept::reset();
return $returnStr;
}
/**
* @return string returns the path to the console executable during tests
*/
protected function getExecutablePath() {
return $this->root->getChild('bin' . DIRECTORY_SEPARATOR . 'console.php')->url();
}
private function setUpVfsDir() {
// the used directories inside the App class
$structure = [
'config' => [],
'bin' => []
];
// create a virtual directory and copy all needed files and folders to it
$this->root = vfsStream::setup('friendica', null, $structure);
$this->setConfigFile('config.ini.php');
$this->setConfigFile('settings.ini.php');
$this->setConfigFile('local.ini.php');
$this->setConfigFile('dbstructure.json');
// fake console.php for setting an executable
vfsStream::newFile('console.php')
->at($this->root->getChild('bin'))
->setContent('<? php');
}
private function setConfigFile($filename)
{
$file = dirname(__DIR__) . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR .
$filename;
if (file_exists($file)) {
vfsStream::newFile($filename)
->at($this->root->getChild('config'))
->setContent(file_get_contents($file));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -383,7 +383,7 @@ function NavUpdate() {
$('nav').trigger('nav-update', data.result);
// start live update
['network', 'profile', 'community', 'notes', 'display'].forEach(function (src) {
['network', 'profile', 'community', 'notes', 'display', 'contacts'].forEach(function (src) {
if ($('#live-' + src).length) {
liveUpdate(src);
}

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

@ -20,8 +20,8 @@
<li class="divider"></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.archive.title}}" onclick="window.location.href='{{$contact_actions.archive.url}}'; return false;">{{$contact_actions.archive.label}}</a></li>
<li role="menuitem"><a href="{{$contact_actions.delete.url}}" title="{{$contact_actions.delete.title}}" onclick="return confirmDelete();">{{$contact_actions.delete.label}}</a></li>
{{if $contact_actions.archive.url}}<li role="menuitem"><a href="#" title="{{$contact_actions.archive.title}}" onclick="window.location.href='{{$contact_actions.archive.url}}'; return false;">{{$contact_actions.archive.label}}</a></li>{{/if}}
{{if $contact_actions.delete.url}}<li role="menuitem"><a href="{{$contact_actions.delete.url}}" title="{{$contact_actions.delete.title}}" onclick="return confirmDelete();">{{$contact_actions.delete.label}}</a></li> {{/if}}
</ul>
</div>
@ -63,6 +63,7 @@
<hr />
{{if $contact_settings_label}}
<h4 id="contact-edit-settings-label" class="fakelink" onclick="openClose('contact-edit-settings')">{{$contact_settings_label}}</h4>
<div id="contact-edit-settings">
<input type="hidden" name="contact_id" value="{{$contact_id}}">
@ -100,7 +101,7 @@
</div>
<input class="contact-edit-submit" type="submit" name="submit" value="{{$submit|escape:'html'}}" />
{{/if}}
<div class="contact-edit-submit-end clearfix"></div>
</form>{{* End of the form *}}

View File

@ -3453,4 +3453,12 @@ section .profile-match-wrapper {
top: 24px;
left: 24px;
}
/*
Prevent automatic zoom on input focus on iOS
see https://stackoverflow.com/a/16255670
*/
.form-control {
font-size: 16px;
}
}

View File

@ -26,8 +26,8 @@
{{/if}}
<li role="presentation"><a role="menuitem" href="{{$contact_actions.block.url}}" title="{{$contact_actions.block.title}}">{{$contact_actions.block.label}}</a></li>
<li role="presentation"><a role="menuitem" href="{{$contact_actions.ignore.url}}" title="{{$contact_actions.ignore.title}}">{{$contact_actions.ignore.label}}</a></li>
<li role="presentation"><a role="menuitem" href="{{$contact_actions.archive.url}}" title="{{$contact_actions.archive.title}}">{{$contact_actions.archive.label}}</a></li>
<li role="presentation"><button role="menuitem" type="button" class="btn-link" title="{{$contact_actions.delete.title}}" onclick="addToModal('{{$contact_actions.delete.url}}?confirm=1');">{{$contact_actions.delete.label}}</button></li>
{{if $contact_actions.archive.url}}<li role="presentation"><a role="menuitem" href="{{$contact_actions.archive.url}}" title="{{$contact_actions.archive.title}}">{{$contact_actions.archive.label}}</a></li>{{/if}}
{{if $contact_actions.delete.url}}<li role="presentation"><button role="menuitem" type="button" class="btn-link" title="{{$contact_actions.delete.title}}" onclick="addToModal('{{$contact_actions.delete.url}}?confirm=1');">{{$contact_actions.delete.label}}</button></li>{{/if}}
</ul>
</li>
</ul>
@ -119,6 +119,7 @@
<div class="clear"></div>
</div>
{{if $contact_settings_label}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="contact-edit-settings">
<h4>
@ -146,7 +147,9 @@
</div>
</div>
</div>
{{/if}}
{{if $lbl_info1}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="contact-edit-info">
<h4>
@ -172,7 +175,8 @@
</div>
</div>
</div>
{{/if}}
{{if $lbl_vis1}}
<div class="panel">
<div class="section-subtitle-wrapper" role="tab" id="contact-edit-profile-select">
<h4>
@ -200,7 +204,7 @@
</div>
</div>
</div>
{{/if}}
</div>
</form>{{* End of the form *}}

View File

@ -40,7 +40,7 @@
<ul class="nav navbar-nav navbar-left" role="menubar">
<li id="nav-communication" class="nav-segment" role="presentation">
{{if $nav.network}}
<a accesskey="n"role="menuitem" class="nav-menu {{$sel.network}}" href="{{$nav.network.0}}" data-toggle="tooltip" aria-label="{{$nav.network.3}}" title="{{$nav.network.3}}"><i class="fa fa-lg fa-th" aria-hidden="true"></i><span id="net-update" class="nav-network-badge badge nav-notify"></span></a>
<a accesskey="n" role="menuitem" class="nav-menu {{$sel.network}}" href="{{$nav.network.0}}" data-toggle="tooltip" aria-label="{{$nav.network.3}}" title="{{$nav.network.3}}"><i class="fa fa-lg fa-th" aria-hidden="true"></i><span id="net-update" class="nav-network-badge badge nav-notify"></span></a>
{{/if}}
{{if $nav.home}}
@ -300,7 +300,7 @@ The result is a friendica logo in the user icon color.*}}
<svg id="friendica-logo-mask" x="0px" y="0px" width="0px" height="0px" viewBox="0 0 250 250">
<defs>
<mask id="logo-mask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#ffffff;" d="M0.796,0L0.172,0.004C0.068,0.008,0.008,0.068,0,0.172V0.824c0,0.076,0.06,0.16,0.168,0.172h0.652c0.072,0,0.148-0.06,0.172-0.144V0.14C1,0.06,0.908,0,0.796,0zM0.812,0.968H0.36v-0.224h0.312v-0.24H0.36V0.3h0.316l0-0.264l0.116-0c0.088,0,0.164,0.044,0.164,0.096l0,0.696C0.96,0.912,0.876,0.968,0.812,0.968z"/>
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:#ffffff;" d="M0.796,0L0.172,0.004C0.068,0.008,0.008,0.068,0,0.172V0.824c0,0.076,0.06,0.16,0.168,0.172h0.652c0.072,0,0.148-0.06,0.172-0.144V0.14C1,0.06,0.908,0,0.796,0zM0.812,0.968H0.36v-0.224h0.312v-0.24H0.36V0.3h0.316l0-0.264l0.116-0c0.088,0,0.164,0.044,0.164,0.096l0,0.696C0.96,0.912,0.876,0.968,0.812,0.968z"></path>
</mask>
</defs>
</svg>

View File

@ -150,8 +150,18 @@ function frio_item_photo_menu(App $a, &$arr)
function frio_contact_photo_menu(App $a, &$args)
{
$cid = $args['contact']['id'];
$pokelink = $args['menu']['poke'][1];
$pmlink = $args['menu']['pm'][1];
if (!empty($args['menu']['poke'])) {
$pokelink = $args['menu']['poke'][1];
} else {
$pokelink = '';
}
if (!empty($args['menu']['poke'])) {
$pmlink = $args['menu']['pm'][1];
} else {
$pmlink = '';
}
// Set the the indicator for opening the status, profile and photo pages
// in a new tab to false if the contact a dfrn (friendica) contact

View File

@ -21,8 +21,8 @@
<li class="divider"></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.archive.title}}" onclick="window.location.href='{{$contact_actions.archive.url}}'; return false;">{{$contact_actions.archive.label}}</a></li>
<li role="menuitem"><a href="{{$contact_actions.delete.url}}" title="{{$contact_actions.delete.title}}" onclick="return confirmDelete();">{{$contact_actions.delete.label}}</a></li>
{{if $contact_actions.archive.url}}<li role="menuitem"><a href="#" title="{{$contact_actions.archive.title}}" onclick="window.location.href='{{$contact_actions.archive.url}}'; return false;">{{$contact_actions.archive.label}}</a></li>{{/if}}
{{if $contact_actions.delete.url}}<li role="menuitem"><a href="{{$contact_actions.delete.url}}" title="{{$contact_actions.delete.title}}" onclick="return confirmDelete();">{{$contact_actions.delete.label}}</a></li>{{/if}}
</ul>
</div>
@ -64,6 +64,7 @@
<hr />
{{if $contact_settings_label}}
<h4 id="contact-edit-settings-label" class="fakelink" onclick="openClose('contact-edit-settings')">{{$contact_settings_label}}</h4>
<div id="contact-edit-settings">
<input type="hidden" name="contact_id" value="{{$contact_id}}">
@ -99,8 +100,8 @@
<div id="contact-edit-profile-select-end"></div>
{{/if}}
</div>
<input class="contact-edit-submit" type="submit" name="submit" value="{{$submit|escape:'html'}}" />
{{/if}}
<div class="contact-edit-submit-end clearfix"></div>