Merge branch '2019.06-rc'

# Conflicts:
#	CHANGELOG
#	VERSION
#	boot.php
This commit is contained in:
Hypolite Petovan 2019-06-23 15:30:44 -04:00
commit c1f99c70b1
594 changed files with 94180 additions and 68341 deletions

8
.gitignore vendored
View File

@ -1,12 +1,11 @@
favicon.*
.htconfig.php
.htpreconfig.php
/.htconfig.php
/.htpreconfig.php
\#*
*.log
*.out
*.version*
home.html
*~
robots.txt
@ -74,3 +73,6 @@ venv/
#ignore filesystem storage default path
/storage
#Ignore log folder
/log

View File

@ -19,6 +19,11 @@ before_script:
- cp config/local-sample.config.php config/local.config.php
- mysql -e 'CREATE DATABASE IF NOT EXISTS test;'
- mysql -utravis test < database.sql
- echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- pecl channel-update pecl.php.net
- pecl config-set preferred_state beta
- if [[ $TRAVIS_PHP_VERSION != "7.1" ]]; then echo yes | pecl upgrade apcu; fi
- if [[ $TRAVIS_PHP_VERSION != "7.1" ]]; then phpenv config-add .travis/apcu.ini; fi
- phpenv config-add .travis/redis.ini
- phpenv config-add .travis/memcached.ini
after_success: bash <(curl -s https://codecov.io/bash)

4
.travis/apcu.ini Normal file
View File

@ -0,0 +1,4 @@
extension="apcu.so"
apc.enabled = 1
apc.enable_cli = 1

1
.travis/memcached.ini Normal file
View File

@ -0,0 +1 @@
extension="memcached.so"

1
.travis/redis.ini Normal file
View File

@ -0,0 +1 @@
extension="redis.so"

View File

@ -1,7 +1,78 @@
Version 2019.06 (2019-06-23)
Friendica Core:
Update to the tranlation (CS, DE, EN-GB, EN-US, ET, FR, IT, PL, PT-BR, SV) [translation teams]
Update to the documentation [nupplaphil, realkinetix, MrPetovan]
Update to the themes (frio, vier) [BinkaDroid, MrPetovan, tobiasd]
Enhancements to the API [annando, MrPetovan]
Enhancements to the way reshares are handled [annando]
Enhancements to the redis configuration [nupplaphil]
Enhancements to the federation stats display in the admin panel [tobiasd]
Enhancements to the processing of changed storage engine [MrPetovan]
Enhancements to ActivityPub support [annando, MrPetovan]
Enhancements to code security [MrPetovan]
Enhancements to delivery counter [annando]
Fixed the notification order [JeroenED]
Fixed the timezone of Friendica logs [nupplaphil]
Fixed tag completion painfully slow [AlfredSK]
Fixed a regression in notifications [MrPetovan, annando]
Fixed an issue with smilies and code blocks [MrPetovan]
Fixed an AP issue with unavailable local profiles [MrPetovan]
Fixed an issue with the File to Folder feature [MrPetovan]
Fixed an issue with the legacy storage engine [fabrixxm]
Fixed an issue with the theme and addon path items [MrPetovan]
Fixed an issue occuring when the BasePath was not set [tobiasd]
Fixed an issue with additionally opened Sessions [MrPetovan]
Fixed an issue with legacy loglevel mapping [nupplaphil]
Fixed contact suggestions [annando]
Fixed an issue with frio hovercard [nupplaphil]
Fixed event interaction federation [annando]
Fixed remote image permission [deantownsley]
General Code cleaning and restructuring [annando, nupplaphil, tobiasd]
Added frio color scheme sharing [JeroenED]
Added syslog and stream Logger [nupplaphil]
Added storage move cronjob [MrPetovan]
Added collapsible panel for connector permission fields [MrPetovan]
Added rule-based router [MrPetovan]
Added Estonian translation [Rain Hawk]
Added APCu caching [nupplaphil]
Added BlockServer command to the Friendica console [nupplaphil]
Added reshare count [annando]
Added rule-based router [MrPetovan, nupplaphil]
Added themed error pages with mascot [MrPetovan, lostinlight]
Added contact relationship filter [MrPetovan]
Removed the old queue mechanism (deferred workers are now used) [annando]
Removed BasePath and Hostname settings from the admin panel [nupplaphil]
Remove support for defunct F-Droid Friendica app [MrPetovan]
Friendica Addons:
Update to the tranlation (ET, SV, ZH_CN) [translation teams]
botdetection:
Added a new addon for preventing access by bots [nupplaphil, annando]
buffer:
Traces of Google+ were removed [annando]
curweather:
Fixed a problem with the display of the correct temperature unit [tobiasd]
fromgplus:
Deprecated the addon as Google+ was closed [tobiasd]
fortunate:
Deprecated addon for incompatibility with latest Friendica version [MrPetovan]
phpmailer:
Added a new addon to use external SMTP for email [M-arcus, kecalcze, MrPetovan]
pledgie:
Deprecated addon as service was discontinued [M-arcus]
xmpp:
Marked addon as unsupported because of various incompatibilities with themes [MrPetovan]
Closed Issues:
1012, 2209, 2528, 3309, 3717, 3816, 3869, 4453, 4999, 5011, 5047, 5276, 5850, 5983, 6303, 6319, 6379, 6410, 6477,
6478, 6720, 6799, 6813, 6819, 6861, 6864, 6879, 6903, 6916, 6917, 6918, 6921, 6927, 6929, 6936, 6938, 6941, 6943,
6947, 6948, 6950, 6952, 6983, 6999, 7023, 7036, 7047, 7106, 7112, 7119, 7128, 7130, 7131, 7141, 7142, 7150, 7171,
7183, 7196, 7209, 7223, 7226, 7240, 7241, 7249, 7264, 7269, 7271, 7275, 7300, 7303
Version 2019.04 (2019-04-28)
Friendica Core:
Fixed a privacy problem with postings accessed by feed [MrPetovan]
Version 2019.03 (2019-03-22)
Friendica Core:
Update to the translation (CS, DE, EN-GB, EN-US, ES, FR, IT, PL, SV, ZH-CN) [translation teams]

View File

@ -1,3 +1,5 @@
23n
Abinoam P. Marques Jr.
Abraham Pérez Hernández
@ -26,6 +28,7 @@ Andy Hee
Angristan
Anthronaut
Arian - Cazare Muncitori
Asher Pen
Athalbert
aweiher
axelt
@ -37,6 +40,8 @@ Beluga
Ben
Ben Roberts
ben-utzer
BinkaDroid
Bjoessi
bufalo1973
Calango Jr
Carlos Solís
@ -107,6 +112,7 @@ Jens Tautenhahn
jensp
Jeroen De Meerleer
jeroenpraat
JOduMonT
Johannes Schwab
John Brazil
Jonatan Nyberg
@ -175,6 +181,7 @@ R C
Rabuzarus
Radek
Rafael Garau
Rain Hawk
Rainulf Pineda
Ralf Thees
Ralph
@ -183,6 +190,7 @@ rcmaniac
rebeka-catalina
repat
Ricardo Pereira
Rik 4
RJ Madsen
Roland Häder
Rui Andrada
@ -207,6 +215,7 @@ Steffen K9
StefOfficiel
Sveinn í Felli
Sven Anders
Sylke Vicious
Sylvain Lagacé
szymon.filip
Sérgio Lima
@ -225,6 +234,7 @@ tomacat
tomamplius
tomtom84
Tony Baldwin
Torbjörn Andersson
TORminator
trebor
tschlotfeldt
@ -234,6 +244,7 @@ U-SOUND\mike
ufic
Ulf Rompe
Unknown
Valvin
Vasudev Kamath
Vasya Novikov
Vinzenz Vietzke

View File

@ -29,7 +29,7 @@ is self-signed).
## 1. Requirements
- Apache with mod-rewrite enabled and "Options All" so you can use a local .htaccess file
- PHP 5.6.1+ (PHP 7.1+ recommended for performance and official support).
- PHP 7+ (PHP 7.1+ recommended for performance and official support).
- PHP *command line* with `register_argc_argv = true` in php.ini
- curl, gd (with at least jpeg support), mysql, mbstring, xml, zip and openssl extensions
- Some form of email server or email gateway such that PHP mail() works

View File

@ -16,26 +16,26 @@ Join today and [get your Friendica profile!](https://dir.friendica.social/server
### Friendica Screenshots
| ![Frio theme in mobile browser](/images/screenshots/friendica-frio-mobile-profle-1.png?raw=true "Frio theme in mobile browser") ![Frio theme in mobile browser](/images/screenshots/friendica-frio-mobile-profle-2.png?raw=true "Frio theme in mobile browser")
| ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profle-1.png?raw=true "Frio theme in mobile browser") ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profle-2.png?raw=true "Frio theme in mobile browser")
|:--:|
|*Frio theme, mobile browser. Timeline and composer view.*|
|![Frio theme in desktop browser](/images/screenshots/friendica-frio-green-profle-1.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profle-1.png?raw=true "Frio theme in desktop browser")
|*Frio theme, desktop browser. Timeline view, contact info popped up, control menu open.*|
|![Frio theme in desktop browser](/images/screenshots/friendica-frio-green-profle-2.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profle-2.png?raw=true "Frio theme in desktop browser")
|*Frio theme, desktop browser. Menu open for controlling individual posts.*|
|![Frio theme in desktop browser](/images/screenshots/friendica-frio-red-profle-3.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profle-3.png?raw=true "Frio theme in desktop browser")
|*Frio theme, desktop browser. Profile view, notification menu open.*|
|![Frio theme in desktop browser](/images/screenshots/friendica-frio-red-profle-2.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profle-2.png?raw=true "Frio theme in desktop browser")
|*Number of new posts, in total and by group.*|
|![Frio theme in desktop browser](/images/screenshots/friendica-frio-red-profle-1.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profle-1.png?raw=true "Frio theme in desktop browser")
|*Calender with popup of event.*|
|![Frio theme default colour in standard browser on tablet](/images/screenshots/friendica-frio-default-profile-1.png?raw=true "Frio theme default colour in standard browser on tablet")
|![Frio theme default colour in standard browser on tablet](images/screenshots/friendica-frio-default-profile-1.png?raw=true "Frio theme default colour in standard browser on tablet")
|*Notifications menu and private messages counter, standard browser on tablet.*|
|![Frio theme in desktop browser](/images/screenshots/friendica-frio-brown-profile-2.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-brown-profile-2.png?raw=true "Frio theme in desktop browser")
|*Number of visible contacts, standard browser.*|
|![Frio theme in desktop browser](/images/screenshots/friendica-frio-brown-profile-1.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-brown-profile-1.png?raw=true "Frio theme in desktop browser")
|*Network posts chronologically ordered, standard browser.*|
|![Vier theme in desktop browser](/images/screenshots/friendica-vier-profile.png?raw=true "Vier theme in desktop browser")
|![Vier theme in desktop browser](images/screenshots/friendica-vier-profile.png?raw=true "Vier theme in desktop browser")
|*Vier theme, desktop browser. Public timeline view.*|
|![Vier theme in desktop browser](/images/screenshots/friendica-vier-community.png?raw=true "Vier theme in desktop browser")
|![Vier theme in desktop browser](images/screenshots/friendica-vier-community.png?raw=true "Vier theme in desktop browser")
|*Vier theme, desktop browser. Community post displayed.*|

View File

@ -1 +1 @@
2019.04
2019.06

View File

@ -144,9 +144,7 @@ if (!$foreground) {
file_put_contents($pidfile, $pid);
// We lose the database connection upon forking
/// @todo refactoring during https://github.com/friendica/friendica/issues/6720
$basePath = \Friendica\Util\BasePath::create(dirname(__DIR__), $_SERVER);
Factory\DBFactory::init($basePath, $a->getConfigCache(), $a->getProfiler(), $_SERVER);
Factory\DBFactory::init($a->getConfigCache(), $a->getProfiler(), $_SERVER);
}
Config::set('system', 'worker_daemon_mode', true);

View File

@ -33,7 +33,7 @@ require dirname(__DIR__) . '/vendor/autoload.php';
$a = Factory\DependencyFactory::setUp('worker', dirname(__DIR__));
// Check the database structure and possibly fixes it
Update::check($a->getBasePath(), true);
Update::check($a->getBasePath(), true, $a->getMode());
// Quit when in maintenance
if (!$a->getMode()->has(App\Mode::MAINTENANCEDISABLED)) {

View File

@ -31,7 +31,7 @@ use Friendica\Util\DateTimeFormat;
define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Dalmatian Bellflower');
define('FRIENDICA_VERSION', '2019.04');
define('FRIENDICA_VERSION', '2019.06');
define('DFRN_PROTOCOL_VERSION', '2.23');
define('NEW_UPDATE_ROUTINE_VERSION', 1170);
@ -82,17 +82,6 @@ define('MAX_IMAGE_LENGTH', -1);
*/
define('DEFAULT_DB_ENGINE', 'InnoDB');
/**
* @name SSL Policy
*
* SSL redirection policies
* @{
*/
define('SSL_POLICY_NONE', 0);
define('SSL_POLICY_FULL', 1);
define('SSL_POLICY_SELFSIGN', 2);
/* @}*/
/** @deprecated since version 2019.03, please use \Friendica\Module\Register::CLOSED instead */
define('REGISTER_CLOSED', \Friendica\Module\Register::CLOSED);
/** @deprecated since version 2019.03, please use \Friendica\Module\Register::APPROVE instead */
@ -204,6 +193,7 @@ define('NAMESPACE_ZOT', 'http://purl.org/zot');
define('NAMESPACE_DFRN', 'http://purl.org/macgirvin/dfrn/1.0');
define('NAMESPACE_THREAD', 'http://purl.org/syndication/thread/1.0');
define('NAMESPACE_TOMB', 'http://purl.org/atompub/tombstones/1.0');
define('NAMESPACE_ACTIVITY2', 'https://www.w3.org/ns/activitystreams#');
define('NAMESPACE_ACTIVITY', 'http://activitystrea.ms/spec/1.0/');
define('NAMESPACE_ACTIVITY_SCHEMA', 'http://activitystrea.ms/schema/1.0/');
define('NAMESPACE_MEDIA', 'http://purl.org/syndication/atommedia');
@ -246,6 +236,7 @@ define('ACTIVITY_FAVORITE', NAMESPACE_ACTIVITY_SCHEMA . 'favorite');
define('ACTIVITY_UNFAVORITE', NAMESPACE_ACTIVITY_SCHEMA . 'unfavorite');
define('ACTIVITY_SHARE', NAMESPACE_ACTIVITY_SCHEMA . 'share');
define('ACTIVITY_DELETE', NAMESPACE_ACTIVITY_SCHEMA . 'delete');
define('ACTIVITY2_ANNOUNCE', NAMESPACE_ACTIVITY2 . 'Announce');
define('ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke');
@ -543,39 +534,6 @@ function is_site_admin()
return local_user() && $admin_email && in_array(defaults($a->user, 'email', ''), $adminlist);
}
/**
* @brief Returns querystring as string from a mapped array.
*
* @param array $params mapped array with query parameters
* @param string $name of parameter, default null
*
* @return string
*/
function build_querystring($params, $name = null)
{
$ret = "";
foreach ($params as $key => $val) {
if (is_array($val)) {
/// @TODO maybe not compare against null, use is_null()
if ($name == null) {
$ret .= build_querystring($val, $key);
} else {
$ret .= build_querystring($val, $name . "[$key]");
}
} else {
$val = urlencode($val);
/// @TODO maybe not compare against null, use is_null()
if ($name != null) {
/// @TODO two string concated, can be merged to one
$ret .= $name . "[$key]" . "=$val&";
} else {
$ret .= "$key=$val&";
}
}
}
return $ret;
}
function explode_querystring($query)
{
$arg_st = strpos($query, '?');

View File

@ -13,7 +13,7 @@
"issues": "https://github.com/friendica/friendica/issues"
},
"require": {
"php": ">=5.6.1",
"php": ">=7.0",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",
@ -27,6 +27,7 @@
"ext-simplexml": "*",
"ext-xml": "*",
"asika/simple-console": "^1.0",
"bacon/bacon-qr-code": "^1.0",
"divineomega/password_exposed": "^2.4",
"ezyang/htmlpurifier": "~4.7.0",
"friendica/json-ld": "^1.0",
@ -35,14 +36,18 @@
"michelf/php-markdown": "^1.7",
"mobiledetect/mobiledetectlib": "2.8.*",
"monolog/monolog": "^1.24",
"paragonie/random_compat": "^2.0",
"nikic/fast-route": "^1.3",
"paragonie/hidden-string": "^1.0",
"pear/text_languagedetect": "1.*",
"pragmarx/google2fa": "^5.0",
"pragmarx/recovery": "^0.1.0",
"psr/container": "^1.0",
"seld/cli-prompt": "^1.0",
"smarty/smarty": "^3.1",
"fxp/composer-asset-plugin": "~1.3",
"bower-asset/base64": "^1.0",
"bower-asset/chart-js": "^2.7",
"bower-asset/dompurify": "^1.0",
"bower-asset/perfect-scrollbar": "^0.6",
"bower-asset/vue": "^2.5",
"npm-asset/jquery": "^2.0",
@ -52,7 +57,8 @@
"npm-asset/moment": "^2.20.1",
"npm-asset/fullcalendar": "^3.0.1",
"npm-asset/cropperjs": "1.2.2",
"npm-asset/imagesloaded": "4.1.4"
"npm-asset/imagesloaded": "4.1.4",
"pear/console_table": "^1.3"
},
"repositories": [
{

633
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "8897c1f6912cc9b889534a8c59deead1",
"content-hash": "eb985236d64ed0b0fe1fc2e4ac6616e2",
"packages": [
{
"name": "asika/simple-console",
@ -39,6 +39,52 @@
"description": "One file console framework to help you write build scripts.",
"time": "2018-03-08T12:05:40+00:00"
},
{
"name": "bacon/bacon-qr-code",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/Bacon/BaconQrCode.git",
"reference": "5a91b62b9d37cee635bbf8d553f4546057250bee"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/5a91b62b9d37cee635bbf8d553f4546057250bee",
"reference": "5a91b62b9d37cee635bbf8d553f4546057250bee",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": "^5.4|^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8"
},
"suggest": {
"ext-gd": "to generate QR code images"
},
"type": "library",
"autoload": {
"psr-0": {
"BaconQrCode": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "http://www.dasprids.de",
"role": "Developer"
}
],
"description": "BaconQrCode is a QR code generator for PHP.",
"homepage": "https://github.com/Bacon/BaconQrCode",
"time": "2017-10-17T09:59:25+00:00"
},
{
"name": "bower-asset/Chart-js",
"version": "v2.7.2",
@ -102,6 +148,51 @@
"description": "Base64 encoding and decoding",
"time": "2017-03-25T21:16:21+00:00"
},
{
"name": "bower-asset/dompurify",
"version": "1.0.10",
"source": {
"type": "git",
"url": "https://github.com/cure53/DOMPurify.git",
"reference": "b537cab466329b1b077e0e5e3c14edad2b7142f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cure53/DOMPurify/zipball/b537cab466329b1b077e0e5e3c14edad2b7142f7",
"reference": "b537cab466329b1b077e0e5e3c14edad2b7142f7",
"shasum": ""
},
"type": "bower-asset-library",
"extra": {
"bower-asset-main": "src/purify.js",
"bower-asset-ignore": [
"**/.*",
"demos",
"scripts",
"test",
"website"
]
},
"license": [
"MPL-2.0",
"Apache-2.0"
],
"description": "A DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG",
"keywords": [
"cross site scripting",
"dom",
"filter",
"html",
"mathml",
"sanitize",
"sanitizer",
"secure",
"security",
"svg",
"xss"
],
"time": "2019-02-19T13:27:01+00:00"
},
{
"name": "bower-asset/perfect-scrollbar",
"version": "0.6.16",
@ -887,6 +978,52 @@
],
"time": "2018-11-05T09:00:11+00:00"
},
{
"name": "nikic/fast-route",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/FastRoute.git",
"reference": "181d480e08d9476e61381e04a71b34dc0432e812"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812",
"reference": "181d480e08d9476e61381e04a71b34dc0432e812",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|~5.7"
},
"type": "library",
"autoload": {
"psr-4": {
"FastRoute\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov",
"email": "nikic@php.net"
}
],
"description": "Fast request router for PHP",
"keywords": [
"router",
"routing"
],
"time": "2018-02-13T20:26:39+00:00"
},
{
"name": "npm-asset/cropperjs",
"version": "1.2.2",
@ -1586,25 +1723,24 @@
},
{
"name": "paragonie/constant_time_encoding",
"version": "v1.0.4",
"version": "v2.2.3",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6"
"reference": "55af0dc01992b4d0da7f6372e2eac097bbbaffdb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/2132f0f293d856026d7d11bd81b9f4a23a1dc1f6",
"reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/55af0dc01992b4d0da7f6372e2eac097bbbaffdb",
"reference": "55af0dc01992b4d0da7f6372e2eac097bbbaffdb",
"shasum": ""
},
"require": {
"php": "^5.3|^7"
"php": "^7"
},
"require-dev": {
"paragonie/random_compat": "^1.4|^2",
"phpunit/phpunit": "4.*|5.*",
"vimeo/psalm": "^0.3|^1"
"phpunit/phpunit": "^6|^7",
"vimeo/psalm": "^1|^2"
},
"type": "library",
"autoload": {
@ -1645,37 +1781,82 @@
"hex2bin",
"rfc4648"
],
"time": "2018-04-30T17:57:16+00:00"
"time": "2019-01-03T20:26:31+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.17",
"name": "paragonie/hidden-string",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d"
"url": "https://github.com/paragonie/hidden-string.git",
"reference": "0bbb00be0e33b8e1d48fa79ea35cd42d3091a936"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d",
"reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d",
"url": "https://api.github.com/repos/paragonie/hidden-string/zipball/0bbb00be0e33b8e1d48fa79ea35cd42d3091a936",
"reference": "0bbb00be0e33b8e1d48fa79ea35cd42d3091a936",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
"paragonie/constant_time_encoding": "^2",
"paragonie/sodium_compat": "^1.6",
"php": "^7"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*"
"phpunit/phpunit": "^6|^7",
"vimeo/psalm": "^1"
},
"type": "library",
"autoload": {
"psr-4": {
"ParagonIE\\HiddenString\\": "./src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MPL-2.0"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "info@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "Encapsulate strings in an object to hide them from stack traces",
"homepage": "https://github.com/paragonie/hidden-string",
"keywords": [
"hidden",
"stack trace",
"string"
],
"time": "2018-05-07T20:28:06+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v9.99.99",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
"reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
"shasum": ""
},
"require": {
"php": "^7"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*",
"vimeo/psalm": "^1"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"type": "library",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
@ -1694,7 +1875,7 @@
"pseudorandom",
"random"
],
"time": "2018-07-04T16:31:37+00:00"
"time": "2018-07-02T15:55:56+00:00"
},
{
"name": "paragonie/sodium_compat",
@ -1778,6 +1959,61 @@
],
"time": "2018-09-22T03:59:58+00:00"
},
{
"name": "pear/console_table",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/pear/Console_Table.git",
"reference": "1930c11897ca61fd24b95f2f785e99e0f36dcdea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/Console_Table/zipball/1930c11897ca61fd24b95f2f785e99e0f36dcdea",
"reference": "1930c11897ca61fd24b95f2f785e99e0f36dcdea",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"suggest": {
"pear/Console_Color2": ">=0.1.2"
},
"type": "library",
"autoload": {
"classmap": [
"Table.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Jan Schneider",
"homepage": "http://pear.php.net/user/yunosh"
},
{
"name": "Tal Peer",
"homepage": "http://pear.php.net/user/tal"
},
{
"name": "Xavier Noguer",
"homepage": "http://pear.php.net/user/xnoguer"
},
{
"name": "Richard Heyes",
"homepage": "http://pear.php.net/user/richard"
}
],
"description": "Library that makes it easy to build console style tables.",
"homepage": "http://pear.php.net/package/Console_Table/",
"keywords": [
"console"
],
"time": "2018-01-25T20:47:17+00:00"
},
{
"name": "pear/text_languagedetect",
"version": "v1.0.0",
@ -1822,6 +2058,189 @@
"homepage": "http://pear.php.net/package/Text_LanguageDetect",
"time": "2017-03-02T16:14:08+00:00"
},
{
"name": "pragmarx/google2fa",
"version": "v5.0.0",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/google2fa.git",
"reference": "17c969c82f427dd916afe4be50bafc6299aef1b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/17c969c82f427dd916afe4be50bafc6299aef1b4",
"reference": "17c969c82f427dd916afe4be50bafc6299aef1b4",
"shasum": ""
},
"require": {
"paragonie/constant_time_encoding": "~1.0|~2.0",
"paragonie/random_compat": ">=1",
"php": ">=5.4",
"symfony/polyfill-php56": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4|~5|~6"
},
"type": "library",
"extra": {
"component": "package",
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"PragmaRX\\Google2FA\\": "src/",
"PragmaRX\\Google2FA\\Tests\\": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"role": "Creator & Designer"
}
],
"description": "A One Time Password Authentication package, compatible with Google Authenticator.",
"keywords": [
"2fa",
"Authentication",
"Two Factor Authentication",
"google2fa"
],
"time": "2019-03-19T22:44:16+00:00"
},
{
"name": "pragmarx/random",
"version": "v0.2.2",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/random.git",
"reference": "daf08a189c5d2d40d1a827db46364d3a741a51b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/random/zipball/daf08a189c5d2d40d1a827db46364d3a741a51b7",
"reference": "daf08a189c5d2d40d1a827db46364d3a741a51b7",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"fzaninotto/faker": "~1.7",
"phpunit/phpunit": "~6.4",
"pragmarx/trivia": "~0.1",
"squizlabs/php_codesniffer": "^2.3"
},
"suggest": {
"fzaninotto/faker": "Allows you to get dozens of randomized types",
"pragmarx/trivia": "For the trivia database"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"PragmaRX\\Random\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"homepage": "https://antoniocarlosribeiro.com",
"role": "Developer"
}
],
"description": "Create random chars, numbers, strings",
"homepage": "https://github.com/antonioribeiro/random",
"keywords": [
"Randomize",
"faker",
"pragmarx",
"random",
"random number",
"random pattern",
"random string"
],
"time": "2017-11-21T05:26:22+00:00"
},
{
"name": "pragmarx/recovery",
"version": "v0.1.0",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/recovery.git",
"reference": "e16573a1ae5345cc3b100eec6d0296a1a15a90fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/recovery/zipball/e16573a1ae5345cc3b100eec6d0296a1a15a90fe",
"reference": "e16573a1ae5345cc3b100eec6d0296a1a15a90fe",
"shasum": ""
},
"require": {
"php": "~7.0",
"pragmarx/random": "~0.1"
},
"require-dev": {
"phpunit/phpunit": ">=5.4.3",
"squizlabs/php_codesniffer": "^2.3",
"tightenco/collect": "^5"
},
"suggest": {
"tightenco/collect": "Allows to generate recovery codes as collections"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"PragmaRX\\Recovery\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"homepage": "https://antoniocarlosribeiro.com",
"role": "Developer"
}
],
"description": "Create recovery codes for two factor auth",
"homepage": "https://github.com/antonioribeiro/recovery",
"keywords": [
"2fa",
"account recovery",
"auth",
"backup codes",
"google2fa",
"pragmarx",
"recovery",
"recovery codes",
"two factor auth"
],
"time": "2017-09-19T16:58:00+00:00"
},
{
"name": "psr/cache",
"version": "1.0.1",
@ -2114,9 +2533,159 @@
"templating"
],
"time": "2018-09-12T20:54:16+00:00"
},
{
"name": "symfony/polyfill-php56",
"version": "v1.11.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php56.git",
"reference": "f4dddbc5c3471e1b700a147a20ae17cdb72dbe42"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/f4dddbc5c3471e1b700a147a20ae17cdb72dbe42",
"reference": "f4dddbc5c3471e1b700a147a20ae17cdb72dbe42",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"symfony/polyfill-util": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.11-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php56\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"time": "2019-02-06T07:57:58+00:00"
},
{
"name": "symfony/polyfill-util",
"version": "v1.11.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-util.git",
"reference": "b46c6cae28a3106735323f00a0c38eccf2328897"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-util/zipball/b46c6cae28a3106735323f00a0c38eccf2328897",
"reference": "b46c6cae28a3106735323f00a0c38eccf2328897",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.11-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Util\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony utilities for portability of PHP codes",
"homepage": "https://symfony.com",
"keywords": [
"compat",
"compatibility",
"polyfill",
"shim"
],
"time": "2019-02-08T14:16:39+00:00"
}
],
"packages-dev": [
{
"name": "dasprid/enum",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/DASPRiD/Enum.git",
"reference": "631ef6e638e9494b0310837fa531bedd908fc22b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/DASPRiD/Enum/zipball/631ef6e638e9494b0310837fa531bedd908fc22b",
"reference": "631ef6e638e9494b0310837fa531bedd908fc22b",
"shasum": ""
},
"require-dev": {
"phpunit/phpunit": "^6.4",
"squizlabs/php_codesniffer": "^3.1"
},
"type": "library",
"autoload": {
"psr-4": {
"DASPRiD\\Enum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/"
}
],
"description": "PHP 7.1 enum implementation",
"keywords": [
"enum",
"map"
],
"time": "2017-10-25T22:45:27+00:00"
},
{
"name": "doctrine/instantiator",
"version": "1.0.5",
@ -2272,12 +2841,12 @@
"version": "v1.6.5",
"source": {
"type": "git",
"url": "https://github.com/mikey179/vfsStream.git",
"url": "https://github.com/bovigo/vfsStream.git",
"reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mikey179/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
"url": "https://api.github.com/repos/bovigo/vfsStream/zipball/d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
"reference": "d5fec95f541d4d71c4823bb5e30cf9b9e5b96145",
"shasum": ""
},
@ -3180,7 +3749,7 @@
}
],
"description": "Provides the functionality to compare PHP values for equality",
"homepage": "http://www.github.com/sebastianbergmann/comparator",
"homepage": "https://github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
@ -3282,7 +3851,7 @@
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
"homepage": "http://www.github.com/sebastianbergmann/environment",
"homepage": "https://github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
@ -3350,7 +3919,7 @@
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"homepage": "https://github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
@ -3402,7 +3971,7 @@
}
],
"description": "Snapshotting of global state",
"homepage": "http://www.github.com/sebastianbergmann/global-state",
"homepage": "https://github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
@ -3504,7 +4073,7 @@
}
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"homepage": "https://github.com/sebastianbergmann/recursion-context",
"time": "2016-11-19T07:33:16+00:00"
},
{
@ -3768,7 +4337,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.6.1",
"php": ">=7.0",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",

60
config/dbstructure.config.php Normal file → Executable file
View File

@ -34,10 +34,22 @@
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1304);
define('DB_UPDATE_VERSION', 1313);
}
return [
"2fa_recovery_codes" => [
"comment" => "Two-factor authentication recovery codes",
"fields" => [
"uid" => ["type" => "mediumint unsigned", "not null" => "1", "primary" => "1", "relation" => ["user" => "uid"], "comment" => "User ID"],
"code" => ["type" => "varchar(50)", "not null" => "1", "primary" => "1", "comment" => "Recovery code string"],
"generated" => ["type" => "datetime", "not null" => "1", "comment" => "Datetime the code was generated"],
"used" => ["type" => "datetime", "comment" => "Datetime the code was used"],
],
"indexes" => [
"PRIMARY" => ["uid", "code"]
]
],
"addon" => [
"comment" => "registered addons",
"fields" => [
@ -74,6 +86,7 @@ return [
"alias" => ["type" => "varchar(255)", "comment" => ""],
"pubkey" => ["type" => "text", "comment" => ""],
"baseurl" => ["type" => "varchar(255)", "comment" => "baseurl of the ap contact"],
"generator" => ["type" => "varchar(255)", "comment" => "Name of the contact's system"],
"updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""]
],
"indexes" => [
@ -180,14 +193,16 @@ return [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
"uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "relation" => ["user" => "uid"], "comment" => "Owner User id"],
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
"updated" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => "Date of last contact update"],
"self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 if the contact is the user him/her self"],
"remote_self" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
"rel" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "The kind of the relation between the user and the contact"],
"duplex" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
"network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network protocol of the contact"],
"network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Network of the contact"],
"protocol" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Protocol of the contact"],
"name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Name that this contact is known by"],
"nick" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Nick- and user name of the contact"],
"location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"location" => ["type" => "varchar(255)", "default" => "", "comment" => ""],
"about" => ["type" => "text", "comment" => ""],
"keywords" => ["type" => "text", "comment" => "public keywords (interests) of the contact"],
"gender" => ["type" => "varchar(32)", "not null" => "1", "default" => "", "comment" => ""],
@ -226,7 +241,8 @@ return [
"term-date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
"last-item" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "date of the last post"],
"priority" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
"blocked" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => ""],
"blocked" => ["type" => "boolean", "not null" => "1", "default" => "1", "comment" => "Node-wide block status"],
"block_reason" => ["type" => "text", "comment" => "Node-wide block reason"],
"readonly" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "posts of the contact are readonly"],
"writable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
"forum" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a forum"],
@ -529,6 +545,21 @@ return [
"hook_file_function" => ["UNIQUE", "hook", "file", "function"],
]
],
"inbox-status" => [
"comment" => "Status of ActivityPub inboxes",
"fields" => [
"url" => ["type" => "varbinary(255)", "not null" => "1", "primary" => "1", "comment" => "URL of the inbox"],
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Creation date of this entry"],
"success" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last successful delivery"],
"failure" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last failed delivery"],
"previous" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Previous delivery date"],
"archive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Is the inbox archived?"],
"shared" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Is it a shared inbox?"]
],
"indexes" => [
"PRIMARY" => ["url"]
]
],
"intro" => [
"comment" => "",
"fields" => [
@ -1103,26 +1134,6 @@ return [
"next_try" => ["next_try"],
]
],
"queue" => [
"comment" => "Queue for messages that couldn't be delivered",
"fields" => [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
"cid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "relation" => ["contact" => "id"], "comment" => "Message receiver"],
"network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => "Receiver's network"],
"guid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Unique GUID of the message"],
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date, when the message was created"],
"last" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of last trial"],
"next" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Next retrial date"],
"retrial" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => "Retrial counter"],
"content" => ["type" => "mediumtext", "comment" => ""],
"batch" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
],
"indexes" => [
"PRIMARY" => ["id"],
"last" => ["last"],
"next" => ["next"],
]
],
"register" => [
"comment" => "registrations requiring admin approval",
"fields" => [
@ -1195,6 +1206,7 @@ return [
],
"indexes" => [
"PRIMARY" => ["tid"],
"term_type" => ["term(64)", "type"],
"oid_otype_type_term" => ["oid", "otype", "type", "term(32)"],
"uid_otype_type_term_global_created" => ["uid", "otype", "type", "term(32)", "global", "created"],
"uid_otype_type_url" => ["uid", "otype", "type", "url(64)"],

View File

@ -72,6 +72,10 @@ return [
// Deny public access to the local user directory.
'block_local_dir' => false,
// cron_interval (Integer)
// Minimal period in minutes between two calls of the "Cron" worker job.
'cron_interval' => 5,
// cache_driver (database|memcache|memcached|redis)
// Whether to use Memcache or Memcached or Redis to store temporary cache.
'cache_driver' => 'database',
@ -214,6 +218,10 @@ return [
// If activated, all hashtags will point to the local server.
'local_tags' => false,
// logger_config (String)
// Sets the logging adapter of Friendica globally (monolog, syslog, stream)
'logger_config' => 'stream',
// max_batch_queue (Integer)
// Maximum number of batched queue items for a single contact before subsequent messages are discarded.
'max_batch_queue' => 1000,
@ -335,6 +343,14 @@ return [
// Port number of the redis daemon.
'redis_port' => 6379,
// redis_db (Integer)
// The sub-database of redis (0 - 15 possible sub-databases)
'redis_db' => 0,
// redis_password (String)
// The authentication password for the redis database
'redis_password' => null,
// session_handler (database|cache|native)
// Whether to use Cache to store session data or to use PHP native session storage.
'session_handler' => 'database',
@ -373,11 +389,6 @@ return [
// Maximum number of posts that a user can send per month with the API. 0 to disable monthly throttling.
'throttle_limit_month' => 0,
// urlpath (String)
// If you are using a subdirectory of your domain you will need to put the relative path (from the root of your domain) here.
// For instance if your URL is 'http://example.com/directory/subdirectory', set urlpath to 'directory/subdirectory'.
'urlpath' => '',
// username_min_length (Integer)
// The minimum character length a username can be.
// This length is check once the username has been trimmed and multiple spaces have been collapsed into one.

View File

@ -74,7 +74,7 @@ return [
// logfile (String)
// The logfile for storing logs.
// Can be a full path or a relative path to the Friendica home directory
'logfile' => 'friendica.log',
'logfile' => 'log/friendica.log',
// loglevel (String)
// The loglevel for all logs.

View File

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2019.03-dev (The Tazmans Flax-lily)
-- DB_UPDATE_VERSION 1300
-- Friendica 2019.06-dev (Dalmatian Bellflower)
-- DB_UPDATE_VERSION 1311
-- ------------------------------------------
@ -40,6 +40,7 @@ CREATE TABLE IF NOT EXISTS `apcontact` (
`alias` varchar(255) COMMENT '',
`pubkey` text COMMENT '',
`baseurl` varchar(255) COMMENT 'baseurl of the ap contact',
`generator` varchar(255) COMMENT 'Name of the contact\'s system',
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
PRIMARY KEY(`url`),
INDEX `addr` (`addr`(32)),
@ -138,14 +139,16 @@ CREATE TABLE IF NOT EXISTS `contact` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`updated` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last contact update',
`self` boolean NOT NULL DEFAULT '0' COMMENT '1 if the contact is the user him/her self',
`remote_self` boolean NOT NULL DEFAULT '0' COMMENT '',
`rel` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'The kind of the relation between the user and the contact',
`duplex` boolean NOT NULL DEFAULT '0' COMMENT '',
`network` char(4) NOT NULL DEFAULT '' COMMENT 'Network protocol of the contact',
`network` char(4) NOT NULL DEFAULT '' COMMENT 'Network of the contact',
`protocol` char(4) NOT NULL DEFAULT '' COMMENT 'Protocol of the contact',
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name that this contact is known by',
`nick` varchar(255) NOT NULL DEFAULT '' COMMENT 'Nick- and user name of the contact',
`location` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`location` varchar(255) DEFAULT '' COMMENT '',
`about` text COMMENT '',
`keywords` text COMMENT 'public keywords (interests) of the contact',
`gender` varchar(32) NOT NULL DEFAULT '' COMMENT '',
@ -470,6 +473,20 @@ CREATE TABLE IF NOT EXISTS `hook` (
UNIQUE INDEX `hook_file_function` (`hook`,`file`,`function`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='addon hook registry';
--
-- TABLE inbox-status
--
CREATE TABLE IF NOT EXISTS `inbox-status` (
`url` varbinary(255) NOT NULL COMMENT 'URL of the inbox',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation date of this entry',
`success` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last successful delivery',
`failure` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last failed delivery',
`previous` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Previous delivery date',
`archive` boolean NOT NULL DEFAULT '0' COMMENT 'Is the inbox archived?',
`shared` boolean NOT NULL DEFAULT '0' COMMENT 'Is it a shared inbox?',
PRIMARY KEY(`url`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Status of ActivityPub inboxes';
--
-- TABLE intro
--
@ -879,7 +896,7 @@ CREATE TABLE IF NOT EXISTS `photo` (
`deny_gid` mediumtext COMMENT 'Access Control - list of denied groups',
`backend-class` tinytext COMMENT 'Storage backend class',
`backend-ref` text COMMENT 'Storage backend data reference',
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'edited timestamp',
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
PRIMARY KEY(`id`),
INDEX `contactid` (`contact-id`),
INDEX `uid_contactid` (`uid`,`contact-id`),
@ -1013,25 +1030,6 @@ CREATE TABLE IF NOT EXISTS `push_subscriber` (
INDEX `next_try` (`next_try`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Used for OStatus: Contains feed subscribers';
--
-- TABLE queue
--
CREATE TABLE IF NOT EXISTS `queue` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Message receiver',
`network` char(4) NOT NULL DEFAULT '' COMMENT 'Receiver\'s network',
`guid` varchar(255) NOT NULL DEFAULT '' COMMENT 'Unique GUID of the message',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date, when the message was created',
`last` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of last trial',
`next` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Next retrial date',
`retrial` tinyint NOT NULL DEFAULT 0 COMMENT 'Retrial counter',
`content` mediumtext COMMENT '',
`batch` boolean NOT NULL DEFAULT '0' COMMENT '',
PRIMARY KEY(`id`),
INDEX `last` (`last`),
INDEX `next` (`next`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Queue for messages that couldn\'t be delivered';
--
-- TABLE register
--
@ -1099,6 +1097,7 @@ CREATE TABLE IF NOT EXISTS `term` (
`global` boolean NOT NULL DEFAULT '0' COMMENT '',
`uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'User id',
PRIMARY KEY(`tid`),
INDEX `term_type` (`term`(64),`type`),
INDEX `oid_otype_type_term` (`oid`,`otype`,`type`,`term`(32)),
INDEX `uid_otype_type_term_global_created` (`uid`,`otype`,`type`,`term`(32),`global`,`created`),
INDEX `uid_otype_type_url` (`uid`,`otype`,`type`,`url`(64)),
@ -1270,13 +1269,12 @@ CREATE TABLE IF NOT EXISTS `workerqueue` (
`retrial` tinyint NOT NULL DEFAULT 0 COMMENT 'Retrial counter',
`done` boolean NOT NULL DEFAULT '0' COMMENT 'Marked 1 when the task was done - will be deleted later',
PRIMARY KEY(`id`),
INDEX `pid` (`pid`),
INDEX `parameter` (`parameter`(64)),
INDEX `priority_created_next_try` (`priority`,`created`,`next_try`),
INDEX `done_priority_executed_next_try` (`done`,`priority`,`executed`,`next_try`),
INDEX `done_executed_next_try` (`done`,`executed`,`next_try`),
INDEX `done_parameter` (`done`,`parameter`(64)),
INDEX `done_executed` (`done`,`executed`),
INDEX `done_priority_created` (`done`,`priority`,`created`),
INDEX `done_priority_next_try` (`done`,`priority`,`next_try`),
INDEX `done_next_try` (`done`,`next_try`)
INDEX `done_pid_next_try` (`done`,`pid`,`next_try`),
INDEX `done_pid_priority_created` (`done`,`pid`,`priority`,`created`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Background tasks queue entries';
--

View File

@ -7,48 +7,65 @@ Please see the sample addon 'randplace' for a working example of using some of t
Addons work by intercepting event hooks - which must be registered.
Modules work by intercepting specific page requests (by URL path).
Addon names cannot contain spaces or other punctuation and are used as filenames and function names.
You may supply a "friendly" name within the comment block.
Each addon must contain both an install and an uninstall function based on the addon name.
For instance "addon1name_install()".
These two functions take no arguments and are usually responsible for registering (and unregistering) event hooks that your addon will require.
The install and uninstall functions will also be called (i.e. re-installed) if the addon changes after installation.
## Naming
Addon names are used in file paths and functions names, and as such:
- Can't contain spaces or punctuation.
- Can't start with a number.
## Metadata
You can provide human-readable information about your addon in the first multi-line comment of your addon file.
Here's the structure:
```php
/**
* Name: {Human-readable name}
* Description: {Short description}
* Version: 1.0
* Author: {Author1 Name}
* Author: {Author2 Name} <{Author profile link}>
* Maintainer: {Maintainer1 Name}
* Maintainer: {Maintainer2 Name} <{Maintainer profile link}>
* Status: {Unsupported|Arbitrary status}
*/
```
You can also provide a longer documentation in a `README` or `README.md` file.
The latter will be converted from Markdown to HTML in the addon detail page.
## Install/Uninstall
If your addon uses hooks, they have to be registered in a `<addon>_install()` function.
This function also allows to perform arbitrary actions your addon needs to function properly.
Uninstalling an addon automatically unregisters any hook it registered, but if you need to provide specific uninstallation steps, you can add them in a `<addon>_uninstall()` function.
The install and uninstall functions will be called (i.e. re-installed) if the addon changes after installation.
Therefore your uninstall should not destroy data and install should consider that data may already exist.
Future extensions may provide for "setup" amd "remove".
Addons should contain a comment block with the four following parameters:
/*
* Name: My Great Addon
* Description: This is what my addon does. It's really cool.
* Version: 1.0
* Author: John Q. Public <john@myfriendicasite.com>
*/
Please also add a README or README.md file to the addon directory.
It will be displayed in the admin panel and should include some further information in addition to the header information.
## PHP addon hooks
Register your addon hooks during installation.
\Friendica\Core\Hook::register($hookname, $file, $function);
$hookname is a string and corresponds to a known Friendica PHP hook.
`$hookname` is a string and corresponds to a known Friendica PHP hook.
$file is a pathname relative to the top-level Friendica directory.
This *should* be 'addon/*addon_name*/*addon_name*.php' in most cases.
`$file` is a pathname relative to the top-level Friendica directory.
This *should* be 'addon/*addon_name*/*addon_name*.php' in most cases and can be shortened to `__FILE__`.
$function is a string and is the name of the function which will be executed when the hook is called.
`$function` is a string and is the name of the function which will be executed when the hook is called.
### Arguments
Your hook callback functions will be called with at least one and possibly two arguments
function myhook_function(App $a, &$b) {
function <addon>_<hookname>(App $a, &$b) {
}
If you wish to make changes to the calling data, you must declare them as reference variables (with `&`) during function declaration.
#### $a
@ -67,6 +84,12 @@ $b can be called anything you like.
This is information specific to the hook currently being processed, and generally contains information that is being immediately processed or acted on that you can use, display, or alter.
Remember to declare it with `&` if you wish to alter it.
## Admin settings
Your addon can provide user-specific settings via the `addon_settings` PHP hook, but it can also provide node-wide settings in the administration page of your addon.
Simply declare a `<addon>_addon_admin(App $a)` function to display the form and a `<addon>_addon_admin_post(App $a)` function to process the data from the form.
## Global stylesheets
If your addon requires adding a stylesheet on all pages of Friendica, add the following hook:
@ -132,11 +155,11 @@ No additional data is provided.
## Modules
Addons may also act as "modules" and intercept all page requests for a given URL path.
In order for a addon to act as a module it needs to define a function "addon_name_module()" which takes no arguments and needs not do anything.
In order for a addon to act as a module it needs to declare an empty function `<addon>_module()`.
If this function exists, you will now receive all page requests for "http://my.web.site/addon_name" - with any number of URL components as additional arguments.
If this function exists, you will now receive all page requests for `https://my.web.site/<addon>` - with any number of URL components as additional arguments.
These are parsed into an array $a->argv, with a corresponding $a->argc indicating the number of URL components.
So http://my.web.site/addon/arg1/arg2 would look for a module named "addon" and pass its module functions the $a App structure (which is available to many components).
So `https://my.web.site/addon/arg1/arg2` would look for a module named "addon" and pass its module functions the $a App structure (which is available to many components).
This will include:
```php
@ -144,9 +167,9 @@ $a->argc = 3
$a->argv = array(0 => 'addon', 1 => 'arg1', 2 => 'arg2');
```
Your module functions will often contain the function addon_name_content(App $a), which defines and returns the page body content.
They may also contain addon_name_post(App $a) which is called before the _content function and typically handles the results of POST forms.
You may also have addon_name_init(App $a) which is called very early on and often does module initialisation.
To display a module page, you need to declare the function `<addon>_content(App $a)`, which defines and returns the page body content.
They may also contain `<addon>_post(App $a)` which is called before the `<addon>_content` function and typically handles the results of POST forms.
You may also have `<addon>_init(App $a)` which is called before `<addon>_content` and should include common logic to your module.
## Templates
@ -160,7 +183,7 @@ In your code, like in the function addon_name_content(), load the template file
```php
# load template file. first argument is the template name,
# second is the addon path relative to friendica top folder
$tpl = Renderer::getMarkupTemplate('mytemplate.tpl', 'addon/addon_name/');
$tpl = Renderer::getMarkupTemplate('mytemplate.tpl', __DIR__);
# apply template. first argument is the loaded template,
# second an array of 'name' => 'values' to pass to template
@ -335,6 +358,7 @@ Called from `Emailer::send()` before building the mime message.
- **htmlVersion**: html version of the message
- **textVersion**: text only version of the message
- **additionalMailHeader**: additions to the smtp mail header
- **sent**: default false, if set to true in the hook, the default mailer will be skipped.
### emailer_send
Called before calling PHP's `mail()`.
@ -344,6 +368,7 @@ Called before calling PHP's `mail()`.
- **subject**
- **body**
- **headers**
- **sent**: default false, if set to true in the hook, the default mailer will be skipped.
### load_config
Called during `App` initialization to allow addons to load their own configuration file(s) with `App::loadConfigFile()`.
@ -411,6 +436,34 @@ Hook data:
visitor => array with the contact record of the visitor
url => the query string
### jot_networks
Called when displaying the post permission screen.
Hook data is a list of form fields that need to be displayed along the ACL.
Form field array structure is:
- **type**: `checkbox` or `select`.
- **field**: Standard field data structure to be used by `field_checkbox.tpl` and `field_select.tpl`.
For `checkbox`, **field** is:
- [0] (String): Form field name; Mandatory.
- [1]: (String): Form field label; Optional, default is none.
- [2]: (Boolean): Whether the checkbox should be checked by default; Optional, default is false.
- [3]: (String): Additional help text; Optional, default is none.
- [4]: (String): Additional HTML attributes; Optional, default is none.
For `select`, **field** is:
- [0] (String): Form field name; Mandatory.
- [1] (String): Form field label; Optional, default is none.
- [2] (Boolean): Default value to be selected by default; Optional, default is none.
- [3] (String): Additional help text; Optional, default is none.
- [4] (Array): Associative array of options. Item key is option value, item value is option label; Mandatory.
### route_collection
Called just before dispatching the router.
Hook data is a `\FastRoute\RouterCollector` object that should be used to add addon routes pointing to classes.
**Notice**: The class whose name is provided in the route handler must be reachable via auto-loader.
## Complete list of hook callbacks
Here is a complete list of all hook callbacks with file locations (as of 24-Sep-2018). Please see the source for details of any hooks not documented above.
@ -586,6 +639,7 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
Hook::callAll('load_config');
Hook::callAll('head');
Hook::callAll('footer');
Hook::callAll('route_collection');
### src/Model/Item.php
@ -661,11 +715,6 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
Hook::callAll('notifier_end', $target_item);
### src/Worker/Queue.php
Hook::callAll('queue_predeliver', $r);
Hook::callAll('queue_deliver', $params);
### src/Module/Login.php
Hook::callAll('authenticate', $addon_auth);

View File

@ -126,16 +126,15 @@ A **hidden contact** will not be displayed in any "friend list" (except to you).
However a hidden contact will appear normally in conversations and this may expose his/her hidden status to anybody who can see the conversation.
<a name="removed"></a>
### What happens when an account is removed? Is it truly deleted?
### What happens when an account is removed?
If you delete your account, we will immediately remove all your content on **your** server.
If you remove your account, it will be scheduled for permanent deletion in *seven days*.
As soon as you activate the deletion process you won't be able to login any more.
Only the administrator of your node can halt this process prior to permanent deletion.
Then Friendica issues requests to all your contacts to remove you.
This will also remove you from the global directory.
Doing this requires your account and profile still to be "partially" available for up to 24 hours in order to establish contact with all your friends.
We can block it in several ways so that it appears empty and all profile information erased, but will then wait for 24 hours (or after all of your contacts have been notified) before we can physically remove it.
After that, your account is deleted.
After the elapsed time of seven days, all your posts, messages, photos, and personal information stored on your node will be deleted.
Your node will also issue removal requests to all your contacts; this will also remove your profile from the global directory if you are listed.
Your username cannot be reissued for future sign-ups for security reasons.
<a name="hashtag"></a>
### Can I follow a hashtag?

View File

@ -25,16 +25,21 @@ Requirements
---
* Apache with mod-rewrite enabled and "Options All" so you can use a local .htaccess file
* PHP 5.6.1+ (PHP 7 is recommended for performance)
* PHP 7+ (PHP 7.1+ is recommended for performance and official support)
* PHP *command line* access with register_argc_argv set to true in the php.ini file
* Curl, GD, PDO, MySQLi, hash, xml, zip and OpenSSL extensions
* The POSIX module of PHP needs to be activated (e.g. [RHEL, CentOS](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) have disabled it)
* some form of email server or email gateway such that PHP mail() works
* Mysql 5.5.3+ or an equivalent alternative for MySQL (MariaDB, Percona Server etc.)
* Mysql 5.6+ or an equivalent alternative for MySQL (MariaDB, Percona Server etc.)
* the ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows) (Note: other options are presented in Section 7 of this document.)
* Installation into a top-level domain or sub-domain (without a directory/path component in the URL) is preferred. Directory paths will not be as convenient to use and have not been thoroughly tested.
* If your hosting provider doesn't allow Unix shell access, you might have trouble getting everything to work.
Optional
---
* PHP ImageMagick extension (php-imagick) for animated GIF support.
Installation procedure
---

View File

@ -3,17 +3,19 @@ If you're not already logged in, do so in the frame below.
Once you've logged in (or if you are already logged in), you'll now be looking at your profile page.
This is a bit like your Facebook wall.
This is a bit like a Facebook wall.
It's where all your status messgages are kept, and where your friends come to post on your wall.
To write your status, simply click in the box that says "share".
When you do this, the box will expand.
You can see some formatting options at the top such as Bold, Italics and Underline, as well as ways to add links and pictures.
At the bottom you'll find some more links.
To write your status, simply click on the Pencil & Paper icon in the top right (in the Frio theme), or click in the box that says "share" (other themes).
When you do this, the posting dialog box will appear or the share box will expand.
You can see some formatting options such as Bold, Italics and Underline, as well as ways to add links, pictures (dependent on the theme), and a paperclip icon to attach or embed content.
You can use these to upload pictures and files from your computer, share websites with a bit of preview text, or embed video and audio files from elsewhere on the web.
With the Frio theme, the browser tab can be used to upload and post media from your account.
You can also set your post location here.
Once you've finished writing your post, click on the padlock icon to select who can see it.
If you do not use the padlock icon, your post will be public.
Once you've finished writing your post, click on the padlock icon or permissions tab to select who can see it.
If you do not change anything, your post will be public.
This means it will appear to anybody who views your profile, and in the community tab if your site has it enabled, as well as in the network tab of any of your contacts.
Play around with this a bit, then when you're ready to move on, we'll take a look at the <a href="help/Quick-Start-network">Network Tab</a>

View File

@ -169,7 +169,6 @@ Your local users will always have access to both pages.
Comma separated list of domains which are allowed to establish friendships with this site.
Wildcards are accepted.
(Wildcard support on Windows platforms requires PHP5.3).
By default, any (valid) domain may establish friendships with this site.
This is useful if you want to setup a closed network for educational groups, cooperatives and similar communities that don't want to communicate with the rest of the network.
@ -179,7 +178,6 @@ This is useful if you want to setup a closed network for educational groups, coo
Comma separated list of domains which are allowed in email addresses for registrations to this site.
This can lockout those who are not part of this organisation from registering here.
Wildcards are accepted.
(Wildcard support on Windows platforms requires PHP5.3).
By default, any (valid) email address is allowed in registrations.
#### Allow Users to set remote_self

View File

@ -11,71 +11,85 @@ Creating posts
Here you can find an overview of the different ways to create and edit your post.
One click on "Share" text box on top of your Home or Network page, and the post editor shows up:
One click on the Pencil & Paper icon in the top right of your Home or Network page, or the "Share" text box, and the post editor shows up.
Below are examples of the post editor in 3 of Friendica's common themes:
<figure>
<img src="doc/img/friendica_editor.png" alt="default editor">
<figcaption>Default post editor, with default Friendica theme (duepuntozero)</figcaption>
<img src="doc/img/editor_frio.png" alt="frio editor">
<figcaption>Post editor, with the <b>Frio</b> (popular default) theme.</figcaption>
</figure>
<p style="clear:both;"></p>
<figure>
<img src="doc/img/editor_vier.png" alt="vier editor" width="675">
<figcaption>Post editor, with the <b>Vier</b> theme.</figcaption>
</figure>
<p style="clear:both;"></p>
<figure>
<img src="doc/img/editor_dpzero.png" alt="duepuntozero editor">
<figcaption>Post editor, with the <b>Duepuntozero</b> theme.</figcaption>
</figure>
Post title is optional, you can set it clicking on "Set title".
Post title is optional, you can set it by clicking on "Set title".
Posts can optionally be in one or more categories. Write categories name separated by a comma to file your new post.
Posts can optionally be in one or more categories. Write category names separated by a comma to file your new post.
The Big Empty Textarea is where you write your new post.
You can simply enter your text there and click "Share" button, and your new post will be public on your profile page and shared to your contact.
You can simply enter your text there and click the "Share" button, and your new post will be public on your profile page and shared to your contact.
If plain text is not so exciting to you, Friendica understands BBCode to spice up your posts: bold, italic, images, links, lists..
See [BBCode tags reference](help/BBCode) page to see all what you can do.
The icons under the text area are there to help you to write posts quickly:
The icons under the text area are there to help you to write posts quickly, but vary depending on the theme:
<img src="doc/img/camera.png" width="32" height="32" alt="editor" align="left" style="padding-bottom: 20px;"> Upload a picture from your computer. The image will be uploaded and correct bbcode tag will be added to your post.*
With the Frio theme, the Underline, Italics and Bold buttons should be self-explanatory.
<img src="doc/img/camera.png" width="32" height="32" alt="editor" align="left"> Upload a picture from your computer. The image will be uploaded and correct bbcode tag will be added to your post.* In the Frio theme, use the <b>Browser</b> tab instead to Upload and/or attach content to your post.
<p style="clear:both;"></p>
<img src="doc/img/paper_clip.png" width="32" height="32" alt="paper_clip" align="left"> Add files from your computer. Same as picture, but for generic attachment to the post.*
<img src="doc/img/paper_clip.png" width="32" height="32" alt="paper_clip" align="left"> This depends on the theme: For Frio, this is to attach remote content - put in a URL to embed in your post, including video or audio content. For other themes: Add files from your computer. Same as picture, but for generic attachment to the post.*
<p style="clear:both;"></p>
<img src="doc/img/chain.png" width="32" height="32" alt="chain" align="left"> Add a web address (url). Enter an url and Friendica will add to your post a link to the url and an excerpt from the web site, if possible.
<img src="doc/img/chain.png" width="32" height="32" alt="chain" align="left"> Add a web address (url). Enter a URL and Friendica will add to your post a link to the url and an excerpt from the web site, if possible.
<p style="clear:both;"></p>
<img src="doc/img/video.png" width="32" height="32" alt="video" align="left"> Add a video. Enter the url to a video (ogg) or to a video page on youtube or vimeo, and it will be embedded in your post with a preview. Friendica is using [HTML5](http://en.wikipedia.org/wiki/HTML5_video) for embedding content. Therefore, the supported files are depending on your browser and operating system (OS). Some filetypes are WebM, MP4 and OGG.*
<img src="doc/img/video.png" width="32" height="32" alt="video" align="left"> Add a video. Enter the url to a video (ogg) or to a video page on youtube or vimeo, and it will be embedded in your post with a preview. (In the Frio theme, this is done with the paperclip as mentioned above.) Friendica is using [HTML5](http://en.wikipedia.org/wiki/HTML5_video) for embedding content. Therefore, the supported files are depending on your browser and operating system (OS). Some filetypes are WebM, MP4 and OGG.*
<p style="clear:both;"></p>
<img src="doc/img/mic.png" width="32" height="32" alt="mic" align="left" style="padding-bottom: 20px;"> Add an audio. Same as video, but for audio. Depending on your browser and operation system MP3, OGG and AAC are supported. Additionally, you are able to add URLs from audiohosters like Soundcloud.
<img src="doc/img/mic.png" width="32" height="32" alt="mic" align="left"> Add an audio. Same as video, but for audio. Depending on your browser and operation system MP3, OGG and AAC are supported. Additionally, you are able to add URLs from audiohosters like Soundcloud.
<p style="clear:both;"></p>
<img src="doc/img/globe.png" width="32" height="32" alt="globe" align="left"> Set your geographic location. This location will be added into a Google Maps search. That's why a note like "New York" or "10004" is already enough.
<img src="doc/img/globe.png" width="32" height="32" alt="globe" align="left"> <b>Or</b> <img src="doc/img/frio_location.png" width="32" height="32" alt="location" align="none"> Set your geographic location. This location will be added into a Google Maps search. That's why a note like "New York" or "10004" is already enough.
<p style="clear:both;"></p>
<br />
<p style="clear:both;"></p>
<i>* how to [upload](help/FAQ#upload) files</i>
Those icons can change with themes. Some examples:
These icons can change depending on the theme. Some examples:
<table>
<tr>
<td>Darkbubble: </td>
<td>Vier: </td>
<td><img src="doc/img/vier_icons.png" alt="vier.png" style="vertical-align:middle;"></td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Smoothly: </td>
<td><img src="doc/img/editor_darkbubble.png" alt="darkbubble.png" style="vertical-align:middle;"></td>
<td><i>(inkl. smoothly, testbubble)</i></td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Frost: </td>
<td><img src="doc/img/editor_frost.png" alt="frost.png" style="vertical-align:middle;"> </td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Vier: </td>
<td><img src="doc/img/editor_vier.png" alt="vier.png" style="vertical-align:middle;"></td>
<td><i>(inkl. dispy)</i></td>
</tr>
</table>
<p style="clear:both;">&nbsp;</p>
<i><b>*</b> how to [upload](help/FAQ#upload) files</i>
<p style="clear:both;">&nbsp;</p>
**<img src="doc/img/lock.png" width="32" height="32" alt="lock icon" style="vertical-align:middle;"> The lock**
**<img src="doc/img/lock.png" width="32" height="32" alt="lock icon" style="vertical-align:middle;"> The Lock / Permissions**
The last button, the Lock, is the most important feature in Friendica. If the lock is open, your post will be public, and will shows up on your profile page when strangers visit it.
In Frio, the Permissions tab, or in other themes, the Lock button, is the most important feature in Friendica. If the lock is open, your post will be public, and will show up on your profile page when strangers visit it.
Click on it and the *Permission settings* window (aka "*Access Control Selector*" or "*ACL Selector*") pops up. There you can select who can see the post.
@ -95,4 +109,4 @@ Click again on "show" or "don't show" to switch it off.
You can search for contacts or groups with the search box.
See also [Group and Privacy](help/Groups-and-Privacy)
See also [Group and Privacy](help/Groups-and-Privacy)

View File

@ -0,0 +1,60 @@
# Configuring two-factor authentication
* [Home](help)
You can configure two-factor authentication using a mobile app.
A time-based one-time password (TOTP) application automatically generates an authentication code that changes after a certain period of time.
**Tip**: To configure authentication via TOTP on multiple devices, during setup, scan the QR code using each device at the same time.
If 2FA is already enabled and you want to add another device, you must re-configure 2FA from your security settings.
## Enabling two-factor authentication
### 1. Download an authenticator app
Any authenticator app should work with Friendica.
Notheless, we recommend:
- For iOS, [Matt Rubin's MIT-licensed Authenticator app](https://mattrubin.me/authenticator).
- For Android, [andOTP](https://github.com/andOTP/andOTP).
### 2. Record your one-use recovery codes
From your [two-factor authentication user settings](/settings/2fa), enter your password and click on "Enable two-factor authentication".
You will be presented with a list of one-use recovery codes.
Please save those in the same place you are saving your Friendica password (ideally, in a password manager like [KeePass](https://keepass.info)).
When you're done, click on "Next".
### 3. Setup your authenticator app
You have three methods to setup your authenticator app:
1. Scan the QR Code with your device camera.
This will automatically configure your account on the app.
2. Click/tap on the provided **totp://** URl.
Ideally your authenticator app should be called with this URL and set up your account.
3. Enter your account settings manually.
Friendica is using default settings for token type, code digit count and hashing algorithm but you may be required to enter them in your app.
**Tip**: If you have multiple devices, configure them all at this point.
Then verify your app is correctly configured by submitting a code provided by your app.
This will conclude two-factor authentication configuration.
**Note:** If you leave this screen at any point without having submitted a verification code, two-factor authentication won't be enabled on your account.
To complete the configuration, just come back to your [two-factor authentication user settings](/settings/2fa) and click on "Finish configuration" after entering your current password.
## Disabling two-factor authentication
You can disable two-factor authentication at any time by going to your [two-factor authentication user settings](/settings/2fa) and click on "Disable two-factor authentication" after entering your current password.
You should remove your Friendica account from your authenticator app as it won't work again even if you reenable two-factor authentication.
In this case you will have to configure your authenticator app again using the process above.
## Managing your one-time recovery codes
When two-factor authentication is enabled, you can show your recovery codes, including the ones you've already used.
You can freely regenerate a new set of fresh recovery codes, just be sure to replace the previous ones where you saved them as they won't be active anymore.

View File

@ -434,11 +434,6 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
Hook::callAll('notifier_end', $target_item);
### src/Worker/Queue.php
Hook::callAll('queue_predeliver', $r);
Hook::callAll('queue_deliver', $params);
### src/Module/Login.php
Hook::callAll('authenticate', $addon_auth);

View File

@ -28,12 +28,12 @@ Requirements
---
* Apache mit einer aktiverten mod-rewrite-Funktion und dem Eintrag "Options All", so dass du die lokale .htaccess-Datei nutzen kannst
* PHP 5.6.1+ (PHP 7 ist aufgrund der Performance empfohlen)
* PHP 7+ (PHP 7.1+ wird für Performance und offiziellen Support empfohlen)
* PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei
* Curl, GD, PDO, MySQLi, xml, zip und OpenSSL-Erweiterung
* Das POSIX Modul muss aktiviert sein ([CentOS, RHEL](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) haben dies z.B. deaktiviert)
* etwas in der Art eines Email-Servers oder eines Gateways wie PHP mail()
* Mysql 5.5.3+ (oder eine äquivalente Alternative: MariaDB, Percona Server etc.)
* Mysql 5.6+ (oder eine äquivalente Alternative: MariaDB, Percona Server etc.)
* die Möglichkeit, wiederkehrende Aufgaben mit cron (Linux/Mac) oder "Scheduled Tasks" einzustellen (Windows) [Beachte: andere Optionen sind in Abschnitt 7 dieser Dokumentation zu finden]
* Installation in einer Top-Level-Domain oder Subdomain (ohne eine Verzeichnis/Pfad-Komponente in der URL) wird bevorzugt. Verzeichnispfade sind für diesen Zweck nicht so günstig und wurden auch nicht ausführlich getestet.

View File

@ -160,7 +160,7 @@ Angemeldete Nutzer des Knotens können grundsätzlich beide Seiten verwenden.
#### Erlaubte Domains für Kontakte
Kommagetrennte Liste von Domains, welche eine Freundschaft mit dieser Seite eingehen dürfen.
Wildcards werden akzeptiert (Wildcard-Unterstützung unter Windows benötigt PHP5.3) Standardmäßig sind alle gültigen Domains erlaubt.
Wildcards werden akzeptiert Standardmäßig sind alle gültigen Domains erlaubt.
Mit dieser Option kann man einfach geschlossene Netzwerke, z.B. im schulischen Bereich aufbauen, aus denen nicht mit dem Rest des Netzwerks kommuniziert werden soll.
@ -168,7 +168,7 @@ Mit dieser Option kann man einfach geschlossene Netzwerke, z.B. im schulischen B
Kommagetrennte Liste von Domains, welche bei der Registrierung als Part der Email-Adresse erlaubt sind.
Das grenzt Leute aus, die nicht Teil der Gruppe oder Organisation sind.
Wildcards werden akzeptiert (Wildcard-Unterstützung unter Windows benötigt PHP5.3) Standardmäßig sind alle gültigen Email-Adressen erlaubt.
Wildcards werden akzeptiert Standardmäßig sind alle gültigen Email-Adressen erlaubt.
#### Nutzern erlauben das remote_self Flag zu setzen

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
doc/img/frio_location.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

BIN
doc/img/vier_icons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -11,7 +11,6 @@ use Friendica\Content\ContactSelector;
use Friendica\Content\Feature;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Core\Authentication;
use Friendica\Core\Config;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
@ -19,6 +18,7 @@ use Friendica\Core\Logger;
use Friendica\Core\NotificationsManager;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\Session;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
@ -250,7 +250,7 @@ function api_login(App $a)
throw new UnauthorizedException("This API requires login");
}
Authentication::setAuthenticatedSessionForUser($record);
Session::setAuthenticatedForUser($a, $record);
$_SESSION["allow_api"] = true;
@ -361,10 +361,10 @@ function api_call(App $a)
}
}
Logger::warning(API_LOG_PREFIX . 'not implemented', ['module' => 'api', 'action' => 'call']);
Logger::warning(API_LOG_PREFIX . 'not implemented', ['module' => 'api', 'action' => 'call', 'query' => $a->query_string]);
throw new NotImplementedException();
} catch (HTTPException $e) {
header("HTTP/1.1 {$e->httpcode} {$e->httpdesc}");
header("HTTP/1.1 {$e->getCode()} {$e->httpdesc}");
return api_error($type, $e);
}
}
@ -384,7 +384,7 @@ function api_error($type, $e)
/// @TODO: https://dev.twitter.com/overview/api/response-codes
$error = ["error" => $error,
"code" => $e->httpcode . " " . $e->httpdesc,
"code" => $e->getCode() . " " . $e->httpdesc,
"request" => $a->query_string];
$return = api_format_data('status', $type, ['status' => $error]);
@ -611,7 +611,7 @@ function api_get_user(App $a, $contact_id = null)
'name' => $contact["name"],
'screen_name' => (($contact['nick']) ? $contact['nick'] : $contact['name']),
'location' => ($contact["location"] != "") ? $contact["location"] : ContactSelector::networkToName($contact['network'], $contact['url']),
'description' => $contact["about"],
'description' => HTML::toPlaintext(BBCode::toPlaintext($contact["about"])),
'profile_image_url' => $contact["micro"],
'profile_image_url_https' => $contact["micro"],
'profile_image_url_profile_size' => $contact["thumb"],
@ -690,7 +690,7 @@ function api_get_user(App $a, $contact_id = null)
'name' => (($uinfo[0]['name']) ? $uinfo[0]['name'] : $uinfo[0]['nick']),
'screen_name' => (($uinfo[0]['nick']) ? $uinfo[0]['nick'] : $uinfo[0]['name']),
'location' => $location,
'description' => $description,
'description' => HTML::toPlaintext(BBCode::toPlaintext($description)),
'profile_image_url' => $uinfo[0]['micro'],
'profile_image_url_https' => $uinfo[0]['micro'],
'profile_image_url_profile_size' => $uinfo[0]["thumb"],
@ -932,7 +932,6 @@ function api_format_data($root_element, $type, $data)
*/
function api_account_verify_credentials($type)
{
$a = \get_app();
if (api_user() === false) {
@ -954,13 +953,9 @@ function api_account_verify_credentials($type)
// - Adding last status
if (!$skip_status) {
$user_info["status"] = api_status_show("raw");
if (isset($user_info["status"])) {
if (!is_array($user_info["status"]) || !count($user_info["status"])) {
unset($user_info["status"]);
} else {
unset($user_info["status"]["user"]);
}
$item = api_get_last_status($user_info['pid'], $user_info['uid']);
if ($item) {
$user_info['status'] = api_format_item($item, $type);
}
}
@ -1244,105 +1239,61 @@ function api_media_upload()
api_register_func('api/media/upload', 'api_media_upload', true, API_METHOD_POST);
/**
*
* @param string $type Return type (atom, rss, xml, json)
*
* @param string $type Return format (atom, rss, xml, json)
* @param int $item_id
* @return array|string
* @throws BadRequestException
* @throws ImagickException
* @throws InternalServerErrorException
* @throws UnauthorizedException
* @return string
* @throws Exception
*/
function api_status_show($type, $item_id = 0)
function api_status_show($type, $item_id)
{
$a = \get_app();
Logger::info(API_LOG_PREFIX . 'Start', ['action' => 'status_show', 'type' => $type, 'item_id' => $item_id]);
$user_info = api_get_user($a);
$status_info = [];
Logger::log('api_status_show: user_info: '.print_r($user_info, true), Logger::DEBUG);
if (!empty($item_id)) {
// Get the item with the given id
$condition = ['id' => $item_id];
} else {
// get last public wall message
$condition = ['owner-id' => $user_info['pid'], 'uid' => api_user(),
'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]];
$item = api_get_item(['id' => $item_id]);
if ($item) {
$status_info = api_format_item($item, $type);
}
if ($type == "raw") {
$condition['private'] = false;
}
Logger::info(API_LOG_PREFIX . 'End', ['action' => 'get_status', 'status_info' => $status_info]);
$lastwall = Item::selectFirst(Item::ITEM_FIELDLIST, $condition, ['order' => ['id' => true]]);
return api_format_data('statuses', $type, ['status' => $status_info]);
}
if (DBA::isResult($lastwall)) {
$in_reply_to = api_in_reply_to($lastwall);
/**
* Retrieves the last public status of the provided user info
*
* @param int $ownerId Public contact Id
* @param int $uid User Id
* @return array
* @throws Exception
*/
function api_get_last_status($ownerId, $uid)
{
$condition = [
'author-id'=> $ownerId,
'uid' => $uid,
'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT],
'private' => false
];
$converted = api_convert_item($lastwall);
$item = api_get_item($condition);
if ($type == "xml") {
$geo = "georss:point";
} else {
$geo = "geo";
}
return $item;
}
$status_info = [
'created_at' => api_date($lastwall['created']),
'id' => intval($lastwall['id']),
'id_str' => (string) $lastwall['id'],
'text' => $converted["text"],
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'truncated' => false,
'in_reply_to_status_id' => $in_reply_to['status_id'],
'in_reply_to_status_id_str' => $in_reply_to['status_id_str'],
'in_reply_to_user_id' => $in_reply_to['user_id'],
'in_reply_to_user_id_str' => $in_reply_to['user_id_str'],
'in_reply_to_screen_name' => $in_reply_to['screen_name'],
'user' => $user_info,
$geo => null,
'coordinates' => '',
'place' => '',
'contributors' => '',
'is_quote_status' => false,
'retweet_count' => 0,
'favorite_count' => 0,
'favorited' => $lastwall['starred'] ? true : false,
'retweeted' => false,
'possibly_sensitive' => false,
'lang' => '',
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $lastwall['parent'],
'external_url' => System::baseUrl() . '/display/' . $lastwall['guid'],
];
/**
* Retrieves a single item record based on the provided condition and converts it for API use.
*
* @param array $condition Item table condition array
* @return array
* @throws Exception
*/
function api_get_item(array $condition)
{
$item = Item::selectFirst(Item::DISPLAY_FIELDLIST, $condition, ['order' => ['id' => true]]);
if (count($converted["attachments"]) > 0) {
$status_info["attachments"] = $converted["attachments"];
}
if (count($converted["entities"]) > 0) {
$status_info["entities"] = $converted["entities"];
}
if ($status_info["source"] == 'web') {
$status_info["source"] = ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']);
} elseif (ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']) != $status_info["source"]) {
$status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']).')');
}
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset($status_info["user"]["uid"]);
unset($status_info["user"]["self"]);
Logger::log('status_info: '.print_r($status_info, true), Logger::DEBUG);
if ($type == "raw") {
return $status_info;
}
return api_format_data("statuses", $type, ['status' => $status_info]);
}
return $item;
}
/**
@ -1359,66 +1310,20 @@ function api_status_show($type, $item_id = 0)
*/
function api_users_show($type)
{
$a = \get_app();
$a = \Friendica\BaseObject::getApp();
$user_info = api_get_user($a);
$condition = ['owner-id' => $user_info['pid'], 'uid' => api_user(),
'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'private' => false];
$lastwall = Item::selectFirst(Item::ITEM_FIELDLIST, $condition, ['order' => ['id' => true]]);
if (DBA::isResult($lastwall)) {
$in_reply_to = api_in_reply_to($lastwall);
$converted = api_convert_item($lastwall);
if ($type == "xml") {
$geo = "georss:point";
} else {
$geo = "geo";
}
$user_info['status'] = [
'text' => $converted["text"],
'truncated' => false,
'created_at' => api_date($lastwall['created']),
'in_reply_to_status_id' => $in_reply_to['status_id'],
'in_reply_to_status_id_str' => $in_reply_to['status_id_str'],
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'id' => intval($lastwall['contact-id']),
'id_str' => (string) $lastwall['contact-id'],
'in_reply_to_user_id' => $in_reply_to['user_id'],
'in_reply_to_user_id_str' => $in_reply_to['user_id_str'],
'in_reply_to_screen_name' => $in_reply_to['screen_name'],
$geo => null,
'favorited' => $lastwall['starred'] ? true : false,
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $lastwall['parent'],
'external_url' => System::baseUrl() . "/display/" . $lastwall['guid'],
];
if (count($converted["attachments"]) > 0) {
$user_info["status"]["attachments"] = $converted["attachments"];
}
if (count($converted["entities"]) > 0) {
$user_info["status"]["entities"] = $converted["entities"];
}
if ($user_info["status"]["source"] == 'web') {
$user_info["status"]["source"] = ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']);
}
if (ContactSelector::networkToName($lastwall['network'], $user_info['url']) != $user_info["status"]["source"]) {
$user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['network'], $lastwall['author-link']) . ')');
}
$item = api_get_last_status($user_info['pid'], $user_info['uid']);
if ($item) {
$user_info['status'] = api_format_item($item, $type);
}
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset($user_info["uid"]);
unset($user_info["self"]);
unset($user_info['uid']);
unset($user_info['self']);
return api_format_data("user", $type, ['user' => $user_info]);
return api_format_data('user', $type, ['user' => $user_info]);
}
/// @TODO move to top of file or somewhere better
@ -1685,7 +1590,7 @@ function api_statuses_home_timeline($type)
Item::update(['unseen' => false], ['unseen' => true, 'id' => $idarray]);
}
}
bindComments($ret);
$data = ['status' => $ret];
@ -2972,7 +2877,7 @@ function api_format_items_profiles($profile_row)
/**
* @brief format items to be returned by api
*
* @param array $r array of items
* @param array $items array of items
* @param array $user_info
* @param bool $filter_user filter items by $user_info
* @param string $type Return type (atom, rss, xml, json)
@ -2982,14 +2887,13 @@ function api_format_items_profiles($profile_row)
* @throws InternalServerErrorException
* @throws UnauthorizedException
*/
function api_format_items($r, $user_info, $filter_user = false, $type = "json")
function api_format_items($items, $user_info, $filter_user = false, $type = "json")
{
$a = \get_app();
$a = \Friendica\BaseObject::getApp();
$ret = [];
foreach ((array)$r as $item) {
localize_item($item);
foreach ((array)$items as $item) {
list($status_user, $author_user, $owner_user) = api_item_get_user($a, $item);
// Look if the posts are matching if they should be filtered by user id
@ -2997,100 +2901,181 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json")
continue;
}
$in_reply_to = api_in_reply_to($item);
$status = api_format_item($item, $type, $status_user, $author_user, $owner_user);
$converted = api_convert_item($item);
if ($type == "xml") {
$geo = "georss:point";
} else {
$geo = "geo";
}
$status = [
'text' => $converted["text"],
'truncated' => false,
'created_at'=> api_date($item['created']),
'in_reply_to_status_id' => $in_reply_to['status_id'],
'in_reply_to_status_id_str' => $in_reply_to['status_id_str'],
'source' => (($item['app']) ? $item['app'] : 'web'),
'id' => intval($item['id']),
'id_str' => (string) intval($item['id']),
'in_reply_to_user_id' => $in_reply_to['user_id'],
'in_reply_to_user_id_str' => $in_reply_to['user_id_str'],
'in_reply_to_screen_name' => $in_reply_to['screen_name'],
$geo => null,
'favorited' => $item['starred'] ? true : false,
'user' => $status_user,
'friendica_author' => $author_user,
'friendica_owner' => $owner_user,
'friendica_private' => $item['private'] == 1,
//'entities' => NULL,
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $item['parent'],
'external_url' => System::baseUrl() . "/display/" . $item['guid'],
'friendica_activities' => api_format_items_activities($item, $type),
];
if (count($converted["attachments"]) > 0) {
$status["attachments"] = $converted["attachments"];
}
if (count($converted["entities"]) > 0) {
$status["entities"] = $converted["entities"];
}
if ($status["source"] == 'web') {
$status["source"] = ContactSelector::networkToName($item['network'], $item['author-link']);
} elseif (ContactSelector::networkToName($item['network'], $item['author-link']) != $status["source"]) {
$status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['network'], $item['author-link']).')');
}
if ($item["id"] == $item["parent"]) {
$retweeted_item = api_share_as_retweet($item);
if ($retweeted_item !== false) {
$retweeted_status = $status;
$status['user'] = $status['friendica_owner'];
try {
$retweeted_status["user"] = api_get_user($a, $retweeted_item["author-id"]);
} catch (BadRequestException $e) {
// user not found. should be found?
/// @todo check if the user should be always found
$retweeted_status["user"] = [];
}
$rt_converted = api_convert_item($retweeted_item);
$retweeted_status['text'] = $rt_converted["text"];
$retweeted_status['statusnet_html'] = $rt_converted["html"];
$retweeted_status['friendica_activities'] = api_format_items_activities($retweeted_item, $type);
$retweeted_status['created_at'] = api_date($retweeted_item['created']);
$status['retweeted_status'] = $retweeted_status;
$status['friendica_author'] = $retweeted_status['friendica_author'];
}
}
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset($status["user"]["uid"]);
unset($status["user"]["self"]);
if ($item["coord"] != "") {
$coords = explode(' ', $item["coord"]);
if (count($coords) == 2) {
if ($type == "json") {
$status["geo"] = ['type' => 'Point',
'coordinates' => [(float) $coords[0],
(float) $coords[1]]];
} else {// Not sure if this is the official format - if someone founds a documentation we can check
$status["georss:point"] = $item["coord"];
}
}
}
$ret[] = $status;
};
}
return $ret;
}
/**
* @param array $item Item record
* @param string $type Return format (atom, rss, xml, json)
* @param array $status_user User record of the item author, can be provided by api_item_get_user()
* @param array $author_user User record of the item author, can be provided by api_item_get_user()
* @param array $owner_user User record of the item owner, can be provided by api_item_get_user()
* @return array API-formatted status
* @throws BadRequestException
* @throws ImagickException
* @throws InternalServerErrorException
* @throws UnauthorizedException
*/
function api_format_item($item, $type = "json", $status_user = null, $author_user = null, $owner_user = null)
{
$a = \Friendica\BaseObject::getApp();
if (empty($status_user) || empty($author_user) || empty($owner_user)) {
list($status_user, $author_user, $owner_user) = api_item_get_user($a, $item);
}
localize_item($item);
$in_reply_to = api_in_reply_to($item);
$converted = api_convert_item($item);
if ($type == "xml") {
$geo = "georss:point";
} else {
$geo = "geo";
}
$status = [
'text' => $converted["text"],
'truncated' => false,
'created_at'=> api_date($item['created']),
'in_reply_to_status_id' => $in_reply_to['status_id'],
'in_reply_to_status_id_str' => $in_reply_to['status_id_str'],
'source' => (($item['app']) ? $item['app'] : 'web'),
'id' => intval($item['id']),
'id_str' => (string) intval($item['id']),
'in_reply_to_user_id' => $in_reply_to['user_id'],
'in_reply_to_user_id_str' => $in_reply_to['user_id_str'],
'in_reply_to_screen_name' => $in_reply_to['screen_name'],
$geo => null,
'favorited' => $item['starred'] ? true : false,
'user' => $status_user,
'friendica_author' => $author_user,
'friendica_owner' => $owner_user,
'friendica_private' => $item['private'] == 1,
//'entities' => NULL,
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $item['parent'],
'external_url' => System::baseUrl() . "/display/" . $item['guid'],
'friendica_activities' => api_format_items_activities($item, $type),
];
if (count($converted["attachments"]) > 0) {
$status["attachments"] = $converted["attachments"];
}
if (count($converted["entities"]) > 0) {
$status["entities"] = $converted["entities"];
}
if ($status["source"] == 'web') {
$status["source"] = ContactSelector::networkToName($item['network'], $item['author-link']);
} elseif (ContactSelector::networkToName($item['network'], $item['author-link']) != $status["source"]) {
$status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['network'], $item['author-link']).')');
}
$retweeted_item = [];
$quoted_item = [];
if ($item["id"] == $item["parent"]) {
$body = $item['body'];
$retweeted_item = api_share_as_retweet($item);
if ($body != $item['body']) {
$quoted_item = $retweeted_item;
$retweeted_item = [];
}
}
if (empty($retweeted_item) && ($item['owner-id'] == $item['author-id'])) {
$announce = api_get_announce($item);
if (!empty($announce)) {
$retweeted_item = $item;
$item = $announce;
$status['friendica_owner'] = api_get_user($a, $announce['author-id']);
}
}
if (!empty($quoted_item)) {
$conv_quoted = api_convert_item($quoted_item);
$quoted_status = $status;
unset($quoted_status['friendica_author']);
unset($quoted_status['friendica_owner']);
unset($quoted_status['friendica_activities']);
unset($quoted_status['friendica_private']);
unset($quoted_status['statusnet_conversation_id']);
$quoted_status['text'] = $conv_quoted['text'];
$quoted_status['statusnet_html'] = $conv_quoted['html'];
try {
$quoted_status["user"] = api_get_user($a, $quoted_item["author-id"]);
} catch (BadRequestException $e) {
// user not found. should be found?
/// @todo check if the user should be always found
$quoted_status["user"] = [];
}
}
if (!empty($retweeted_item)) {
$retweeted_status = $status;
unset($retweeted_status['friendica_author']);
unset($retweeted_status['friendica_owner']);
unset($retweeted_status['friendica_activities']);
unset($retweeted_status['friendica_private']);
unset($retweeted_status['statusnet_conversation_id']);
$status['user'] = $status['friendica_owner'];
try {
$retweeted_status["user"] = api_get_user($a, $retweeted_item["author-id"]);
} catch (BadRequestException $e) {
// user not found. should be found?
/// @todo check if the user should be always found
$retweeted_status["user"] = [];
}
$rt_converted = api_convert_item($retweeted_item);
$retweeted_status['text'] = $rt_converted["text"];
$retweeted_status['statusnet_html'] = $rt_converted["html"];
$retweeted_status['created_at'] = api_date($retweeted_item['created']);
if (!empty($quoted_status)) {
$retweeted_status['quoted_status'] = $quoted_status;
}
$status['friendica_author'] = $retweeted_status['user'];
$status['retweeted_status'] = $retweeted_status;
} elseif (!empty($quoted_status)) {
$root_status = api_convert_item($item);
$status['text'] = $root_status["text"];
$status['statusnet_html'] = $root_status["html"];
$status['quoted_status'] = $quoted_status;
}
// "uid" and "self" are only needed for some internal stuff, so remove it from here
unset($status["user"]["uid"]);
unset($status["user"]["self"]);
if ($item["coord"] != "") {
$coords = explode(' ', $item["coord"]);
if (count($coords) == 2) {
if ($type == "json") {
$status["geo"] = ['type' => 'Point',
'coordinates' => [(float) $coords[0],
(float) $coords[1]]];
} else {// Not sure if this is the official format - if someone founds a documentation we can check
$status["georss:point"] = $item["coord"];
}
}
}
return $status;
}
/**
* Returns the remaining number of API requests available to the user before the API limit is reached.
*
@ -5046,6 +5031,40 @@ function api_friendica_remoteauth()
}
api_register_func('api/friendica/remoteauth', 'api_friendica_remoteauth', true);
/**
* Return an item with announcer data if it had been announced
*
* @param array $item Item array
* @return array Item array with announce data
*/
function api_get_announce($item)
{
// Quit if the item already has got a different owner and author
if ($item['owner-id'] != $item['author-id']) {
return [];
}
// Don't change original or Diaspora posts
if ($item['origin'] || in_array($item['network'], [Protocol::DIASPORA])) {
return [];
}
// Quit if we do now the original author and it had been a post from a native network
if (!empty($item['contact-uid']) && in_array($item['network'], Protocol::NATIVE_SUPPORT)) {
return [];
}
$fields = ['author-id', 'author-name', 'author-link', 'author-avatar'];
$activity = Item::activityToIndex(ACTIVITY2_ANNOUNCE);
$condition = ['parent-uri' => $item['uri'], 'gravity' => GRAVITY_ACTIVITY, 'uid' => [0, $item['uid']], 'activity' => $activity];
$announce = Item::selectFirstForUser($item['uid'], $fields, $condition, ['order' => ['created' => true]]);
if (!DBA::isResult($announce)) {
return [];
}
return array_merge($item, $announce);
}
/**
* @brief Return the item shared, if the item contains only the [share] tag
*
@ -5141,7 +5160,12 @@ function api_share_as_retweet(&$item)
$posted = $matches[1];
}
$shared_body = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "$2", $body);
$pre_body = trim(preg_replace("/(.*?)\[share.*?\]\s?.*?\s?\[\/share\]\s?/ism", "$1", $body));
if ($pre_body != '') {
$item['body'] = $pre_body;
}
$shared_body = trim(preg_replace("/(.*?)\[share.*?\]\s?(.*?)\s?\[\/share\]\s?/ism", "$2", $body));
if (($shared_body == "") || ($profile == "") || ($author == "") || ($avatar == "") || ($posted == "")) {
return false;
@ -5957,7 +5981,7 @@ function api_friendica_notification($type)
}
$nm = new NotificationsManager();
$notes = $nm->getAll([], "+seen -date", 50);
$notes = $nm->getAll([], ['seen' => 'ASC', 'date' => 'DESC'], 50);
if ($type == "xml") {
$xmlnotes = [];

View File

@ -396,7 +396,7 @@ function visible_activity($item) {
* likes (etc.) can apply to other things besides posts. Check if they are post children,
* in which case we handle them specially
*/
$hidden_activities = [ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE, ACTIVITY_FOLLOW];
$hidden_activities = [ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE, ACTIVITY_FOLLOW, ACTIVITY2_ANNOUNCE];
foreach ($hidden_activities as $act) {
if (activity_match($item['verb'], $act)) {
return false;
@ -565,8 +565,12 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
$items = $cb['items'];
$conv_responses = [
'like' => ['title' => L10n::t('Likes','title')], 'dislike' => ['title' => L10n::t('Dislikes','title')],
'attendyes' => ['title' => L10n::t('Attending','title')], 'attendno' => ['title' => L10n::t('Not attending','title')], 'attendmaybe' => ['title' => L10n::t('Might attend','title')]
'like' => ['title' => L10n::t('Likes','title')],
'dislike' => ['title' => L10n::t('Dislikes','title')],
'attendyes' => ['title' => L10n::t('Attending','title')],
'attendno' => ['title' => L10n::t('Not attending','title')],
'attendmaybe' => ['title' => L10n::t('Might attend','title')],
'announce' => ['title' => L10n::t('Reshares','title')]
];
// array with html for each thread (parent+comments)
@ -784,6 +788,46 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
return $o;
}
/**
* Fetch all comments from a query. Additionally set the newest resharer as thread owner.
*
* @param $thread_items Database statement with thread posts
* @return array items with parents and comments
*/
function conversation_fetch_comments($thread_items) {
$comments = [];
$parentlines = [];
$lineno = 0;
$actor = [];
$created = '';
while ($row = Item::fetch($thread_items)) {
if (($row['verb'] == ACTIVITY2_ANNOUNCE) && !empty($row['contact-uid']) && ($row['created'] > $created) && ($row['thr-parent'] == $row['parent-uri'])) {
$actor = ['link' => $row['author-link'], 'avatar' => $row['author-avatar'], 'name' => $row['author-name']];
$created = $row['created'];
}
if ((($row['gravity'] == GRAVITY_PARENT) && !$row['origin'] && !in_array($row['network'], [Protocol::DIASPORA])) &&
(empty($row['contact-uid']) || !in_array($row['network'], Protocol::NATIVE_SUPPORT))) {
$parentlines[] = $lineno;
}
$comments[] = $row;
$lineno++;
}
DBA::close($thread_items);
if (!empty($actor)) {
foreach ($parentlines as $line) {
$comments[$line]['owner-link'] = $actor['link'];
$comments[$line]['owner-avatar'] = $actor['avatar'];
$comments[$line]['owner-name'] = $actor['name'];
}
}
return $comments;
}
/**
* @brief Add comments to top level entries that had been fetched before
*
@ -815,9 +859,10 @@ function conversation_add_children(array $parents, $block_authors, $order, $uid)
if ($block_authors) {
$condition[0] .= "AND NOT `author`.`hidden`";
}
$thread_items = Item::selectForUser(local_user(), [], $condition, $params);
$comments = Item::inArray($thread_items);
$thread_items = Item::selectForUser(local_user(), array_merge(Item::DISPLAY_FIELDLIST, ['contact-uid', 'gravity']), $condition, $params);
$comments = conversation_fetch_comments($thread_items);
if (count($comments) != 0) {
$items = array_merge($items, $comments);
@ -963,6 +1008,9 @@ function builtin_activity_puller($item, &$conv_responses) {
case 'attendmaybe':
$verb = ACTIVITY_ATTENDMAYBE;
break;
case 'announce':
$verb = ACTIVITY2_ANNOUNCE;
break;
default:
return;
}
@ -1045,6 +1093,9 @@ function format_like($cnt, array $arr, $type, $id) {
case 'attendmaybe' :
$phrase = L10n::t('%s attends maybe.', $likers);
break;
case 'announce' :
$phrase = L10n::t('%s reshared this.', $likers);
break;
}
}
@ -1084,6 +1135,10 @@ function format_like($cnt, array $arr, $type, $id) {
$phrase = L10n::t('<span %1$s>%2$d people</span> attend maybe', $spanatts, $cnt);
$explikers = L10n::t('%s attend maybe.', $likers);
break;
case 'announce':
$phrase = L10n::t('<span %1$s>%2$d people</span> reshared this', $spanatts, $cnt);
$explikers = L10n::t('%s reshared this.', $likers);
break;
}
$expanded .= "\t" . '<p class="wall-item-' . $type . '-expanded" id="' . $type . 'list-' . $id . '" style="display: none;" >' . $explikers . EOL . '</p>';

View File

@ -446,80 +446,3 @@ function drop_item($id, $return = '')
//NOTREACHED
}
}
/* arrange the list in years */
function list_post_dates($uid, $wall)
{
$dnow = DateTimeFormat::localNow('Y-m-d');
$dthen = Item::firstPostDate($uid, $wall);
if (!$dthen) {
return [];
}
// Set the start and end date to the beginning of the month
$dnow = substr($dnow, 0, 8) . '01';
$dthen = substr($dthen, 0, 8) . '01';
$ret = [];
/*
* Starting with the current month, get the first and last days of every
* month down to and including the month of the first post
*/
while (substr($dnow, 0, 7) >= substr($dthen, 0, 7)) {
$dyear = intval(substr($dnow, 0, 4));
$dstart = substr($dnow, 0, 8) . '01';
$dend = substr($dnow, 0, 8) . Temporal::getDaysInMonth(intval($dnow), intval(substr($dnow, 5)));
$start_month = DateTimeFormat::utc($dstart, 'Y-m-d');
$end_month = DateTimeFormat::utc($dend, 'Y-m-d');
$str = L10n::getDay(DateTimeFormat::utc($dnow, 'F'));
if (empty($ret[$dyear])) {
$ret[$dyear] = [];
}
$ret[$dyear][] = [$str, $end_month, $start_month];
$dnow = DateTimeFormat::utc($dnow . ' -1 month', 'Y-m-d');
}
return $ret;
}
function posted_date_widget($url, $uid, $wall)
{
$o = '';
if (!Feature::isEnabled($uid, 'archives')) {
return $o;
}
// For former Facebook folks that left because of "timeline"
/*
* @TODO old-lost code?
if ($wall && intval(PConfig::get($uid, 'system', 'no_wall_archive_widget')))
return $o;
*/
$visible_years = PConfig::get($uid, 'system', 'archive_visible_years', 5);
$ret = list_post_dates($uid, $wall);
if (!DBA::isResult($ret)) {
return $o;
}
$cutoff_year = intval(DateTimeFormat::localNow('Y')) - $visible_years;
$cutoff = ((array_key_exists($cutoff_year, $ret))? true : false);
$o = Renderer::replaceMacros(Renderer::getMarkupTemplate('posted_date_widget.tpl'),[
'$title' => L10n::t('Archives'),
'$size' => $visible_years,
'$cutoff_year' => $cutoff_year,
'$cutoff' => $cutoff,
'$url' => $url,
'$dates' => $ret,
'$showmore' => L10n::t('show more')
]);
return $o;
}

View File

@ -8,10 +8,8 @@ use Friendica\Content\Smilies;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Protocol;
use Friendica\Model\Contact;
use Friendica\Model\FileTag;
use Friendica\Util\Strings;
use Friendica\Util\XML;
/**
* Turn user/group ACLs stored as angle bracketed text into arrays
@ -186,21 +184,17 @@ function get_cats_and_terms($item)
{
$categories = [];
$folders = [];
$matches = [];
$first = true;
$cnt = preg_match_all('/<(.*?)>/', $item['file'], $matches, PREG_SET_ORDER);
if ($cnt) {
foreach ($matches as $mtch) {
$categories[] = [
'name' => XML::escape(FileTag::decode($mtch[1])),
'url' => "#",
'removeurl' => ((local_user() == $item['uid'])?'filerm/' . $item['id'] . '?f=&cat=' . XML::escape(FileTag::decode($mtch[1])):""),
'first' => $first,
'last' => false
];
$first = false;
}
foreach (FileTag::fileToArray($item['file'] ?? '', 'category') as $savedFolderName) {
$categories[] = [
'name' => $savedFolderName,
'url' => "#",
'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&cat=' . rawurlencode($savedFolderName) : ""),
'first' => $first,
'last' => false
];
$first = false;
}
if (count($categories)) {
@ -208,20 +202,15 @@ function get_cats_and_terms($item)
}
if (local_user() == $item['uid']) {
$matches = [];
$first = true;
$cnt = preg_match_all('/\[(.*?)\]/', $item['file'], $matches, PREG_SET_ORDER);
if ($cnt) {
foreach ($matches as $mtch) {
$folders[] = [
'name' => XML::escape(FileTag::decode($mtch[1])),
'url' => "#",
'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&term=' . XML::escape(FileTag::decode($mtch[1])) : ""),
'first' => $first,
'last' => false
];
$first = false;
}
foreach (FileTag::fileToArray($item['file'] ?? '') as $savedFolderName) {
$folders[] = [
'name' => $savedFolderName,
'url' => "#",
'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&term=' . rawurlencode($savedFolderName) : ""),
'first' => $first,
'last' => false
];
$first = false;
}
}

View File

@ -1,82 +0,0 @@
<?php
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\System;
require_once 'mod/hostxrd.php';
require_once 'mod/nodeinfo.php';
require_once 'mod/xrd.php';
function _well_known_init(App $a)
{
if ($a->argc > 1) {
switch ($a->argv[1]) {
case "host-meta":
hostxrd_init($a);
break;
case "x-social-relay":
wk_social_relay();
break;
case "nodeinfo":
nodeinfo_wellknown($a);
break;
case "webfinger":
xrd_init($a);
break;
}
}
System::httpExit(404);
}
function wk_social_relay()
{
$subscribe = (bool) Config::get('system', 'relay_subscribe', false);
if ($subscribe) {
$scope = Config::get('system', 'relay_scope', SR_SCOPE_ALL);
} else {
$scope = SR_SCOPE_NONE;
}
$tags = [];
if ($scope == SR_SCOPE_TAGS) {
$server_tags = Config::get('system', 'relay_server_tags');
$tagitems = explode(",", $server_tags);
/// @todo Check if it was better to use "strtolower" on the tags
foreach ($tagitems AS $tag) {
$tag = trim($tag, "# ");
$tags[$tag] = $tag;
}
if (Config::get('system', 'relay_user_tags')) {
$terms = q("SELECT DISTINCT(`term`) FROM `search`");
foreach ($terms AS $term) {
$tag = trim($term["term"], "#");
$tags[$tag] = $tag;
}
}
}
$taglist = [];
foreach ($tags AS $tag) {
if (!empty($tag)) {
$taglist[] = $tag;
}
}
$relay = [
'subscribe' => $subscribe,
'scope' => $scope,
'tags' => $taglist,
'protocols' => ['diaspora' => ['receive' => System::baseUrl() . '/receive/public'],
'dfrn' => ['receive' => System::baseUrl() . '/dfrn_notify']]
];
header('Content-type: application/json; charset=utf-8');
echo json_encode($relay, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
exit;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,106 +0,0 @@
<?php
/**
* @file mod/allfriends.php
*/
use Friendica\App;
use Friendica\Content\ContactSelector;
use Friendica\Content\Pager;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model;
use Friendica\Module;
use Friendica\Util\Proxy as ProxyUtils;
function allfriends_content(App $a)
{
$o = '';
if (!local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
$cid = 0;
if ($a->argc > 1) {
$cid = intval($a->argv[1]);
}
if (!$cid) {
return;
}
$uid = $a->user['uid'];
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo', 'uid', 'id'], ['id' => $cid, 'uid' => local_user()]);
if (!DBA::isResult($contact)) {
return;
}
$a->page['aside'] = "";
Model\Profile::load($a, "", 0, Model\Contact::getDetailsByURL($contact["url"]));
$total = Model\GContact::countAllFriends(local_user(), $cid);
$pager = new Pager($a->query_string);
$r = Model\GContact::allFriends(local_user(), $cid, $pager->getStart(), $pager->getItemsPerPage());
if (!DBA::isResult($r)) {
$o .= L10n::t('No friends to display.');
return $o;
}
$id = 0;
$entries = [];
foreach ($r as $rr) {
//get further details of the contact
$contact_details = Model\Contact::getDetailsByURL($rr['url'], $uid, $rr);
$connlnk = '';
// $rr[cid] is only available for common contacts. So if the contact is a common one, use contact_photo_menu to generate the photo_menu
// If the contact is not common to the user, Connect/Follow' will be added to the photo menu
if ($rr['cid']) {
$rr['id'] = $rr['cid'];
$photo_menu = Model\Contact::photoMenu($rr);
} else {
$connlnk = System::baseUrl() . '/follow/?url=' . $rr['url'];
$photo_menu = [
'profile' => [L10n::t("View Profile"), Model\Contact::magicLink($rr['url'])],
'follow' => [L10n::t("Connect/Follow"), $connlnk]
];
}
$entry = [
'url' => Model\Contact::magicLink($rr['url']),
'itemurl' => defaults($contact_details, 'addr', $rr['url']),
'name' => $contact_details['name'],
'thumb' => ProxyUtils::proxifyUrl($contact_details['thumb'], false, ProxyUtils::SIZE_THUMB),
'img_hover' => $contact_details['name'],
'details' => $contact_details['location'],
'tags' => $contact_details['keywords'],
'about' => $contact_details['about'],
'account_type' => Model\Contact::getAccountType($contact_details),
'network' => ContactSelector::networkToName($contact_details['network'], $contact_details['url']),
'photo_menu' => $photo_menu,
'conntxt' => L10n::t('Connect'),
'connlnk' => $connlnk,
'id' => ++$id,
];
$entries[] = $entry;
}
$tab_str = Module\Contact::getTabsHTML($a, $contact, 4);
$tpl = Renderer::getMarkupTemplate('viewcontact_template.tpl');
$o .= Renderer::replaceMacros($tpl, [
'$tab_str' => $tab_str,
'$contacts' => $entries,
'$paginate' => $pager->renderFull($total),
]);
return $o;
}

View File

@ -1,49 +0,0 @@
<?php
function amcd_content()
{
echo <<< JSON
{
"version":1,
"sessionstatus":{
"method":"GET",
"path":"/session"
},
"auth-methods": {
"username-password-form": {
"connect": {
"method":"POST",
"path":"/login",
"params": {
"username":"login-name",
"password":"password"
},
"onsuccess": { "action":"reload" }
},
"disconnect": {
"method":"GET",
"path":"\/logout"
}
}
}
"methods": {
"username-password-form": {
"connect": {
"method":"POST",
"path":"\/login",
"params": {
"username":"login-name",
"password":"password"
},
"onsuccess": { "action":"reload" }
},
"disconnect": {
"method":"GET",
"path":"\/logout"
}
}
}
}
JSON;
exit();
}

View File

@ -1,33 +0,0 @@
<?php
/**
* @file mod/apps.php
*/
use Friendica\Content\Nav;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
function apps_content()
{
$privateaddons = Config::get('config', 'private_addons');
if ($privateaddons === "1") {
if (! local_user()) {
info(L10n::t('You must be logged in to use addons. '));
return;
};
}
$title = L10n::t('Applications');
$apps = Nav::getAppMenu();
if (count($apps) == 0) {
notice(L10n::t('No installed applications.') . EOL);
}
$tpl = Renderer::getMarkupTemplate('apps.tpl');
return Renderer::replaceMacros($tpl, [
'$title' => $title,
'$apps' => $apps,
]);
}

View File

@ -1,168 +0,0 @@
<?php
/**
* @file mod/babel.php
*/
use Friendica\Content\Text;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
function visible_whitespace($s)
{
$s = str_replace(' ', '&nbsp;', $s);
return str_replace(["\r\n", "\n", "\r"], '<br />', $s);
}
function babel_content()
{
$results = [];
if (!empty($_REQUEST['text'])) {
switch (defaults($_REQUEST, 'type', 'bbcode')) {
case 'bbcode':
$bbcode = trim($_REQUEST['text']);
$results[] = [
'title' => L10n::t('Source input'),
'content' => visible_whitespace($bbcode)
];
$plain = Text\BBCode::toPlaintext($bbcode, false);
$results[] = [
'title' => L10n::t('BBCode::toPlaintext'),
'content' => visible_whitespace($plain)
];
$html = Text\BBCode::convert($bbcode);
$results[] = [
'title' => L10n::t('BBCode::convert (raw HTML)'),
'content' => visible_whitespace(htmlspecialchars($html))
];
$results[] = [
'title' => L10n::t('BBCode::convert'),
'content' => $html
];
$bbcode2 = Text\HTML::toBBCode($html);
$results[] = [
'title' => L10n::t('BBCode::convert => HTML::toBBCode'),
'content' => visible_whitespace($bbcode2)
];
$markdown = Text\BBCode::toMarkdown($bbcode);
$results[] = [
'title' => L10n::t('BBCode::toMarkdown'),
'content' => visible_whitespace($markdown)
];
$html2 = Text\Markdown::convert($markdown);
$results[] = [
'title' => L10n::t('BBCode::toMarkdown => Markdown::convert'),
'content' => $html2
];
$bbcode3 = Text\Markdown::toBBCode($markdown);
$results[] = [
'title' => L10n::t('BBCode::toMarkdown => Markdown::toBBCode'),
'content' => visible_whitespace($bbcode3)
];
$bbcode4 = Text\HTML::toBBCode($html2);
$results[] = [
'title' => L10n::t('BBCode::toMarkdown => Markdown::convert => HTML::toBBCode'),
'content' => visible_whitespace($bbcode4)
];
$item = [
'body' => $bbcode,
'tag' => '',
];
\Friendica\Model\Item::setHashtags($item);
$results[] = [
'title' => L10n::t('Item Body'),
'content' => visible_whitespace($item['body'])
];
$results[] = [
'title' => L10n::t('Item Tags'),
'content' => $item['tag']
];
break;
case 'markdown':
$markdown = trim($_REQUEST['text']);
$results[] = [
'title' => L10n::t('Source input (Diaspora format)'),
'content' => '<pre>' . $markdown . '</pre>'
];
$html = Text\Markdown::convert($markdown);
$results[] = [
'title' => L10n::t('Markdown::convert (raw HTML)'),
'content' => visible_whitespace(htmlspecialchars($html))
];
$results[] = [
'title' => L10n::t('Markdown::convert'),
'content' => $html
];
$bbcode = Text\Markdown::toBBCode($markdown);
$results[] = [
'title' => L10n::t('Markdown::toBBCode'),
'content' => '<pre>' . $bbcode . '</pre>'
];
break;
case 'html' :
$html = trim($_REQUEST['text']);
$results[] = [
'title' => L10n::t('Raw HTML input'),
'content' => htmlspecialchars($html)
];
$results[] = [
'title' => L10n::t('HTML Input'),
'content' => $html
];
$bbcode = Text\HTML::toBBCode($html);
$results[] = [
'title' => L10n::t('HTML::toBBCode'),
'content' => visible_whitespace($bbcode)
];
$html2 = Text\BBCode::convert($bbcode);
$results[] = [
'title' => L10n::t('HTML::toBBCode => BBCode::convert'),
'content' => $html2
];
$results[] = [
'title' => L10n::t('HTML::toBBCode => BBCode::convert (raw HTML)'),
'content' => htmlspecialchars($html2)
];
$markdown = Text\HTML::toMarkdown($html);
$results[] = [
'title' => L10n::t('HTML::toMarkdown'),
'content' => visible_whitespace($markdown)
];
$text = Text\HTML::toPlaintext($html);
$results[] = [
'title' => L10n::t('HTML::toPlaintext'),
'content' => '<pre>' . $text . '</pre>'
];
}
}
$tpl = Renderer::getMarkupTemplate('babel.tpl');
$o = Renderer::replaceMacros($tpl, [
'$text' => ['text', L10n::t('Source text'), defaults($_REQUEST, 'text', ''), ''],
'$type_bbcode' => ['type', L10n::t('BBCode'), 'bbcode', '', defaults($_REQUEST, 'type', 'bbcode') == 'bbcode'],
'$type_markdown' => ['type', L10n::t('Markdown'), 'markdown', '', defaults($_REQUEST, 'type', 'bbcode') == 'markdown'],
'$type_html' => ['type', L10n::t('HTML'), 'html', '', defaults($_REQUEST, 'type', 'bbcode') == 'html'],
'$results' => $results
]);
return $o;
}

View File

@ -1,59 +0,0 @@
<?php
/**
* @file mod/bookmarklet.php
*/
use Friendica\App;
use Friendica\Core\ACL;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Module\Login;
use Friendica\Util\Strings;
function bookmarklet_init()
{
$_GET["mode"] = "minimal";
}
function bookmarklet_content(App $a)
{
if (!local_user()) {
$o = '<h2>' . L10n::t('Login') . '</h2>';
$o .= Login::form($a->query_string, intval(Config::get('config', 'register_policy')) === \Friendica\Module\Register::CLOSED ? false : true);
return $o;
}
$referer = Strings::normaliseLink(defaults($_SERVER, 'HTTP_REFERER', ''));
$page = Strings::normaliseLink(System::baseUrl() . "/bookmarklet");
if (!strstr($referer, $page)) {
if (empty($_REQUEST["url"])) {
System::httpExit(400, ["title" => L10n::t('Bad Request')]);
}
$content = add_page_info($_REQUEST["url"]);
$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'),
'default_perms' => ACL::getDefaultUserPermissions($a->user),
'acl' => ACL::getFullSelectorHTML($a->user, true),
'bang' => '',
'visitor' => 'block',
'profile_uid' => local_user(),
'title' => trim(defaults($_REQUEST, 'title', ''), "*"),
'content' => $content
];
$o = status_editor($a, $x, 0, false);
$o .= "<script>window.resizeTo(800,550);</script>";
} else {
$o = '<h2>' . L10n::t('The post was created') . '</h2>';
$o .= "<script>window.close()</script>";
}
return $o;
}

View File

@ -31,11 +31,11 @@ function cal_init(App $a)
}
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
System::httpExit(403, ['title' => L10n::t('Access denied.')]);
throw new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Access denied.'));
}
if ($a->argc < 2) {
System::httpExit(403, ['title' => L10n::t('Access denied.')]);
throw new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Access denied.'));
}
Nav::setSelected('events');
@ -43,7 +43,7 @@ function cal_init(App $a)
$nick = $a->argv[1];
$user = DBA::selectFirst('user', [], ['nickname' => $nick, 'blocked' => false]);
if (!DBA::isResult($user)) {
System::httpExit(404, ['title' => L10n::t('Page not found.')]);
throw new \Friendica\Network\HTTPException\NotFoundException();
}
$a->data['user'] = $user;
@ -59,7 +59,7 @@ function cal_init(App $a)
$account_type = Contact::getAccountType($profile);
$tpl = Renderer::getMarkupTemplate("vcard-widget.tpl");
$tpl = Renderer::getMarkupTemplate("widget/vcard.tpl");
$vcard_widget = Renderer::replaceMacros($tpl, [
'$name' => $profile['name'],
@ -90,7 +90,6 @@ function cal_content(App $a)
$htpl = Renderer::getMarkupTemplate('event_head.tpl');
$a->page['htmlhead'] .= Renderer::replaceMacros($htpl, [
'$baseurl' => System::baseUrl(),
'$module_url' => '/cal/' . $a->data['user']['nickname'],
'$modparams' => 2,
'$i18n' => $i18n,
@ -148,7 +147,7 @@ function cal_content(App $a)
$sql_extra = " AND `event`.`cid` = 0 " . $sql_perms;
// get the tab navigation bar
$tabs = Profile::getTabs($a, false, $a->data['user']['nickname']);
$tabs = Profile::getTabs($a, 'cal', false, $a->data['user']['nickname']);
// The view mode part is similiar to /mod/events.php
if ($mode == 'view') {
@ -268,7 +267,6 @@ function cal_content(App $a)
}
$o = Renderer::replaceMacros($tpl, [
'$baseurl' => System::baseUrl(),
'$tabs' => $tabs,
'$title' => L10n::t('Events'),
'$view' => L10n::t('View'),

View File

@ -47,7 +47,7 @@ function common_content(App $a)
$contact = DBA::selectFirst('contact', ['name', 'url', 'photo', 'uid', 'id'], ['self' => true, 'uid' => $uid]);
if (DBA::isResult($contact)) {
$vcard_widget = Renderer::replaceMacros(Renderer::getMarkupTemplate("vcard-widget.tpl"), [
$vcard_widget = Renderer::replaceMacros(Renderer::getMarkupTemplate("widget/vcard.tpl"), [
'$name' => $contact['name'],
'$photo' => $contact['photo'],
'url' => 'contact/' . $cid

View File

@ -1,23 +0,0 @@
<?php
/**
* @file mod/credits.php
* Show a credits page for all the developers who helped with the project
* (only contributors to the git repositories for friendica core and the
* addons repository will be listed though ATM)
*/
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
function credits_content()
{
/* fill the page with credits */
$credits_string = file_get_contents('CREDITS.txt');
$names = explode("\n", $credits_string);
$tpl = Renderer::getMarkupTemplate('credits.tpl');
return Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Credits'),
'$thanks' => L10n::t('Friendica is a community project, that would not be possible without the help of many people. Here is a list of those who have contributed to the code or the translation of Friendica. Thank you all!'),
'$names' => $names,
]);
}

View File

@ -28,8 +28,6 @@ use Friendica\Model\Contact;
use Friendica\Model\Group;
use Friendica\Model\User;
use Friendica\Network\Probe;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\ActivityPub;
use Friendica\Util\Crypto;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network;
@ -136,163 +134,153 @@ function dfrn_confirm_post(App $a, $handsfree = null)
$site_pubkey = $contact['site-pubkey'];
$dfrn_confirm = $contact['confirm'];
$aes_allow = $contact['aes_allow'];
$protocol = $contact['network'];
$network = ((strlen($contact['issued-id'])) ? Protocol::DFRN : Protocol::OSTATUS);
/*
* Generate a key pair for all further communications with this person.
* We have a keypair for every contact, and a site key for unknown people.
* This provides a means to carry on relationships with other people if
* any single key is compromised. It is a robust key. We're much more
* worried about key leakage than anybody cracking it.
*/
$res = Crypto::newKeypair(4096);
if ($contact['network']) {
$network = $contact['network'];
$private_key = $res['prvkey'];
$public_key = $res['pubkey'];
// Save the private key. Send them the public key.
$fields = ['prvkey' => $private_key, 'protocol' => Protocol::DFRN];
DBA::update('contact', $fields, ['id' => $contact_id]);
$params = [];
/*
* Per the DFRN protocol, we will verify both ends by encrypting the dfrn_id with our
* site private key (person on the other end can decrypt it with our site public key).
* Then encrypt our profile URL with the other person's site public key. They can decrypt
* it with their site private key. If the decryption on the other end fails for either
* item, it indicates tampering or key failure on at least one site and we will not be
* able to provide a secure communication pathway.
*
* If other site is willing to accept full encryption, (aes_allow is 1 AND we have php5.3
* or later) then we encrypt the personal public key we send them using AES-256-CBC and a
* random key which is encrypted with their site public key.
*/
$src_aes_key = openssl_random_pseudo_bytes(64);
$result = '';
openssl_private_encrypt($dfrn_id, $result, $user['prvkey']);
$params['dfrn_id'] = bin2hex($result);
$params['public_key'] = $public_key;
$my_url = System::baseUrl() . '/profile/' . $user['nickname'];
openssl_public_encrypt($my_url, $params['source_url'], $site_pubkey);
$params['source_url'] = bin2hex($params['source_url']);
if ($aes_allow && function_exists('openssl_encrypt')) {
openssl_public_encrypt($src_aes_key, $params['aes_key'], $site_pubkey);
$params['aes_key'] = bin2hex($params['aes_key']);
$params['public_key'] = bin2hex(openssl_encrypt($public_key, 'AES-256-CBC', $src_aes_key));
}
if ($network === Protocol::DFRN) {
/*
* Generate a key pair for all further communications with this person.
* We have a keypair for every contact, and a site key for unknown people.
* This provides a means to carry on relationships with other people if
* any single key is compromised. It is a robust key. We're much more
* worried about key leakage than anybody cracking it.
*/
$res = Crypto::newKeypair(4096);
$params['dfrn_version'] = DFRN_PROTOCOL_VERSION;
if ($duplex == 1) {
$params['duplex'] = 1;
}
$private_key = $res['prvkey'];
$public_key = $res['pubkey'];
if ($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY) {
$params['page'] = 1;
}
// Save the private key. Send them the public key.
q("UPDATE `contact` SET `prvkey` = '%s' WHERE `id` = %d AND `uid` = %d",
DBA::escape($private_key),
intval($contact_id),
intval($uid)
);
if ($user['page-flags'] == User::PAGE_FLAGS_PRVGROUP) {
$params['page'] = 2;
}
$params = [];
Logger::log('Confirm: posting data to ' . $dfrn_confirm . ': ' . print_r($params, true), Logger::DATA);
/*
* Per the DFRN protocol, we will verify both ends by encrypting the dfrn_id with our
* site private key (person on the other end can decrypt it with our site public key).
* Then encrypt our profile URL with the other person's site public key. They can decrypt
* it with their site private key. If the decryption on the other end fails for either
* item, it indicates tampering or key failure on at least one site and we will not be
* able to provide a secure communication pathway.
*
* If other site is willing to accept full encryption, (aes_allow is 1 AND we have php5.3
* or later) then we encrypt the personal public key we send them using AES-256-CBC and a
* random key which is encrypted with their site public key.
*/
/*
*
* POST all this stuff to the other site.
* Temporarily raise the network timeout to 120 seconds because the default 60
* doesn't always give the other side quite enough time to decrypt everything.
*
*/
$src_aes_key = openssl_random_pseudo_bytes(64);
$res = Network::post($dfrn_confirm, $params, [], 120)->getBody();
$result = '';
openssl_private_encrypt($dfrn_id, $result, $user['prvkey']);
Logger::log(' Confirm: received data: ' . $res, Logger::DATA);
$params['dfrn_id'] = bin2hex($result);
$params['public_key'] = $public_key;
// Now figure out what they responded. Try to be robust if the remote site is
// having difficulty and throwing up errors of some kind.
$my_url = System::baseUrl() . '/profile/' . $user['nickname'];
$leading_junk = substr($res, 0, strpos($res, '<?xml'));
openssl_public_encrypt($my_url, $params['source_url'], $site_pubkey);
$params['source_url'] = bin2hex($params['source_url']);
$res = substr($res, strpos($res, '<?xml'));
if (!strlen($res)) {
// No XML at all, this exchange is messed up really bad.
// We shouldn't proceed, because the xml parser might choke,
// and $status is going to be zero, which indicates success.
// We can hardly call this a success.
notice(L10n::t('Response from remote site was not understood.') . EOL);
return;
}
if ($aes_allow && function_exists('openssl_encrypt')) {
openssl_public_encrypt($src_aes_key, $params['aes_key'], $site_pubkey);
$params['aes_key'] = bin2hex($params['aes_key']);
$params['public_key'] = bin2hex(openssl_encrypt($public_key, 'AES-256-CBC', $src_aes_key));
if (strlen($leading_junk) && Config::get('system', 'debugging')) {
// This might be more common. Mixed error text and some XML.
// If we're configured for debugging, show the text. Proceed in either case.
notice(L10n::t('Unexpected response from remote site: ') . EOL . $leading_junk . EOL);
}
if (stristr($res, "<status") === false) {
// wrong xml! stop here!
Logger::log('Unexpected response posting to ' . $dfrn_confirm);
notice(L10n::t('Unexpected response from remote site: ') . EOL . htmlspecialchars($res) . EOL);
return;
}
$xml = XML::parseString($res);
$status = (int) $xml->status;
$message = XML::unescape($xml->message); // human readable text of what may have gone wrong.
switch ($status) {
case 0:
info(L10n::t("Confirmation completed successfully.") . EOL);
break;
case 1:
// birthday paradox - generate new dfrn-id and fall through.
$new_dfrn_id = Strings::getRandomHex();
q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d AND `uid` = %d",
DBA::escape($new_dfrn_id),
intval($contact_id),
intval($uid)
);
case 2:
notice(L10n::t("Temporary failure. Please wait and try again.") . EOL);
break;
case 3:
notice(L10n::t("Introduction failed or was revoked.") . EOL);
break;
}
if (strlen($message)) {
notice(L10n::t('Remote site reported: ') . $message . EOL);
}
if (($status == 0) && $intro_id) {
$intro = DBA::selectFirst('intro', ['note'], ['id' => $intro_id]);
if (DBA::isResult($intro)) {
DBA::update('contact', ['reason' => $intro['note']], ['id' => $contact_id]);
}
$params['dfrn_version'] = DFRN_PROTOCOL_VERSION;
if ($duplex == 1) {
$params['duplex'] = 1;
}
// Success. Delete the notification.
DBA::delete('intro', ['id' => $intro_id]);
}
if ($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY) {
$params['page'] = 1;
}
if ($user['page-flags'] == User::PAGE_FLAGS_PRVGROUP) {
$params['page'] = 2;
}
Logger::log('Confirm: posting data to ' . $dfrn_confirm . ': ' . print_r($params, true), Logger::DATA);
/*
*
* POST all this stuff to the other site.
* Temporarily raise the network timeout to 120 seconds because the default 60
* doesn't always give the other side quite enough time to decrypt everything.
*
*/
$res = Network::post($dfrn_confirm, $params, null, $redirects, 120)->getBody();
Logger::log(' Confirm: received data: ' . $res, Logger::DATA);
// Now figure out what they responded. Try to be robust if the remote site is
// having difficulty and throwing up errors of some kind.
$leading_junk = substr($res, 0, strpos($res, '<?xml'));
$res = substr($res, strpos($res, '<?xml'));
if (!strlen($res)) {
// No XML at all, this exchange is messed up really bad.
// We shouldn't proceed, because the xml parser might choke,
// and $status is going to be zero, which indicates success.
// We can hardly call this a success.
notice(L10n::t('Response from remote site was not understood.') . EOL);
return;
}
if (strlen($leading_junk) && Config::get('system', 'debugging')) {
// This might be more common. Mixed error text and some XML.
// If we're configured for debugging, show the text. Proceed in either case.
notice(L10n::t('Unexpected response from remote site: ') . EOL . $leading_junk . EOL);
}
if (stristr($res, "<status") === false) {
// wrong xml! stop here!
Logger::log('Unexpected response posting to ' . $dfrn_confirm);
notice(L10n::t('Unexpected response from remote site: ') . EOL . htmlspecialchars($res) . EOL);
return;
}
$xml = XML::parseString($res);
$status = (int) $xml->status;
$message = XML::unescape($xml->message); // human readable text of what may have gone wrong.
switch ($status) {
case 0:
info(L10n::t("Confirmation completed successfully.") . EOL);
break;
case 1:
// birthday paradox - generate new dfrn-id and fall through.
$new_dfrn_id = Strings::getRandomHex();
q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d AND `uid` = %d",
DBA::escape($new_dfrn_id),
intval($contact_id),
intval($uid)
);
case 2:
notice(L10n::t("Temporary failure. Please wait and try again.") . EOL);
break;
case 3:
notice(L10n::t("Introduction failed or was revoked.") . EOL);
break;
}
if (strlen($message)) {
notice(L10n::t('Remote site reported: ') . $message . EOL);
}
if (($status == 0) && $intro_id) {
$intro = DBA::selectFirst('intro', ['note'], ['id' => $intro_id]);
if (DBA::isResult($intro)) {
DBA::update('contact', ['reason' => $intro['note']], ['id' => $contact_id]);
}
// Success. Delete the notification.
DBA::delete('intro', ['id' => $intro_id]);
}
if ($status != 0) {
return;
}
if ($status != 0) {
return;
}
/*
@ -306,101 +294,39 @@ function dfrn_confirm_post(App $a, $handsfree = null)
Logger::log('dfrn_confirm: confirm - imported photos');
if ($network === Protocol::DFRN) {
$new_relation = Contact::FOLLOWER;
$new_relation = Contact::FOLLOWER;
if (($relation == Contact::SHARING) || ($duplex)) {
$new_relation = Contact::FRIEND;
}
if (($relation == Contact::SHARING) && ($duplex)) {
$duplex = 0;
}
$r = q("UPDATE `contact` SET `rel` = %d,
`name-date` = '%s',
`uri-date` = '%s',
`blocked` = 0,
`pending` = 0,
`duplex` = %d,
`hidden` = %d,
`network` = '%s' WHERE `id` = %d
",
intval($new_relation),
DBA::escape(DateTimeFormat::utcNow()),
DBA::escape(DateTimeFormat::utcNow()),
intval($duplex),
intval($hidden),
DBA::escape(Protocol::DFRN),
intval($contact_id)
);
} else {
if ($network == Protocol::ACTIVITYPUB) {
ActivityPub\Transmitter::sendContactAccept($contact['url'], $contact['hub-verify'], $uid);
// Setting "pending" to true on a bidirectional contact request could create a problem when it isn't accepted on the other side
// Then we have got a situation where - although one direction is accepted - the contact still appears as pending.
// Possibly we need two different "pending" fields, one for incoming, one for outgoing?
// This has to be thought over, but for now this here is a better solution.
// $pending = $duplex;
$pending = false;
} else {
$pending = false;
}
// $network !== Protocol::DFRN
$network = defaults($contact, 'network', Protocol::OSTATUS);
$arr = Probe::uri($contact['url'], $network);
$notify = defaults($contact, 'notify' , $arr['notify']);
$poll = defaults($contact, 'poll' , $arr['poll']);
$addr = $arr['addr'];
$new_relation = $contact['rel'];
$writable = $contact['writable'];
if (in_array($network, [Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
if ($duplex) {
$new_relation = Contact::FRIEND;
} else {
$new_relation = Contact::FOLLOWER;
}
if ($new_relation != Contact::FOLLOWER) {
$writable = 1;
}
}
DBA::delete('intro', ['id' => $intro_id]);
$fields = ['name-date' => DateTimeFormat::utcNow(),
'uri-date' => DateTimeFormat::utcNow(), 'addr' => $addr,
'notify' => $notify, 'poll' => $poll, 'blocked' => false,
'pending' => $pending, 'network' => $network,
'writable' => $writable, 'hidden' => $hidden, 'rel' => $new_relation];
DBA::update('contact', $fields, ['id' => $contact_id]);
if (($relation == Contact::SHARING) || ($duplex)) {
$new_relation = Contact::FRIEND;
}
if (!DBA::isResult($r)) {
notice(L10n::t('Unable to set contact photo.') . EOL);
if (($relation == Contact::SHARING) && ($duplex)) {
$duplex = 0;
}
$r = q("UPDATE `contact` SET `rel` = %d,
`name-date` = '%s',
`uri-date` = '%s',
`blocked` = 0,
`pending` = 0,
`duplex` = %d,
`hidden` = %d,
`network` = '%s' WHERE `id` = %d
",
intval($new_relation),
DBA::escape(DateTimeFormat::utcNow()),
DBA::escape(DateTimeFormat::utcNow()),
intval($duplex),
intval($hidden),
DBA::escape(Protocol::DFRN),
intval($contact_id)
);
// reload contact info
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id]);
if ((isset($new_relation) && $new_relation == Contact::FRIEND)) {
if (DBA::isResult($contact) && ($contact['network'] === Protocol::DIASPORA)) {
$ret = Diaspora::sendShare($user, $contact);
Logger::log('share returns: ' . $ret);
}
}
Group::addMember(User::getDefaultGroup($uid, $contact["network"]), $contact['id']);
if ($network == Protocol::ACTIVITYPUB && $duplex) {
ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $uid);
}
// Let's send our user to the contact editor in case they want to
// do anything special with this new friend.
if ($handsfree === null) {

View File

@ -29,7 +29,7 @@ function dfrn_notify_post(App $a) {
$user = DBA::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
if (!DBA::isResult($user)) {
System::httpExit(500);
throw new \Friendica\Network\HTTPException\InternalServerErrorException();
}
dfrn_dispatch_private($user, $postdata);
} elseif (!dfrn_dispatch_public($postdata)) {
@ -190,13 +190,13 @@ function dfrn_dispatch_public($postdata)
}
// Fetch the corresponding public contact
$contact = Contact::getDetailsByAddr($msg['author'], 0);
if (!$contact) {
$contact_id = Contact::getIdForURL($msg['author']);
if (empty($contact_id)) {
Logger::log('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact ' . $msg['author'] . ' not found');
}
$importer = DFRN::getImporter($contact['id']);
$importer = DFRN::getImporter($contact_id);
// This should never fail
if (empty($importer)) {

View File

@ -50,7 +50,7 @@ function dfrn_poll_init(App $a)
if (($dfrn_id === '') && empty($_POST['dfrn_id'])) {
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
System::httpExit(403);
throw new \Friendica\Network\HTTPException\ForbiddenException();
}
$user = '';
@ -59,7 +59,7 @@ function dfrn_poll_init(App $a)
DBA::escape($a->argv[1])
);
if (!$r) {
System::httpExit(404);
throw new \Friendica\Network\HTTPException\NotFoundException();
}
$hidewall = ($r[0]['hidewall'] && !local_user());
@ -483,7 +483,7 @@ function dfrn_poll_content(App $a)
// heluecht: I don't know why we don't fail immediately when the user or contact hadn't been found.
// Since it doesn't make sense to continue from this point on, we now fail here. This should be safe.
if (!DBA::isResult($r)) {
System::httpExit(404, ["title" => L10n::t('Page not found.')]);
throw new \Friendica\Network\HTTPException\NotFoundException();
}
// URL reply

View File

@ -476,7 +476,7 @@ function dfrn_request_post(App $a)
function dfrn_request_content(App $a)
{
if (($a->argc != 2) || (!count($a->profile))) {
if ($a->argc != 2 || empty($a->profile)) {
return "";
}

View File

@ -1,230 +0,0 @@
<?php
/**
* @file mod/directory.php
*/
use Friendica\App;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Widget;
use Friendica\Core\Config;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Profile;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings;
function directory_init(App $a)
{
if (local_user()) {
$a->page['aside'] .= Widget::findPeople();
$a->page['aside'] .= Widget::follow();
} else {
unset($_SESSION['theme']);
unset($_SESSION['mobile-theme']);
}
}
function directory_post(App $a)
{
if (!empty($_POST['search'])) {
$a->data['search'] = $_POST['search'];
}
}
function directory_content(App $a)
{
if ((Config::get('system', 'block_public') && !local_user() && !remote_user())
|| (Config::get('system', 'block_local_dir') && !local_user() && !remote_user())
) {
notice(L10n::t('Public access denied.') . EOL);
return;
}
$o = '';
$entries = [];
Nav::setSelected('directory');
if (!empty($a->data['search'])) {
$search = Strings::escapeTags(trim($a->data['search']));
} else {
$search = (!empty($_GET['search']) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : '');
}
$gdirpath = '';
$dirurl = Config::get('system', 'directory');
if (strlen($dirurl)) {
$gdirpath = Profile::zrl($dirurl, true);
}
if ($search) {
$search = DBA::escape($search);
$sql_extra = " AND ((`profile`.`name` LIKE '%$search%') OR
(`user`.`nickname` LIKE '%$search%') OR
(`profile`.`pdesc` LIKE '%$search%') OR
(`profile`.`locality` LIKE '%$search%') OR
(`profile`.`region` LIKE '%$search%') OR
(`profile`.`country-name` LIKE '%$search%') OR
(`profile`.`gender` LIKE '%$search%') OR
(`profile`.`marital` LIKE '%$search%') OR
(`profile`.`sexual` LIKE '%$search%') OR
(`profile`.`about` LIKE '%$search%') OR
(`profile`.`romance` LIKE '%$search%') OR
(`profile`.`work` LIKE '%$search%') OR
(`profile`.`education` LIKE '%$search%') OR
(`profile`.`pub_keywords` LIKE '%$search%') OR
(`profile`.`prv_keywords` LIKE '%$search%'))";
} else {
$sql_extra = '';
}
$publish = (Config::get('system', 'publish_all') ? '' : " AND `publish` = 1 " );
$total = 0;
$cnt = DBA::fetchFirst("SELECT COUNT(*) AS `total` FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` $sql_extra");
if (DBA::isResult($cnt)) {
$total = $cnt['total'];
}
$pager = new Pager($a->query_string, 60);
$order = " ORDER BY `name` ASC ";
$limit = $pager->getStart()."," . $pager->getItemsPerPage();
$r = DBA::p("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags`,
`contact`.`addr`, `contact`.`url` AS `profile_url` FROM `profile`
LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid`
LEFT JOIN `contact` ON `contact`.`uid` = `user`.`uid`
WHERE `is-default` $publish AND NOT `user`.`blocked` AND NOT `user`.`account_removed` AND `contact`.`self`
$sql_extra $order LIMIT $limit"
);
if (DBA::isResult($r)) {
if (in_array('small', $a->argv)) {
$photo = 'thumb';
} else {
$photo = 'photo';
}
while ($rr = DBA::fetch($r)) {
$entries[] = format_directory_entry($rr, $photo);
}
DBA::close($r);
} else {
info(L10n::t("No entries \x28some entries may be hidden\x29.") . EOL);
}
$tpl = Renderer::getMarkupTemplate('directory_header.tpl');
$o .= Renderer::replaceMacros($tpl, [
'$search' => $search,
'$globaldir' => L10n::t('Global Directory'),
'$gdirpath' => $gdirpath,
'$desc' => L10n::t('Find on this site'),
'$contacts' => $entries,
'$finding' => L10n::t('Results for:'),
'$findterm' => (strlen($search) ? $search : ""),
'$title' => L10n::t('Site Directory'),
'$search_mod' => 'directory',
'$submit' => L10n::t('Find'),
'$paginate' => $pager->renderFull($total),
]);
return $o;
}
/**
* Format contact/profile/user data from the database into an usable
* array for displaying directory entries.
*
* @param array $arr The directory entry from the database.
* @param string $photo_size Avatar size (thumb, photo or micro).
*
* @return array
*/
function format_directory_entry(array $arr, $photo_size = 'photo')
{
$itemurl = (($arr['addr'] != "") ? $arr['addr'] : $arr['profile_url']);
$profile_link = $arr['profile_url'];
$pdesc = (($arr['pdesc']) ? $arr['pdesc'] . '<br />' : '');
$details = '';
if (strlen($arr['locality'])) {
$details .= $arr['locality'];
}
if (strlen($arr['region'])) {
if (strlen($arr['locality'])) {
$details .= ', ';
}
$details .= $arr['region'];
}
if (strlen($arr['country-name'])) {
if (strlen($details)) {
$details .= ', ';
}
$details .= $arr['country-name'];
}
$profile = $arr;
if (!empty($profile['address'])
|| !empty($profile['locality'])
|| !empty($profile['region'])
|| !empty($profile['postal-code'])
|| !empty($profile['country-name'])
) {
$location = L10n::t('Location:');
} else {
$location = '';
}
$gender = (!empty($profile['gender']) ? L10n::t('Gender:') : false);
$marital = (!empty($profile['marital']) ? L10n::t('Status:') : false);
$homepage = (!empty($profile['homepage']) ? L10n::t('Homepage:') : false);
$about = (!empty($profile['about']) ? L10n::t('About:') : false);
$location_e = $location;
$photo_menu = [
'profile' => [L10n::t("View Profile"), Contact::magicLink($profile_link)]
];
$entry = [
'id' => $arr['id'],
'url' => Contact::magicLInk($profile_link),
'itemurl' => $itemurl,
'thumb' => ProxyUtils::proxifyUrl($arr[$photo_size], false, ProxyUtils::SIZE_THUMB),
'img_hover' => $arr['name'],
'name' => $arr['name'],
'details' => $details,
'account_type' => Contact::getAccountType($arr),
'profile' => $profile,
'location' => $location_e,
'tags' => $arr['pub_keywords'],
'gender' => $gender,
'pdesc' => $pdesc,
'marital' => $marital,
'homepage' => $homepage,
'about' => $about,
'photo_menu' => $photo_menu,
];
$hook = ['contact' => $arr, 'entry' => $entry];
Hook::callAll('directory_item', $hook);
unset($profile);
unset($location);
return $hook['entry'];
}

View File

@ -1,265 +0,0 @@
<?php
/**
* @file mod/dirfind.php
*/
use Friendica\App;
use Friendica\Content\ContactSelector;
use Friendica\Content\Pager;
use Friendica\Content\Widget;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\Model;
use Friendica\Module;
use Friendica\Network\Probe;
use Friendica\Protocol\PortableContact;
use Friendica\Util\Network;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings;
function dirfind_init(App $a) {
if (! local_user()) {
notice(L10n::t('Permission denied.') . EOL );
return;
}
if (empty($a->page['aside'])) {
$a->page['aside'] = '';
}
$a->page['aside'] .= Widget::findPeople();
$a->page['aside'] .= Widget::follow();
}
function dirfind_content(App $a, $prefix = "") {
$community = false;
$discover_user = false;
$local = Config::get('system','poco_local_search');
$search = $prefix.Strings::escapeTags(trim(defaults($_REQUEST, 'search', '')));
$header = '';
if (strpos($search,'@') === 0) {
$search = substr($search,1);
$header = L10n::t('People Search - %s', $search);
if ((filter_var($search, FILTER_VALIDATE_EMAIL) && Network::isEmailDomainValid($search)) ||
(substr(Strings::normaliseLink($search), 0, 7) == "http://")) {
$user_data = Probe::uri($search);
$discover_user = (in_array($user_data["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::DIASPORA]));
}
}
if (strpos($search,'!') === 0) {
$search = substr($search,1);
$community = true;
$header = L10n::t('Forum Search - %s', $search);
}
$o = '';
if ($search) {
$pager = new Pager($a->query_string);
if ($discover_user) {
$j = new stdClass();
$j->total = 1;
$j->items_page = 1;
$j->page = $pager->getPage();
$objresult = new stdClass();
$objresult->cid = 0;
$objresult->name = $user_data["name"];
$objresult->addr = $user_data["addr"];
$objresult->url = $user_data["url"];
$objresult->photo = $user_data["photo"];
$objresult->tags = "";
$objresult->network = $user_data["network"];
$contact = Model\Contact::getDetailsByURL($user_data["url"], local_user());
$objresult->cid = $contact["cid"];
$objresult->pcid = $contact["zid"];
$j->results[] = $objresult;
// Add the contact to the global contacts if it isn't already in our system
if (($contact["cid"] == 0) && ($contact["zid"] == 0) && ($contact["gid"] == 0)) {
Model\GContact::update($user_data);
}
} elseif ($local) {
if ($community) {
$extra_sql = " AND `community`";
} else {
$extra_sql = "";
}
$pager->setItemsPerPage(80);
if (Config::get('system','diaspora_enabled')) {
$diaspora = Protocol::DIASPORA;
} else {
$diaspora = Protocol::DFRN;
}
if (!Config::get('system','ostatus_disabled')) {
$ostatus = Protocol::OSTATUS;
} else {
$ostatus = Protocol::DFRN;
}
$search2 = "%".$search."%";
/// @TODO These 2 SELECTs are not checked on validity with DBA::isResult()
$count = q("SELECT count(*) AS `total` FROM `gcontact`
WHERE NOT `hide` AND `network` IN ('%s', '%s', '%s', '%s') AND
((`last_contact` >= `last_failure`) OR (`updated` >= `last_failure`)) AND
(`url` LIKE '%s' OR `name` LIKE '%s' OR `location` LIKE '%s' OR
`addr` LIKE '%s' OR `about` LIKE '%s' OR `keywords` LIKE '%s') $extra_sql",
DBA::escape(Protocol::ACTIVITYPUB), DBA::escape(Protocol::DFRN), DBA::escape($ostatus), DBA::escape($diaspora),
DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)),
DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)));
$results = q("SELECT `nurl`
FROM `gcontact`
WHERE NOT `hide` AND `network` IN ('%s', '%s', '%s', '%s') AND
((`last_contact` >= `last_failure`) OR (`updated` >= `last_failure`)) AND
(`url` LIKE '%s' OR `name` LIKE '%s' OR `location` LIKE '%s' OR
`addr` LIKE '%s' OR `about` LIKE '%s' OR `keywords` LIKE '%s') $extra_sql
GROUP BY `nurl`
ORDER BY `updated` DESC LIMIT %d, %d",
DBA::escape(Protocol::ACTIVITYPUB), DBA::escape(Protocol::DFRN), DBA::escape($ostatus), DBA::escape($diaspora),
DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)),
DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)),
$pager->getStart(), $pager->getItemsPerPage());
$j = new stdClass();
$j->total = $count[0]["total"];
$j->items_page = $pager->getItemsPerPage();
$j->page = $pager->getPage();
foreach ($results AS $result) {
if (PortableContact::alternateOStatusUrl($result["nurl"])) {
continue;
}
$urlparts = parse_url($result["nurl"]);
// Ignore results that look strange.
// For historic reasons the gcontact table does contain some garbage.
if (!empty($urlparts['query']) || !empty($urlparts['fragment'])) {
continue;
}
$result = Model\Contact::getDetailsByURL($result["nurl"], local_user());
if ($result["name"] == "") {
$result["name"] = end(explode("/", $urlparts["path"]));
}
$objresult = new stdClass();
$objresult->cid = $result["cid"];
$objresult->pcid = $result["zid"];
$objresult->name = $result["name"];
$objresult->addr = $result["addr"];
$objresult->url = $result["url"];
$objresult->photo = $result["photo"];
$objresult->tags = $result["keywords"];
$objresult->network = $result["network"];
$j->results[] = $objresult;
}
// Add found profiles from the global directory to the local directory
Worker::add(PRIORITY_LOW, 'DiscoverPoCo', "dirsearch", urlencode($search));
} elseif (strlen(Config::get('system','directory'))) {
$p = (($pager->getPage() != 1) ? '&p=' . $pager->getPage() : '');
$x = Network::fetchUrl(get_server() . '/lsearch?f=' . $p . '&search=' . urlencode($search));
$j = json_decode($x);
$pager->setItemsPerPage($j->items_page);
}
if (!empty($j->results)) {
$id = 0;
$entries = [];
foreach ($j->results as $jj) {
$alt_text = "";
$contact_details = Model\Contact::getDetailsByURL($jj->url, local_user());
$itemurl = (($contact_details["addr"] != "") ? $contact_details["addr"] : $jj->url);
// If We already know this contact then don't show the "connect" button
if ($jj->cid > 0) {
$connlnk = "";
$conntxt = "";
$contact = DBA::selectFirst('contact', [], ['id' => $jj->cid]);
if (DBA::isResult($contact)) {
$photo_menu = Model\Contact::photoMenu($contact);
$details = Module\Contact::getContactTemplateVars($contact);
$alt_text = $details['alt_text'];
} else {
$photo_menu = [];
}
} else {
$connlnk = System::baseUrl().'/follow/?url='.(!empty($jj->connect) ? $jj->connect : $jj->url);
$conntxt = L10n::t('Connect');
$contact = DBA::selectFirst('contact', [], ['id' => $jj->pcid]);
if (DBA::isResult($contact)) {
$photo_menu = Model\Contact::photoMenu($contact);
} else {
$photo_menu = [];
}
$photo_menu['profile'] = [L10n::t("View Profile"), Model\Contact::magicLink($jj->url)];
$photo_menu['follow'] = [L10n::t("Connect/Follow"), $connlnk];
}
$jj->photo = str_replace("http:///photo/", get_server()."/photo/", $jj->photo);
$entry = [
'alt_text' => $alt_text,
'url' => Model\Contact::magicLink($jj->url),
'itemurl' => $itemurl,
'name' => $jj->name,
'thumb' => ProxyUtils::proxifyUrl($jj->photo, false, ProxyUtils::SIZE_THUMB),
'img_hover' => $jj->tags,
'conntxt' => $conntxt,
'connlnk' => $connlnk,
'photo_menu' => $photo_menu,
'details' => $contact_details['location'],
'tags' => $contact_details['keywords'],
'about' => $contact_details['about'],
'account_type' => Model\Contact::getAccountType($contact_details),
'network' => ContactSelector::networkToName($jj->network, $jj->url),
'id' => ++$id,
];
$entries[] = $entry;
}
$tpl = Renderer::getMarkupTemplate('viewcontact_template.tpl');
$o .= Renderer::replaceMacros($tpl,[
'title' => $header,
'$contacts' => $entries,
'$paginate' => $pager->renderFull($j->total),
]);
} else {
info(L10n::t('No matches') . EOL);
}
}
return $o;
}

View File

@ -20,6 +20,7 @@ use Friendica\Model\Group;
use Friendica\Model\Item;
use Friendica\Model\Profile;
use Friendica\Module\Objects;
use Friendica\Network\HTTPException;
use Friendica\Protocol\ActivityPub;
use Friendica\Protocol\DFRN;
use Friendica\Util\Strings;
@ -76,7 +77,11 @@ function display_init(App $a)
}
if (!DBA::isResult($item)) {
System::httpExit(404);
return;
}
if ($a->argc >= 3 && $nick == 'feed-item') {
displayShowFeed($item['id'], $a->argc > 3 && $a->argv[3] == 'conversation.atom');
}
if ($a->argc >= 3 && $nick == 'feed-item') {
@ -185,23 +190,13 @@ function display_fetchauthor($a, $item)
$profiledata["photo"] = System::removedBaseUrl($profiledata["photo"]);
if (local_user()) {
if (in_array($profiledata["network"], [Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS])) {
$profiledata["remoteconnect"] = System::baseUrl()."/follow?url=".urlencode($profiledata["url"]);
}
} elseif ($profiledata["network"] == Protocol::DFRN) {
$connect = str_replace("/profile/", "/dfrn_request/", $profiledata["url"]);
$profiledata["remoteconnect"] = $connect;
}
return($profiledata);
return $profiledata;
}
function display_content(App $a, $update = false, $update_uid = 0)
{
if (Config::get('system','block_public') && !local_user() && !remote_user()) {
notice(L10n::t('Public access denied.') . EOL);
return;
throw new HTTPException\ForbiddenException(L10n::t('Public access denied.'));
}
$o = '';
@ -254,7 +249,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
}
if (!$item_id) {
System::httpExit(404);
throw new HTTPException\NotFoundException(L10n::t('The requested item doesn\'t exist or has been deleted.'));
}
// We are displaying an "alternate" link if that post was public. See issue 2864
@ -303,8 +298,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
$is_owner = (local_user() && (in_array($a->profile['profile_uid'], [local_user(), 0])) ? true : false);
if (!empty($a->profile['hidewall']) && !$is_owner && !$is_remote_contact) {
notice(L10n::t('Access to this profile has been restricted.') . EOL);
return;
throw new HTTPException\ForbiddenException(L10n::t('Access to this profile has been restricted.'));
}
// We need the editor here to be able to reshare an item.
@ -340,7 +334,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
$item = Item::selectFirstForUser(local_user(), $fields, $condition);
if (!DBA::isResult($item)) {
System::httpExit(404);
throw new HTTPException\NotFoundException(L10n::t('The requested item doesn\'t exist or has been deleted.'));
}
$item['uri'] = $item['parent-uri'];
@ -415,7 +409,7 @@ function displayShowFeed($item_id, $conversation)
{
$xml = DFRN::itemFeed($item_id, $conversation);
if ($xml == '') {
System::httpExit(500);
throw new HTTPException\InternalServerErrorException(L10n::t('The feed for this item is unavailable.'));
}
header("Content-type: application/atom+xml");
echo $xml;

View File

@ -8,7 +8,6 @@ use Friendica\Content\Feature;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Model\FileTag;
use Friendica\Model\Item;
use Friendica\Database\DBA;
@ -48,7 +47,6 @@ function editpost_content(App $a)
$tpl = Renderer::getMarkupTemplate('jot-header.tpl');
$a->page['htmlhead'] .= Renderer::replaceMacros($tpl, [
'$baseurl' => System::baseUrl(),
'$ispublic' => '&nbsp;', // L10n::t('Visible to <strong>everybody</strong>'),
'$geotag' => $geotag,
'$nickname' => $a->user['nickname']
@ -91,7 +89,6 @@ function editpost_content(App $a)
'$posttype' => $item['post-type'],
'$content' => undo_post_tagging($item['body']),
'$post_id' => $post_id,
'$baseurl' => System::baseUrl(),
'$defloc' => $a->user['default-location'],
'$visitor' => 'none',
'$pvisit' => 'none',

View File

@ -21,6 +21,7 @@ use Friendica\Module\Login;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
use Friendica\Worker\Delivery;
function events_init(App $a)
{
@ -195,7 +196,7 @@ function events_post(App $a)
$item_id = Event::store($datarray);
if (!$cid) {
Worker::add(PRIORITY_HIGH, "Notifier", "event", $item_id);
Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $item_id);
}
$a->internalRedirect('events');
@ -237,7 +238,6 @@ function events_content(App $a)
$htpl = Renderer::getMarkupTemplate('event_head.tpl');
$a->page['htmlhead'] .= Renderer::replaceMacros($htpl, [
'$baseurl' => System::baseUrl(),
'$module_url' => '/events',
'$modparams' => 1,
'$i18n' => $i18n,
@ -247,7 +247,7 @@ function events_content(App $a)
$tabs = '';
// tabs
if ($a->theme_events_in_profile) {
$tabs = Profile::getTabs($a, true);
$tabs = Profile::getTabs($a, 'events', true);
}
$mode = 'view';
@ -379,7 +379,6 @@ function events_content(App $a)
}
$o = Renderer::replaceMacros($tpl, [
'$baseurl' => System::baseUrl(),
'$tabs' => $tabs,
'$title' => L10n::t('Events'),
'$view' => L10n::t('View'),

View File

@ -11,6 +11,7 @@ use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Object\Image;
use Friendica\Util\Strings;
/**
* @param App $a
@ -27,6 +28,12 @@ function fbrowser_content(App $a)
exit();
}
// Needed to match the correct template in a module that uses a different theme than the user/site/default
$theme = Strings::sanitizeFilePathItem(defaults($_GET, 'theme', null));
if ($theme && is_file("view/theme/$theme/config.php")) {
$a->setCurrentTheme($theme);
}
$template_file = "filebrowser.tpl";
$o = '';
@ -97,7 +104,6 @@ function fbrowser_content(App $a)
$o = Renderer::replaceMacros($tpl, [
'$type' => 'image',
'$baseurl' => System::baseUrl(),
'$path' => $path,
'$folders' => $albums,
'$files' => $files,
@ -127,7 +133,6 @@ function fbrowser_content(App $a)
$tpl = Renderer::getMarkupTemplate($template_file);
$o = Renderer::replaceMacros($tpl, [
'$type' => 'file',
'$baseurl' => System::baseUrl(),
'$path' => [ [ "", L10n::t("Files")] ],
'$folders' => false,
'$files' => $files,

View File

@ -1,50 +0,0 @@
<?php
/**
* @file_tag_list_to_file mod/feedtest.php
*/
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Protocol\Feed;
use Friendica\Util\Network;
function feedtest_content(App $a)
{
if (!local_user()) {
info(L10n::t('You must be logged in to use this module'));
return;
};
$result = [];
if (!empty($_REQUEST['url'])) {
$url = $_REQUEST['url'];
$importer = DBA::selectFirst('user', [], ['uid' => local_user()]);
$contact_id = Contact::getIdForURL($url, local_user(), true);
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id]);
$xml = Network::fetchUrl($contact['poll']);
$dummy = null;
$import_result = Feed::import($xml, $importer, $contact, $dummy, true);
$result = [
'input' => $xml,
'output' => var_export($import_result, true),
];
}
$tpl = Renderer::getMarkupTemplate('feedtest.tpl');
$o = Renderer::replaceMacros($tpl, [
'$url' => ['url', L10n::t('Source URL'), defaults($_REQUEST, 'url', ''), ''],
'$result' => $result
]);
return $o;
}

View File

@ -1,62 +0,0 @@
<?php
/*
This file is part of the Diaspora protocol. It is used for fetching single public posts.
*/
use Friendica\App;
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Protocol\Diaspora;
use Friendica\Model\Item;
use Friendica\Model\User;
use Friendica\Util\Strings;
use Friendica\Database\DBA;
function fetch_init(App $a)
{
if (($a->argc != 3) || (!in_array($a->argv[1], ["post", "status_message", "reshare"]))) {
System::httpExit(404);
}
$guid = $a->argv[2];
// Fetch the item
$fields = ['uid', 'title', 'body', 'guid', 'contact-id', 'private', 'created', 'app', 'location', 'coord', 'network',
'event-id', 'resource-id', 'author-link', 'author-avatar', 'author-name', 'plink', 'owner-link', 'attach'];
$condition = ['wall' => true, 'private' => false, 'guid' => $guid, 'network' => [Protocol::DFRN, Protocol::DIASPORA]];
$item = Item::selectFirst($fields, $condition);
if (!DBA::isResult($item)) {
$condition = ['guid' => $guid, 'network' => [Protocol::DFRN, Protocol::DIASPORA]];
$item = Item::selectFirst(['author-link'], $condition);
if (DBA::isResult($item)) {
$parts = parse_url($item["author-link"]);
$host = $parts["scheme"]."://".$parts["host"];
if (Strings::normaliseLink($host) != Strings::normaliseLink(System::baseUrl())) {
$location = $host."/fetch/".$a->argv[1]."/".urlencode($guid);
header("HTTP/1.1 301 Moved Permanently");
header("Location:".$location);
exit();
}
}
System::httpExit(404);
}
// Fetch some data from the author (We could combine both queries - but I think this is more readable)
$user = User::getOwnerDataById($item["uid"]);
if (!$user) {
System::httpExit(404);
}
$status = Diaspora::buildStatus($item, $user);
$xml = Diaspora::buildPostXml($status["type"], $status["message"]);
// Send the envelope
header("Content-Type: application/magic-envelope+xml; charset=utf-8");
echo Diaspora::buildMagicEnvelope($xml, $user);
exit();
}

View File

@ -1,42 +0,0 @@
<?php
/**
* @file mod/filer.php
*/
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\PConfig;
use Friendica\Core\Renderer;
use Friendica\Model\FileTag;
use Friendica\Util\XML;
function filer_content(App $a)
{
if (! local_user()) {
exit();
}
$term = XML::unescape(trim(defaults($_GET, 'term', '')));
$item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0);
Logger::log('filer: tag ' . $term . ' item ' . $item_id);
if ($item_id && strlen($term)) {
// file item
FileTag::saveFile(local_user(), $item_id, $term);
} else {
// return filer dialog
$filetags = PConfig::get(local_user(), 'system', 'filetags');
$filetags = FileTag::fileToList($filetags, 'file');
$filetags = explode(",", $filetags);
$tpl = Renderer::getMarkupTemplate("filer_dialog.tpl");
$o = Renderer::replaceMacros($tpl, [
'$field' => ['term', L10n::t("Save to Folder:"), '', '', $filetags, L10n::t('- select -')],
'$submit' => L10n::t('Save'),
]);
echo $o;
}
exit();
}

View File

@ -1,40 +0,0 @@
<?php
use Friendica\App;
use Friendica\Core\Logger;
use Friendica\Model\FileTag;
use Friendica\Util\XML;
function filerm_content(App $a)
{
if (! local_user())
{
exit();
}
$term = XML::unescape(trim(defaults($_GET, 'term', '')));
$cat = XML::unescape(trim(defaults($_GET, 'cat', '')));
$category = (($cat) ? true : false);
if ($category)
{
$term = $cat;
}
$item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0);
Logger::log('filerm: tag ' . $term . ' item ' . $item_id . ' category ' . ($category ? 'true' : 'false'));
if ($item_id && strlen($term)) {
if (FileTag::unsaveFile(local_user(), $item_id, $term, $category)) {
info('Item removed');
}
}
else {
info('Item was not deleted');
}
$a->internalRedirect('/network?f=&file=' . rawurlencode($term));
exit();
}

View File

@ -17,7 +17,7 @@ use Friendica\Util\Strings;
function follow_post(App $a)
{
if (!local_user()) {
System::httpExit(403, ['title' => L10n::t('Access denied.')]);
throw new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Access denied.'));
}
if (isset($_REQUEST['cancel'])) {
@ -91,32 +91,34 @@ function follow_content(App $a)
$ret = Probe::uri($url);
if (($ret['network'] == Protocol::DIASPORA) && !Config::get('system', 'diaspora_enabled')) {
$protocol = Contact::getProtocol($ret['url'], $ret['network']);
if (($protocol == Protocol::DIASPORA) && !Config::get('system', 'diaspora_enabled')) {
notice(L10n::t("Diaspora support isn't enabled. Contact can't be added."));
$submit = '';
//$a->internalRedirect($_SESSION['return_path']);
// NOTREACHED
}
if (($ret['network'] == Protocol::OSTATUS) && Config::get('system', 'ostatus_disabled')) {
if (($protocol == Protocol::OSTATUS) && Config::get('system', 'ostatus_disabled')) {
notice(L10n::t("OStatus support is disabled. Contact can't be added."));
$submit = '';
//$a->internalRedirect($_SESSION['return_path']);
// NOTREACHED
}
if ($ret['network'] == Protocol::PHANTOM) {
if ($protocol == Protocol::PHANTOM) {
notice(L10n::t("The network type couldn't be detected. Contact can't be added."));
$submit = '';
//$a->internalRedirect($_SESSION['return_path']);
// NOTREACHED
}
if ($ret['network'] == Protocol::MAIL) {
if ($protocol == Protocol::MAIL) {
$ret['url'] = $ret['addr'];
}
if (($ret['network'] === Protocol::DFRN) && !DBA::isResult($r)) {
if (($protocol === Protocol::DFRN) && !DBA::isResult($r)) {
$request = $ret['request'];
$tpl = Renderer::getMarkupTemplate('dfrn_request.tpl');
} else {
@ -147,7 +149,7 @@ function follow_content(App $a)
$gcontact_id = $r[0]['id'];
}
if ($ret['network'] === Protocol::DIASPORA) {
if ($protocol === Protocol::DIASPORA) {
$r[0]['location'] = '';
$r[0]['about'] = '';
}

View File

@ -1,141 +0,0 @@
<?php
/**
* @file mod/friendica.php
*/
use Friendica\App;
use Friendica\Core\Addon;
use Friendica\Core\Config;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Module\Register;
function friendica_init(App $a)
{
if (!empty($a->argv[1]) && ($a->argv[1] == "json")) {
$register_policies = [
Register::CLOSED => 'REGISTER_CLOSED',
Register::APPROVE => 'REGISTER_APPROVE',
Register::OPEN => 'REGISTER_OPEN'
];
$register_policy_int = intval(Config::get('config', 'register_policy'));
if ($register_policy_int !== Register::CLOSED && Config::get('config', 'invitation_only')) {
$register_policy = 'REGISTER_INVITATION';
} else {
$register_policy = $register_policies[$register_policy_int];
}
$condition = [];
$admin = false;
if (!empty(Config::get('config', 'admin_nickname'))) {
$condition['nickname'] = Config::get('config', 'admin_nickname');
}
if (!empty(Config::get('config', 'admin_email'))) {
$adminlist = explode(",", str_replace(" ", "", Config::get('config', 'admin_email')));
$condition['email'] = $adminlist[0];
$administrator = DBA::selectFirst('user', ['username', 'nickname'], $condition);
if (DBA::isResult($administrator)) {
$admin = [
'name' => $administrator['username'],
'profile'=> System::baseUrl() . '/profile/' . $administrator['nickname'],
];
}
}
$visible_addons = Addon::getVisibleList();
Config::load('feature_lock');
$locked_features = [];
$featureLock = Config::get('config', 'feature_lock');
if (isset($featureLock)) {
foreach ($featureLock as $k => $v) {
if ($k === 'config_loaded') {
continue;
}
$locked_features[$k] = intval($v);
}
}
$data = [
'version' => FRIENDICA_VERSION,
'url' => System::baseUrl(),
'addons' => $visible_addons,
'locked_features' => $locked_features,
'explicit_content' => (int)Config::get('system', 'explicit_content', false),
'language' => Config::get('system','language'),
'register_policy' => $register_policy,
'admin' => $admin,
'site_name' => Config::get('config', 'sitename'),
'platform' => FRIENDICA_PLATFORM,
'info' => Config::get('config', 'info'),
'no_scrape_url' => System::baseUrl().'/noscrape'
];
header('Content-type: application/json; charset=utf-8');
echo json_encode($data);
exit();
}
}
function friendica_content(App $a)
{
$o = '<h1>Friendica</h1>' . PHP_EOL;
$o .= '<p>';
$o .= L10n::t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.',
'<strong>' . FRIENDICA_VERSION . '</strong>', System::baseUrl(), '<strong>' . DB_UPDATE_VERSION . '</strong>',
'<strong>' . Config::get("system", "post_update_version") . '</strong>');
$o .= '</p>' . PHP_EOL;
$o .= '<p>';
$o .= L10n::t('Please visit <a href="https://friendi.ca">Friendi.ca</a> to learn more about the Friendica project.') . PHP_EOL;
$o .= '</p>' . PHP_EOL;
$o .= '<p>';
$o .= L10n::t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">'.L10n::t('the bugtracker at github').'</a>';
$o .= '</p>' . PHP_EOL;
$o .= '<p>';
$o .= L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca');
$o .= '</p>' . PHP_EOL;
$visible_addons = Addon::getVisibleList();
if (count($visible_addons)) {
$o .= '<p>' . L10n::t('Installed addons/apps:') . '</p>' . PHP_EOL;
$sorted = $visible_addons;
$s = '';
sort($sorted);
foreach ($sorted as $p) {
if (strlen($p)) {
if (strlen($s)) {
$s .= ', ';
}
$s .= $p;
}
}
$o .= '<div style="margin-left: 25px; margin-right: 25px; margin-bottom: 25px;">' . $s . '</div>' . PHP_EOL;
} else {
$o .= '<p>' . L10n::t('No installed addons/apps') . '</p>' . PHP_EOL;
}
if (Config::get('system', 'tosdisplay'))
{
$o .= '<p>'.L10n::t('Read about the <a href="%1$s/tos">Terms of Service</a> of this node.', System::baseurl()).'</p>';
}
$blocklist = Config::get('system', 'blocklist', []);
if (!empty($blocklist)) {
$o .= '<div id="about_blocklist"><p>' . L10n::t('On this server the following remote servers are blocked.') . '</p>' . PHP_EOL;
$o .= '<table class="table"><thead><tr><th>' . L10n::t('Blocked domain') . '</th><th>' . L10n::t('Reason for the block') . '</th></thead><tbody>' . PHP_EOL;
foreach ($blocklist as $b) {
$o .= '<tr><td>' . $b['domain'] .'</td><td>' . $b['reason'] . '</td></tr>' . PHP_EOL;
}
$o .= '</tbody></table></div>' . PHP_EOL;
}
Hook::callAll('about_hook', $o);
return $o;
}

View File

@ -10,10 +10,11 @@ use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
function fsuggest_post(App $a)
{
if (! local_user()) {
if (!local_user()) {
return;
}
@ -22,53 +23,38 @@ function fsuggest_post(App $a)
}
$contact_id = intval($a->argv[1]);
if (empty($contact_id)) {
return;
}
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => local_user()]);
if (! DBA::isResult($contact)) {
// We do query the "uid" as well to ensure that it is our contact
if (!DBA::exists('contact', ['id' => $contact_id, 'uid' => local_user()])) {
notice(L10n::t('Contact not found.') . EOL);
return;
}
$new_contact = intval($_POST['suggest']);
$suggest_contact_id = intval($_POST['suggest']);
if (empty($suggest_contact_id)) {
return;
}
$hash = Strings::getRandomHex();
// We do query the "uid" as well to ensure that it is our contact
$contact = DBA::selectFirst('contact', ['name', 'url', 'request', 'avatar'], ['id' => $suggest_contact_id, 'uid' => local_user()]);
if (!DBA::isResult($contact)) {
notice(L10n::t('Suggested contact not found.') . EOL);
return;
}
$note = Strings::escapeHtml(trim(defaults($_POST, 'note', '')));
if ($new_contact) {
$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($new_contact),
intval(local_user())
);
if (DBA::isResult($r)) {
q("INSERT INTO `fsuggest` ( `uid`,`cid`,`name`,`url`,`request`,`photo`,`note`,`created`)
VALUES ( %d, %d, '%s','%s','%s','%s','%s','%s')",
intval(local_user()),
intval($contact_id),
DBA::escape($contact['name']),
DBA::escape($contact['url']),
DBA::escape($contact['request']),
DBA::escape($contact['photo']),
DBA::escape($hash),
DBA::escape(DateTimeFormat::utcNow())
);
$r = q("SELECT `id` FROM `fsuggest` WHERE `note` = '%s' AND `uid` = %d LIMIT 1",
DBA::escape($hash),
intval(local_user())
);
if (DBA::isResult($r)) {
$fsuggest_id = $contact['id'];
q("UPDATE `fsuggest` SET `note` = '%s' WHERE `id` = %d AND `uid` = %d",
DBA::escape($note),
intval($fsuggest_id),
intval(local_user())
);
Worker::add(PRIORITY_HIGH, 'Notifier', 'suggest', $fsuggest_id);
}
$fields = ['uid' => local_user(),'cid' => $contact_id, 'name' => $contact['name'],
'url' => $contact['url'], 'request' => $contact['request'],
'photo' => $contact['avatar'], 'note' => $note, 'created' => DateTimeFormat::utcNow()];
DBA::insert('fsuggest', $fields);
info(L10n::t('Friend suggestion sent.') . EOL);
}
}
Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::SUGGESTION, DBA::lastInsertId());
info(L10n::t('Friend suggestion sent.') . EOL);
}
function fsuggest_content(App $a)

View File

@ -17,9 +17,7 @@ function hcard_init(App $a)
if ($a->argc > 1) {
$which = $a->argv[1];
} else {
notice(L10n::t('No profile') . EOL);
$a->error = 404;
return;
throw new \Friendica\Network\HTTPException\NotFoundException(L10n::t('No profile'));
}
$profile = 0;

View File

@ -1,119 +0,0 @@
<?php
/**
* @file mod/help.php
*/
use Friendica\App;
use Friendica\Content\Nav;
use Friendica\Content\Text\Markdown;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Util\Strings;
function load_doc_file($s)
{
$lang = Config::get('system', 'language');
$b = basename($s);
$d = dirname($s);
if (file_exists("$d/$lang/$b")) {
return file_get_contents("$d/$lang/$b");
}
if (file_exists($s)) {
return file_get_contents($s);
}
return '';
}
function help_content(App $a)
{
Nav::setSelected('help');
$text = '';
$filename = '';
if ($a->argc > 1) {
$path = '';
// looping through the argv keys bigger than 0 to build
// a path relative to /help
for ($x = 1; $x < $a->argc; $x ++) {
if (strlen($path)) {
$path .= '/';
}
$path .= $a->getArgumentValue($x);
}
$title = basename($path);
$filename = $path;
$text = load_doc_file('doc/' . $path . '.md');
$a->page['title'] = L10n::t('Help:') . ' ' . str_replace('-', ' ', Strings::escapeTags($title));
}
$home = load_doc_file('doc/Home.md');
if (!$text) {
$text = $home;
$filename = "Home";
$a->page['title'] = L10n::t('Help');
} else {
$a->page['aside'] = Markdown::convert($home, false);
}
if (!strlen($text)) {
header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . L10n::t('Not Found'));
$tpl = Renderer::getMarkupTemplate("404.tpl");
return Renderer::replaceMacros($tpl, [
'$message' => L10n::t('Page not found.')
]);
}
$html = Markdown::convert($text, false);
if ($filename !== "Home") {
// create TOC but not for home
$lines = explode("\n", $html);
$toc = "<h2>TOC</h2><ul id='toc'>";
$lastlevel = 1;
$idnum = [0, 0, 0, 0, 0, 0, 0];
foreach ($lines as &$line) {
if (substr($line, 0, 2) == "<h") {
$level = substr($line, 2, 1);
if ($level != "r") {
$level = intval($level);
if ($level < $lastlevel) {
for ($k = $level; $k < $lastlevel; $k++) {
$toc .= "</ul></li>";
}
for ($k = $level + 1; $k < count($idnum); $k++) {
$idnum[$k] = 0;
}
}
if ($level > $lastlevel) {
$toc .= "<li><ul>";
}
$idnum[$level] ++;
$id = implode("_", array_slice($idnum, 1, $level));
$href = System::baseUrl() . "/help/{$filename}#{$id}";
$toc .= "<li><a href='{$href}'>" . strip_tags($line) . "</a></li>";
$line = "<a name='{$id}'></a>" . $line;
$lastlevel = $level;
}
}
}
for ($k = 0; $k < $lastlevel; $k++) {
$toc .= "</ul>";
}
$html = implode("\n", $lines);
$a->page['aside'] = '<div class="help-aside-wrapper widget"><div id="toc-wrapper">' . $toc . '</div>' . $a->page['aside'] . '</div>';
}
return $html;
}

View File

@ -1,64 +0,0 @@
<?php
/**
* @file mod/home.php
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Module\Login;
if(! function_exists('home_init')) {
function home_init(App $a) {
$ret = [];
Hook::callAll('home_init',$ret);
if (local_user() && ($a->user['nickname'])) {
$a->internalRedirect('network');
}
if (strlen(Config::get('system','singleuser'))) {
$a->internalRedirect('profile/' . Config::get('system','singleuser'));
}
}}
if(! function_exists('home_content')) {
function home_content(App $a) {
if (!empty($_SESSION['theme'])) {
unset($_SESSION['theme']);
}
if (!empty($_SESSION['mobile-theme'])) {
unset($_SESSION['mobile-theme']);
}
$customhome = false;
$defaultheader = '<h1>' . (Config::get('config', 'sitename') ? L10n::t('Welcome to %s', Config::get('config', 'sitename')) : '') . '</h1>';
$homefilepath = $a->getBasePath() . "/home.html";
$cssfilepath = $a->getBasePath() . "/home.css";
if (file_exists($homefilepath)) {
$customhome = $homefilepath;
if (file_exists($cssfilepath)) {
$a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="'.System::baseUrl().'/home.css'.'" media="all" />';
}
}
$login = Login::form($a->query_string, intval(Config::get('config', 'register_policy')) === \Friendica\Module\Register::CLOSED ? 0 : 1);
$content = '';
Hook::callAll("home_content",$content);
$tpl = Renderer::getMarkupTemplate('home.tpl');
return Renderer::replaceMacros($tpl, [
'$defaultheader' => $defaultheader,
'$customhome' => $customhome,
'$login' => $login,
'$content' => $content
]);
}}

View File

@ -1,34 +0,0 @@
<?php
/**
* @file mod/hostxrd.php
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Protocol\Salmon;
use Friendica\Util\Crypto;
function hostxrd_init(App $a)
{
header('Access-Control-Allow-Origin: *');
header("Content-type: text/xml");
$pubkey = Config::get('system', 'site_pubkey');
if (! $pubkey) {
$res = Crypto::newKeypair(1024);
Config::set('system','site_prvkey', $res['prvkey']);
Config::set('system','site_pubkey', $res['pubkey']);
}
$tpl = Renderer::getMarkupTemplate('xrd_host.tpl');
echo Renderer::replaceMacros($tpl, [
'$zhost' => $a->getHostName(),
'$zroot' => System::baseUrl(),
'$domain' => System::baseUrl(),
'$bigkey' => Salmon::salmonKey(Config::get('system', 'site_pubkey'))]
);
exit();
}

View File

@ -31,7 +31,7 @@ function hovercard_content()
// Get out if the system doesn't have public access allowed
if (intval(Config::get('system', 'block_public'))) {
System::httpExit(401);
throw new \Friendica\Network\HTTPException\ForbiddenException();
}
// Return the raw content of the template. We use this to make templates usable for js functions.

View File

@ -1,158 +0,0 @@
<?php
/**
* Module: invite.php
*
* Send email invitations to join social network
*
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\PConfig;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Module\Register;
use Friendica\Protocol\Email;
use Friendica\Util\Strings;
function invite_post(App $a)
{
if (! local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
BaseModule::checkFormSecurityTokenRedirectOnError('/', 'send_invite');
$max_invites = intval(Config::get('system', 'max_invites'));
if (! $max_invites) {
$max_invites = 50;
}
$current_invites = intval(PConfig::get(local_user(), 'system', 'sent_invites'));
if ($current_invites > $max_invites) {
notice(L10n::t('Total invitation limit exceeded.') . EOL);
return;
}
$recipients = !empty($_POST['recipients']) ? explode("\n", $_POST['recipients']) : [];
$message = !empty($_POST['message']) ? Strings::escapeTags(trim($_POST['message'])) : '';
$total = 0;
$invitation_only = false;
$invites_remaining = null;
if (Config::get('system', 'invitation_only')) {
$invitation_only = true;
$invites_remaining = PConfig::get(local_user(), 'system', 'invites_remaining');
if ((! $invites_remaining) && (! is_site_admin())) {
return;
}
}
foreach ($recipients as $recipient) {
$recipient = trim($recipient);
if (!filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
notice(L10n::t('%s : Not a valid email address.', $recipient) . EOL);
continue;
}
if ($invitation_only && ($invites_remaining || is_site_admin())) {
$code = Friendica\Model\Register::createForInvitation();
$nmessage = str_replace('$invite_code', $code, $message);
if (! is_site_admin()) {
$invites_remaining --;
if ($invites_remaining >= 0) {
PConfig::set(local_user(), 'system', 'invites_remaining', $invites_remaining);
} else {
return;
}
}
} else {
$nmessage = $message;
}
$additional_headers = 'From: ' . $a->user['email'] . "\n"
. 'Sender: ' . $a->getSenderEmailAddress() . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit';
$res = mail(
$recipient,
Email::encodeHeader(L10n::t('Please join us on Friendica'), 'UTF-8'),
$nmessage,
$additional_headers);
if ($res) {
$total ++;
$current_invites ++;
PConfig::set(local_user(), 'system', 'sent_invites', $current_invites);
if ($current_invites > $max_invites) {
notice(L10n::t('Invitation limit exceeded. Please contact your site administrator.') . EOL);
return;
}
} else {
notice(L10n::t('%s : Message delivery failed.', $recipient) . EOL);
}
}
notice(L10n::tt("%d message sent.", "%d messages sent.", $total) . EOL);
return;
}
function invite_content(App $a) {
if (! local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
$tpl = Renderer::getMarkupTemplate('invite.tpl');
$invonly = false;
if (Config::get('system', 'invitation_only')) {
$invonly = true;
$x = PConfig::get(local_user(), 'system', 'invites_remaining');
if ((! $x) && (! is_site_admin())) {
notice(L10n::t('You have no more invitations available') . EOL);
return '';
}
}
$dirloc = Config::get('system', 'directory');
if (strlen($dirloc)) {
if (intval(Config::get('config', 'register_policy')) === Register::CLOSED) {
$linktxt = L10n::t('Visit %s for a list of public sites that you can join. Friendica members on other sites can all connect with each other, as well as with members of many other social networks.', $dirloc . '/servers');
} else {
$linktxt = L10n::t('To accept this invitation, please visit and register at %s or any other public Friendica website.', System::baseUrl())
. "\r\n" . "\r\n" . L10n::t('Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks. See %s for a list of alternate Friendica sites you can join.', $dirloc . '/servers');
}
} else { // there is no global directory URL defined
if (intval(Config::get('config', 'register_policy')) === Register::CLOSED) {
$o = L10n::t('Our apologies. This system is not currently configured to connect with other public sites or invite members.');
return $o;
} else {
$linktxt = L10n::t('To accept this invitation, please visit and register at %s.', System::baseUrl()
. "\r\n" . "\r\n" . L10n::t('Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks.'));
}
}
$o = Renderer::replaceMacros($tpl, [
'$form_security_token' => BaseModule::getFormSecurityToken("send_invite"),
'$title' => L10n::t('Send invitations'),
'$recipients' => ['recipients', L10n::t('Enter email addresses, one per line:')],
'$message' => ['message', L10n::t('Your message:'),L10n::t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n"
. $linktxt
. "\r\n" . "\r\n" . (($invonly) ? L10n::t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .L10n::t('Once you have registered, please connect with me via my profile page at:')
. "\r\n" . "\r\n" . System::baseUrl() . '/profile/' . $a->user['nickname']
. "\r\n" . "\r\n" . L10n::t('For more information about the Friendica project and why we feel it is important, please visit http://friendi.ca') . "\r\n" . "\r\n"],
'$submit' => L10n::t('Submit')
]);
return $o;
}

View File

@ -27,12 +27,12 @@ use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\Model\Attach;
use Friendica\Model\Contact;
use Friendica\Model\Conversation;
use Friendica\Model\FileTag;
use Friendica\Model\Item;
use Friendica\Model\Photo;
use Friendica\Model\Attach;
use Friendica\Model\Term;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\Email;
@ -40,6 +40,7 @@ use Friendica\Util\DateTimeFormat;
use Friendica\Util\Emailer;
use Friendica\Util\Security;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
require_once 'include/items.php';
@ -327,10 +328,9 @@ function item_post(App $a) {
}
}
if (!empty($categories))
{
if (!empty($categories)) {
// get the "fileas" tags for this post
$filedas = FileTag::fileToList($categories, 'file');
$filedas = FileTag::fileToArray($categories);
}
// save old and new categories, so we can determine what needs to be deleted from pconfig
@ -338,10 +338,9 @@ function item_post(App $a) {
$categories = FileTag::listToFile(trim(defaults($_REQUEST, 'category', '')), 'category');
$categories_new = $categories;
if (!empty($filedas))
{
if (!empty($filedas) && is_array($filedas)) {
// append the fileas stuff to the new categories list
$categories .= FileTag::listToFile($filedas, 'file');
$categories .= FileTag::arrayToFile($filedas);
}
// get contact info for poster
@ -605,8 +604,6 @@ function item_post(App $a) {
$origin = $_REQUEST['origin'];
}
$notify_type = ($toplevel_item_id ? 'comment-new' : 'wall-new');
$uri = ($message_id ? $message_id : Item::newURI($api_source ? $profile_uid : $uid, $guid));
// Fallback so that we alway have a parent uri
@ -871,7 +868,7 @@ function item_post(App $a) {
// When we are doing some forum posting via ! we have to start the notifier manually.
// These kind of posts don't initiate the notifier call in the item class.
if ($only_to_forum) {
Worker::add(PRIORITY_HIGH, "Notifier", $notify_type, $post_id);
Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $post_id);
}
Logger::log('post_complete');

View File

@ -1,48 +0,0 @@
<?php
use Friendica\App;
use Friendica\Model\Item;
use Friendica\Util\Strings;
function like_content(App $a) {
if (!local_user() && !remote_user()) {
return false;
}
$verb = Strings::escapeTags(trim($_GET['verb']));
if (!$verb) {
$verb = 'like';
}
$item_id = (($a->argc > 1) ? Strings::escapeTags(trim($a->argv[1])) : 0);
$r = Item::performLike($item_id, $verb);
if (!$r) {
return;
}
// See if we've been passed a return path to redirect to
$return_path = defaults($_REQUEST, 'return', '');
like_content_return($a, $return_path);
exit();
}
// Decide how to return. If we were called with a 'return' argument,
// then redirect back to the calling page. If not, just quietly end
function like_content_return(App $a, $return_path) {
if ($return_path) {
$rand = '_=' . time();
if (strpos($return_path, '?')) {
$rand = "&$rand";
} else {
$rand = "?$rand";
}
$a->internalRedirect($return_path . $rand);
}
}

View File

@ -1,59 +0,0 @@
<?php
/**
* @file mod/localtime.php
*/
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Temporal;
function localtime_post(App $a)
{
$t = $_REQUEST['time'];
if (! $t) {
$t = 'now';
}
$bd_format = L10n::t('l F d, Y \@ g:i A') ; // Friday January 18, 2011 @ 8 AM
if ($_POST['timezone']) {
$a->data['mod-localtime'] = DateTimeFormat::convert($t, $_POST['timezone'], 'UTC', $bd_format);
}
}
function localtime_content(App $a)
{
$t = $_REQUEST['time'];
if (! $t) {
$t = 'now';
}
$o = '<h3>' . L10n::t('Time Conversion') . '</h3>';
$o .= '<p>' . L10n::t('Friendica provides this service for sharing events with other networks and friends in unknown timezones.') . '</p>';
$o .= '<p>' . L10n::t('UTC time: %s', $t) . '</p>';
if ($_REQUEST['timezone']) {
$o .= '<p>' . L10n::t('Current timezone: %s', $_REQUEST['timezone']) . '</p>';
}
if (!empty($a->data['mod-localtime'])) {
$o .= '<p>' . L10n::t('Converted localtime: %s', $a->data['mod-localtime']) . '</p>';
}
$o .= '<form action ="' . System::baseUrl() . '/localtime?f=&time=' . $t . '" method="post" >';
$o .= '<p>' . L10n::t('Please select your timezone:') . '</p>';
$o .= Temporal::getTimezoneSelect(($_REQUEST['timezone']) ? $_REQUEST['timezone'] : 'America/Los_Angeles');
$o .= '<input type="submit" name="submit" value="' . L10n::t('Submit') . '" /></form>';
return $o;
}

View File

@ -139,7 +139,6 @@ function lostpass_generate_password($user)
'$lbl5' => '<a href="' . System::baseUrl() . '">' . L10n::t('click here to login') . '</a>.',
'$lbl6' => L10n::t('Your password may be changed from the <em>Settings</em> page after successful login.'),
'$newpass' => $new_password,
'$baseurl' => System::baseUrl()
]);
info("Your password has been reset." . EOL);

View File

@ -1,29 +0,0 @@
<?php
/**
* @file mod/maintenance.php
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Util\Strings;
function maintenance_content(App $a)
{
$reason = Config::get('system', 'maintenance_reason');
if (substr(Strings::normaliseLink($reason), 0, 7) == 'http://') {
header("HTTP/1.1 307 Temporary Redirect");
header("Location:".$reason);
return;
}
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
header('Retry-After: 600');
return Renderer::replaceMacros(Renderer::getMarkupTemplate('maintenance.tpl'), [
'$sysdown' => L10n::t('System down for maintenance'),
'$reason' => $reason
]);
}

View File

@ -2,11 +2,12 @@
/**
* @file mod/manage.php
*/
use Friendica\App;
use Friendica\Core\Authentication;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\Database\DBA;
function manage_post(App $a) {
@ -108,7 +109,7 @@ function manage_post(App $a) {
unset($_SESSION['sysmsg_info']);
}
Authentication::setAuthenticatedSessionForUser($r[0], true, true);
Session::setAuthenticatedForUser($a, $r[0], true, true);
if ($limited_id) {
$_SESSION['submanage'] = $original_id;

View File

@ -1,28 +0,0 @@
<?php
use Friendica\App;
use Friendica\Core\System;
use Friendica\Core\Config;
use Friendica\Core\Renderer;
function manifest_content(App $a) {
$tpl = Renderer::getMarkupTemplate('manifest.tpl');
header('Content-type: application/manifest+json');
$touch_icon = Config::get('system', 'touch_icon', 'images/friendica-128.png');
if ($touch_icon == '') {
$touch_icon = 'images/friendica-128.png';
}
$o = Renderer::replaceMacros($tpl, [
'$baseurl' => System::baseUrl(),
'$touch_icon' => $touch_icon,
'$title' => Config::get('config', 'sitename', 'Friendica'),
]);
echo $o;
exit();
}

View File

@ -1,36 +0,0 @@
<?php
use Friendica\App;
use Friendica\Database\DBA;
function modexp_init(App $a) {
if($a->argc != 2)
exit();
$nick = $a->argv[1];
$r = q("SELECT `spubkey` FROM `user` WHERE `nickname` = '%s' LIMIT 1",
DBA::escape($nick)
);
if (! DBA::isResult($r)) {
exit();
}
$lines = explode("\n",$r[0]['spubkey']);
unset($lines[0]);
unset($lines[count($lines)]);
$x = base64_decode(implode('',$lines));
$r = ASN_BASE::parseASNString($x);
$m = $r[0]->asnData[1]->asnData[0]->asnData[0]->asnData;
$e = $r[0]->asnData[1]->asnData[0]->asnData[1]->asnData;
header("Content-type: application/magic-public-key");
echo 'RSA' . '.' . $m . '.' . $e;
exit();
}

View File

@ -77,9 +77,7 @@ function network_init(App $a)
// convert query string to array. remove friendica args
$query_array = [];
$query_string = str_replace($a->cmd . '?', '', $a->query_string);
parse_str($query_string, $query_array);
array_shift($query_array);
parse_str(parse_url($a->query_string, PHP_URL_QUERY), $query_array);
// fetch last used network view and redirect if needed
if (!$is_a_date_query) {
@ -99,7 +97,7 @@ function network_init(App $a)
if ($remember_tab) {
// redirect if current selected tab is '/network' and
// last selected tab is _not_ '/network?f=&order=comment'.
// last selected tab is _not_ '/network?order=comment'.
// and this isn't a date query
$tab_baseurls = [
@ -111,12 +109,12 @@ function network_init(App $a)
'', //bookmarked
];
$tab_args = [
'f=&order=comment', //all
'f=&order=post', //postord
'f=&conv=1', //conv
'order=comment', //all
'order=post', //postord
'conv=1', //conv
'', //new
'f=&star=1', //starred
'f=&bmark=1', //bookmarked
'star=1', //starred
'bmark=1', //bookmarked
];
$k = array_search('active', $last_sel_tabs);
@ -140,7 +138,7 @@ function network_init(App $a)
if ($remember_tab) {
$net_args = array_merge($query_array, $net_args);
$net_queries = build_querystring($net_args);
$net_queries = http_build_query($net_args);
$redir_url = ($net_queries ? $net_baseurl . '?' . $net_queries : $net_baseurl);
@ -154,7 +152,7 @@ function network_init(App $a)
$a->page['aside'] .= Group::sidebarWidget('network/0', 'network', 'standard', $group_id);
$a->page['aside'] .= ForumManager::widget(local_user(), $cid);
$a->page['aside'] .= posted_date_widget('network', local_user(), false);
$a->page['aside'] .= Widget::postedByYear('network', local_user(), false);
$a->page['aside'] .= Widget::networks('network', defaults($_GET, 'nets', '') );
$a->page['aside'] .= saved_searches($search);
$a->page['aside'] .= Widget::fileAs('network', defaults($_GET, 'file', '') );
@ -202,12 +200,12 @@ function saved_searches($search)
*
* urls -> returns
* '/network' => $no_active = 'active'
* '/network?f=&order=comment' => $comment_active = 'active'
* '/network?f=&order=post' => $postord_active = 'active'
* '/network?f=&conv=1', => $conv_active = 'active'
* '/network?order=comment' => $comment_active = 'active'
* '/network?order=post' => $postord_active = 'active'
* '/network?conv=1', => $conv_active = 'active'
* '/network/new', => $new_active = 'active'
* '/network?f=&star=1', => $starred_active = 'active'
* '/network?f=&bmark=1', => $bookmarked_active = 'active'
* '/network?star=1', => $starred_active = 'active'
* '/network?bmark=1', => $bookmarked_active = 'active'
*
* @param App $a
* @return array ($no_active, $comment_active, $postord_active, $conv_active, $new_active, $starred_active, $bookmarked_active);
@ -973,7 +971,7 @@ function network_tabs(App $a)
$tabs = [
[
'label' => L10n::t('Commented Order'),
'url' => str_replace('/new', '', $cmd) . '?f=&order=comment' . (!empty($_GET['cid']) ? '&cid=' . $_GET['cid'] : ''),
'url' => str_replace('/new', '', $cmd) . '?order=comment' . (!empty($_GET['cid']) ? '&cid=' . $_GET['cid'] : ''),
'sel' => $all_active,
'title' => L10n::t('Sort by Comment Date'),
'id' => 'commented-order-tab',
@ -981,7 +979,7 @@ function network_tabs(App $a)
],
[
'label' => L10n::t('Posted Order'),
'url' => str_replace('/new', '', $cmd) . '?f=&order=post' . (!empty($_GET['cid']) ? '&cid=' . $_GET['cid'] : ''),
'url' => str_replace('/new', '', $cmd) . '?order=post' . (!empty($_GET['cid']) ? '&cid=' . $_GET['cid'] : ''),
'sel' => $postord_active,
'title' => L10n::t('Sort by Post Date'),
'id' => 'posted-order-tab',
@ -991,7 +989,7 @@ function network_tabs(App $a)
$tabs[] = [
'label' => L10n::t('Personal'),
'url' => str_replace('/new', '', $cmd) . (!empty($_GET['cid']) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&conv=1',
'url' => str_replace('/new', '', $cmd) . (!empty($_GET['cid']) ? '/?cid=' . $_GET['cid'] : '/?f=') . '&conv=1',
'sel' => $conv_active,
'title' => L10n::t('Posts that mention or involve you'),
'id' => 'personal-tab',
@ -1001,7 +999,7 @@ function network_tabs(App $a)
if (Feature::isEnabled(local_user(), 'new_tab')) {
$tabs[] = [
'label' => L10n::t('New'),
'url' => 'network/new' . (!empty($_GET['cid']) ? '/?f=&cid=' . $_GET['cid'] : ''),
'url' => 'network/new' . (!empty($_GET['cid']) ? '/?cid=' . $_GET['cid'] : ''),
'sel' => $new_active,
'title' => L10n::t('Activity Stream - by date'),
'id' => 'activitiy-by-date-tab',
@ -1012,7 +1010,7 @@ function network_tabs(App $a)
if (Feature::isEnabled(local_user(), 'link_tab')) {
$tabs[] = [
'label' => L10n::t('Shared Links'),
'url' => str_replace('/new', '', $cmd) . (!empty($_GET['cid']) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&bmark=1',
'url' => str_replace('/new', '', $cmd) . (!empty($_GET['cid']) ? '/?cid=' . $_GET['cid'] : '/?f=') . '&bmark=1',
'sel' => $bookmarked_active,
'title' => L10n::t('Interesting Links'),
'id' => 'shared-links-tab',
@ -1022,7 +1020,7 @@ function network_tabs(App $a)
$tabs[] = [
'label' => L10n::t('Starred'),
'url' => str_replace('/new', '', $cmd) . (!empty($_GET['cid']) ? '/?f=&cid=' . $_GET['cid'] : '/?f=') . '&star=1',
'url' => str_replace('/new', '', $cmd) . (!empty($_GET['cid']) ? '/?cid=' . $_GET['cid'] : '/?f=') . '&star=1',
'sel' => $starred_active,
'title' => L10n::t('Favourite Posts'),
'id' => 'starred-posts-tab',

View File

@ -1,61 +0,0 @@
<?php
/**
* @file mod/newmember.php
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\L10n;
function newmember_content(App $a)
{
$o = '<div class="generic-page-wrapper">';
$o .= '<h1>' . L10n::t('Welcome to Friendica') . '</h1>';
$o .= '<h3>' . L10n::t('New Member Checklist') . '</h3>';
$o .= '<div style="font-size: 120%;">';
$o .= L10n::t('We would like to offer some tips and links to help make your experience enjoyable. Click any item to visit the relevant page. A link to this page will be visible from your home page for two weeks after your initial registration and then will quietly disappear.');
$o .= '<h4>' . L10n::t('Getting Started') . '</h4>';
$o .= '<ul>';
$o .= '<li> ' . '<a target="newmember" href="help/Quick-Start-guide">' . L10n::t('Friendica Walk-Through') . '</a><br />' . L10n::t('On your <em>Quick Start</em> page - find a brief introduction to your profile and network tabs, make some new connections, and find some groups to join.') . '</li>' . EOL;
$o .= '</ul>';
$o .= '<h4>' . L10n::t('Settings') . '</h4>';
$o .= '<ul>';
$o .= '<li>' . '<a target="newmember" href="settings">' . L10n::t('Go to Your Settings') . '</a><br />' . L10n::t('On your <em>Settings</em> page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web.') . '</li>' . EOL;
$o .= '<li>' . L10n::t('Review the other settings, particularly the privacy settings. An unpublished directory listing is like having an unlisted phone number. In general, you should probably publish your listing - unless all of your friends and potential friends know exactly how to find you.') . '</li>' . EOL;
$o .= '</ul>';
$o .= '<h4>' . L10n::t('Profile') . '</h4>';
$o .= '<ul>';
$o .= '<li>' . '<a target="newmember" href="profile_photo">' . L10n::t('Upload Profile Photo') . '</a><br />' . L10n::t('Upload a profile photo if you have not done so already. Studies have shown that people with real photos of themselves are ten times more likely to make friends than people who do not.') . '</li>' . EOL;
$o .= '<li>' . '<a target="newmember" href="profiles">' . L10n::t('Edit Your Profile') . '</a><br />' . L10n::t('Edit your <strong>default</strong> profile to your liking. Review the settings for hiding your list of friends and hiding the profile from unknown visitors.') . '</li>' . EOL;
$o .= '<li>' . '<a target="newmember" href="profiles">' . L10n::t('Profile Keywords') . '</a><br />' . L10n::t('Set some public keywords for your default profile which describe your interests. We may be able to find other people with similar interests and suggest friendships.') . '</li>' . EOL;
$o .= '</ul>';
$o .= '<h4>' . L10n::t('Connecting') . '</h4>';
$o .= '<ul>';
$mail_disabled = ((function_exists('imap_open') && (!Config::get('system', 'imap_disabled'))) ? 0 : 1);
if (!$mail_disabled) {
$o .= '<li>' . '<a target="newmember" href="settings/connectors">' . L10n::t('Importing Emails') . '</a><br />' . L10n::t('Enter your email access information on your Connector Settings page if you wish to import and interact with friends or mailing lists from your email INBOX') . '</li>' . EOL;
}
$o .= '<li>' . '<a target="newmember" href="contact">' . L10n::t('Go to Your Contacts Page') . '</a><br />' . L10n::t('Your Contacts page is your gateway to managing friendships and connecting with friends on other networks. Typically you enter their address or site URL in the <em>Add New Contact</em> dialog.') . '</li>' . EOL;
$o .= '<li>' . '<a target="newmember" href="directory">' . L10n::t("Go to Your Site's Directory") . '</a><br />' . L10n::t('The Directory page lets you find other people in this network or other federated sites. Look for a <em>Connect</em> or <em>Follow</em> link on their profile page. Provide your own Identity Address if requested.') . '</li>' . EOL;
$o .= '<li>' . '<a target="newmember" href="contact">' . L10n::t('Finding New People') . '</a><br />' . L10n::t("On the side panel of the Contacts page are several tools to find new friends. We can match people by interest, look up people by name or interest, and provide suggestions based on network relationships. On a brand new site, friend suggestions will usually begin to be populated within 24 hours.") . '</li>' . EOL;
$o .= '</ul>';
$o .= '<h4>' . L10n::t('Groups') . '</h4>';
$o .= '<ul>';
$o .= '<li>' . '<a target="newmember" href="contact">' . L10n::t('Group Your Contacts') . '</a><br />' . L10n::t('Once you have made some friends, organize them into private conversation groups from the sidebar of your Contacts page and then you can interact with each group privately on your Network page.') . '</li>' . EOL;
if (Config::get('system', 'newuser_private')) {
$o .= '<li>' . '<a target="newmember" href="help/Groups-and-Privacy">' . L10n::t("Why Aren't My Posts Public?") . '</a><br />' . L10n::t("Friendica respects your privacy. By default, your posts will only show up to people you've added as friends. For more information, see the help section from the link above.") . '</li>' . EOL;
}
$o .= '</ul>';
$o .= '<h4>' . L10n::t('Getting Help') . '</h4>';
$o .= '<ul>';
$o .= '<li>' . '<a target="newmember" href="help">' . L10n::t('Go to the Help Section') . '</a><br />' . L10n::t('Our <strong>help</strong> pages may be consulted for detail on other program features and resources.') . '</li>' . EOL;
$o .= '</ul>';
$o .= '</div>';
$o .= '</div>';
return $o;
}

View File

@ -1,221 +0,0 @@
<?php
/**
* @file mod/nodeinfo.php
*
* Documentation: http://nodeinfo.diaspora.software/schema.html
*/
use Friendica\App;
use Friendica\Core\Addon;
use Friendica\Core\Config;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Util\Network;
function nodeinfo_wellknown(App $a) {
if (!Config::get('system', 'nodeinfo')) {
System::httpExit(404);
}
$nodeinfo = ['links' => [['rel' => 'http://nodeinfo.diaspora.software/ns/schema/1.0',
'href' => System::baseUrl().'/nodeinfo/1.0']]];
header('Content-type: application/json; charset=utf-8');
echo json_encode($nodeinfo, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit;
}
function nodeinfo_init(App $a) {
if (!Config::get('system', 'nodeinfo')) {
System::httpExit(404);
}
if (($a->argc != 2) || ($a->argv[1] != '1.0')) {
System::httpExit(404);
}
$smtp = (function_exists('imap_open') && !Config::get('system', 'imap_disabled') && !Config::get('system', 'dfrn_only'));
$nodeinfo = [];
$nodeinfo['version'] = '1.0';
$nodeinfo['software'] = ['name' => 'friendica', 'version' => FRIENDICA_VERSION.'-'.DB_UPDATE_VERSION];
$nodeinfo['protocols'] = [];
$nodeinfo['protocols']['inbound'] = [];
$nodeinfo['protocols']['outbound'] = [];
if (Config::get('system', 'diaspora_enabled')) {
$nodeinfo['protocols']['inbound'][] = 'diaspora';
$nodeinfo['protocols']['outbound'][] = 'diaspora';
}
$nodeinfo['protocols']['inbound'][] = 'friendica';
$nodeinfo['protocols']['outbound'][] = 'friendica';
if (!Config::get('system', 'ostatus_disabled')) {
$nodeinfo['protocols']['inbound'][] = 'gnusocial';
$nodeinfo['protocols']['outbound'][] = 'gnusocial';
}
$nodeinfo['services'] = [];
$nodeinfo['services']['inbound'] = [];
$nodeinfo['services']['outbound'] = [];
$nodeinfo['usage'] = [];
$nodeinfo['openRegistrations'] = intval(Config::get('config', 'register_policy')) !== \Friendica\Module\Register::CLOSED;
$nodeinfo['metadata'] = ['nodeName' => Config::get('config', 'sitename')];
if (Config::get('system', 'nodeinfo')) {
$nodeinfo['usage']['users'] = ['total' => (int)Config::get('nodeinfo', 'total_users'),
'activeHalfyear' => (int)Config::get('nodeinfo', 'active_users_halfyear'),
'activeMonth' => (int)Config::get('nodeinfo', 'active_users_monthly')];
$nodeinfo['usage']['localPosts'] = (int)Config::get('nodeinfo', 'local_posts');
$nodeinfo['usage']['localComments'] = (int)Config::get('nodeinfo', 'local_comments');
if (Addon::isEnabled('blogger')) {
$nodeinfo['services']['outbound'][] = 'blogger';
}
if (Addon::isEnabled('dwpost')) {
$nodeinfo['services']['outbound'][] = 'dreamwidth';
}
if (Addon::isEnabled('statusnet')) {
$nodeinfo['services']['inbound'][] = 'gnusocial';
$nodeinfo['services']['outbound'][] = 'gnusocial';
}
if (Addon::isEnabled('ijpost')) {
$nodeinfo['services']['outbound'][] = 'insanejournal';
}
if (Addon::isEnabled('libertree')) {
$nodeinfo['services']['outbound'][] = 'libertree';
}
if (Addon::isEnabled('buffer')) {
$nodeinfo['services']['outbound'][] = 'linkedin';
}
if (Addon::isEnabled('ljpost')) {
$nodeinfo['services']['outbound'][] = 'livejournal';
}
if (Addon::isEnabled('buffer')) {
$nodeinfo['services']['outbound'][] = 'pinterest';
}
if (Addon::isEnabled('posterous')) {
$nodeinfo['services']['outbound'][] = 'posterous';
}
if (Addon::isEnabled('pumpio')) {
$nodeinfo['services']['inbound'][] = 'pumpio';
$nodeinfo['services']['outbound'][] = 'pumpio';
}
if ($smtp) {
$nodeinfo['services']['outbound'][] = 'smtp';
}
if (Addon::isEnabled('tumblr')) {
$nodeinfo['services']['outbound'][] = 'tumblr';
}
if (Addon::isEnabled('twitter') || Addon::isEnabled('buffer')) {
$nodeinfo['services']['outbound'][] = 'twitter';
}
if (Addon::isEnabled('wppost')) {
$nodeinfo['services']['outbound'][] = 'wordpress';
}
$nodeinfo['metadata']['protocols'] = $nodeinfo['protocols'];
$nodeinfo['metadata']['protocols']['outbound'][] = 'atom1.0';
$nodeinfo['metadata']['protocols']['inbound'][] = 'atom1.0';
$nodeinfo['metadata']['protocols']['inbound'][] = 'rss2.0';
$nodeinfo['metadata']['services'] = $nodeinfo['services'];
if (Addon::isEnabled('twitter')) {
$nodeinfo['metadata']['services']['inbound'][] = 'twitter';
}
$nodeinfo['metadata']['explicitContent'] = Config::get('system', 'explicit_content', false) == true;
}
header('Content-type: application/json; charset=utf-8');
echo json_encode($nodeinfo, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
exit;
}
function nodeinfo_cron() {
$a = \get_app();
// If the addon 'statistics_json' is enabled then disable it and activate nodeinfo.
if (Addon::isEnabled('statistics_json')) {
Config::set('system', 'nodeinfo', true);
$addon = 'statistics_json';
$addons = Config::get('system', 'addon');
if ($addons) {
$addons_arr = explode(',',str_replace(' ', '',$addons));
$idx = array_search($addon, $addons_arr);
if ($idx !== false) {
unset($addons_arr[$idx]);
Addon::uninstall($addon);
Config::set('system', 'addon', implode(', ',$addons_arr));
}
}
}
if (!Config::get('system', 'nodeinfo')) {
return;
}
Logger::log('cron_start');
$users = q("SELECT `user`.`uid`, `user`.`login_date`, `contact`.`last-item`
FROM `user`
INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid` AND `profile`.`is-default`
INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self`
WHERE (`profile`.`publish` OR `profile`.`net-publish`) AND `user`.`verified`
AND NOT `user`.`blocked` AND NOT `user`.`account_removed`
AND NOT `user`.`account_expired`");
if (is_array($users)) {
$total_users = count($users);
$active_users_halfyear = 0;
$active_users_monthly = 0;
$halfyear = time() - (180 * 24 * 60 * 60);
$month = time() - (30 * 24 * 60 * 60);
foreach ($users AS $user) {
if ((strtotime($user['login_date']) > $halfyear) ||
(strtotime($user['last-item']) > $halfyear)) {
++$active_users_halfyear;
}
if ((strtotime($user['login_date']) > $month) ||
(strtotime($user['last-item']) > $month)) {
++$active_users_monthly;
}
}
Config::set('nodeinfo', 'total_users', $total_users);
Config::set('nodeinfo', 'active_users_halfyear', $active_users_halfyear);
Config::set('nodeinfo', 'active_users_monthly', $active_users_monthly);
Logger::log('total_users: ' . $total_users . '/' . $active_users_halfyear. '/' . $active_users_monthly, Logger::DEBUG);
}
$local_posts = DBA::count('thread', ["`wall` AND NOT `deleted` AND `uid` != 0"]);
Config::set('nodeinfo', 'local_posts', $local_posts);
Logger::log('local_posts: ' . $local_posts, Logger::DEBUG);
$local_comments = DBA::count('item', ["`origin` AND `id` != `parent` AND NOT `deleted` AND `uid` != 0"]);
Config::set('nodeinfo', 'local_comments', $local_comments);
Logger::log('local_comments: ' . $local_comments, Logger::DEBUG);
// Now trying to register
$url = 'http://the-federation.info/register/'.$a->getHostName();
Logger::log('registering url: '.$url, Logger::DEBUG);
$ret = Network::fetchUrl($url);
Logger::log('registering answer: '.$ret, Logger::DEBUG);
Logger::log('cron_end');
}

View File

@ -1,23 +0,0 @@
<?php
/**
* @file mod/nogroup.php
*/
use Friendica\App;
use Friendica\Core\L10n;
function nogroup_init(App $a)
{
if (! local_user()) {
return;
}
}
function nogroup_content(App $a)
{
if (! local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return '';
}
$a->internalRedirect('group/none');
}

View File

@ -28,7 +28,7 @@ function notes_content(App $a, $update = false)
return;
}
$o = Profile::getTabs($a, true);
$o = Profile::getTabs($a, 'notes', true);
if (!$update) {
$o .= '<h3>' . L10n::t('Personal Notes') . '</h3>';

View File

@ -1,24 +0,0 @@
<?php
/**
* @file mod/notice.php
* GNU Social -> friendica items permanent-url compatibility
*/
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Database\DBA;
function notice_init(App $a)
{
$id = $a->argv[1];
$r = q("SELECT `user`.`nickname` FROM `user` LEFT JOIN `item` ON `item`.`uid` = `user`.`uid` WHERE `item`.`id` = %d", intval($id));
if (DBA::isResult($r)) {
$nick = $r[0]['nickname'];
$a->internalRedirect('display/' . $nick . '/' . $id);
} else {
$a->error = 404;
notice(L10n::t('Item not found.') . EOL);
}
return;
}

View File

@ -121,6 +121,9 @@ function notifications_content(App $a)
} elseif (($a->argc > 1) && ($a->argv[1] == 'home')) {
$notif_header = L10n::t('Home Notifications');
$notifs = $nm->homeNotifs($show, $startrec, $perpage);
// fallback - redirect to main page
} else {
$a->internalRedirect('notifications');
}
// Set the pager
@ -223,6 +226,14 @@ function notifications_content(App $a)
'$as_fan' => (($notif['network'] == Protocol::DIASPORA) ? L10n::t('Sharer') : L10n::t('Subscriber'))
]);
$contact = DBA::selectFirst('contact', ['network', 'protocol'], ['id' => $notif['contact_id']]);
if (($contact['network'] != Protocol::DFRN) || ($contact['protocol'] == Protocol::ACTIVITYPUB)) {
$action = 'follow_confirm';
} else {
$action = 'dfrn_confirm';
}
$header = $notif['name'];
if ($notif['addr'] != '') {
@ -270,6 +281,7 @@ function notifications_content(App $a)
'$note' => $notif['note'],
'$ignore' => L10n::t('Ignore'),
'$discard' => $discard,
'$action' => $action,
]);
break;
}

View File

@ -1,90 +0,0 @@
<?php
/**
* @file mod/notify.php
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\L10n;
use Friendica\Core\NotificationsManager;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model\Item;
use Friendica\Module\Login;
use Friendica\Util\Temporal;
function notify_init(App $a)
{
if (! local_user()) {
return;
}
$nm = new NotificationsManager();
if ($a->argc > 2 && $a->argv[1] === 'view' && intval($a->argv[2])) {
$note = $nm->getByID($a->argv[2]);
if ($note) {
$nm->setSeen($note);
// The friendica client has problems with the GUID. this is some workaround
if ($a->isFriendicaApp()) {
require_once("include/items.php");
$urldata = parse_url($note['link']);
$guid = basename($urldata["path"]);
$itemdata = Item::getIdAndNickByGuid($guid, local_user());
if ($itemdata["id"] != 0) {
$note['link'] = System::baseUrl().'/display/'.$itemdata["nick"].'/'.$itemdata["id"];
}
}
System::externalRedirect($note['link']);
}
$a->internalRedirect();
}
if ($a->argc > 2 && $a->argv[1] === 'mark' && $a->argv[2] === 'all') {
$r = $nm->setAllSeen();
$j = json_encode(['result' => ($r) ? 'success' : 'fail']);
echo $j;
exit();
}
}
function notify_content(App $a)
{
if (! local_user()) {
return Login::form();
}
$notif_content = '';
$nm = new NotificationsManager();
$notif_tpl = Renderer::getMarkupTemplate('notifications.tpl');
$not_tpl = Renderer::getMarkupTemplate('notify.tpl');
$r = $nm->getAll(['seen'=>0]);
if (DBA::isResult($r) > 0) {
foreach ($r as $it) {
$notif_content .= Renderer::replaceMacros($not_tpl, [
'$item_link' => System::baseUrl(true).'/notify/view/'. $it['id'],
'$item_image' => $it['photo'],
'$item_text' => strip_tags(BBCode::convert($it['msg'])),
'$item_when' => Temporal::getRelativeDate($it['date'])
]);
}
} else {
$notif_content .= L10n::t('No more system notifications.');
}
$o = Renderer::replaceMacros($notif_tpl, [
'$notif_header' => L10n::t('System Notifications'),
'$tabs' => false, // $tabs,
'$notif_content' => $notif_content,
]);
return $o;
}

View File

@ -4,10 +4,10 @@
*/
use Friendica\App;
use Friendica\Core\Authentication;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Util\Strings;
@ -52,7 +52,7 @@ function openid_content(App $a) {
unset($_SESSION['openid']);
Authentication::setAuthenticatedSessionForUser($r[0],true,true);
Session::setAuthenticatedForUser($a, $r[0],true,true);
// just in case there was no return url set
// and we fell through

View File

@ -1,21 +0,0 @@
<?php
use Friendica\App;
use Friendica\Core\Renderer;
use Friendica\Core\System;
function opensearch_content(App $a) {
$tpl = Renderer::getMarkupTemplate('opensearch.tpl');
header("Content-type: application/opensearchdescription+xml");
$o = Renderer::replaceMacros($tpl, [
'$baseurl' => System::baseUrl(),
'$nodename' => $a->getHostName(),
]);
echo $o;
exit();
}

View File

@ -9,12 +9,14 @@
*
* @see ParseUrl::getSiteinfo() for more information about scraping embeddable content
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Util\Network;
use Friendica\Util\ParseUrl;
use Friendica\Util\Strings;
function parse_url_content(App $a)
{
@ -25,10 +27,14 @@ function parse_url_content(App $a)
$br = "\n";
if (!empty($_GET['binurl'])) {
if (!empty($_GET['binurl']) && Strings::isHex($_GET['binurl'])) {
$url = trim(hex2bin($_GET['binurl']));
} else {
} elseif (!empty($_GET['url'])) {
$url = trim($_GET['url']);
// fallback in case no url is valid
} else {
Logger::info('No url given');
exit();
}
if (!empty($_GET['title'])) {
@ -64,9 +70,8 @@ function parse_url_content(App $a)
// Check if the URL is an image, video or audio file. If so format
// the URL with the corresponding BBCode media tag
$redirects = 0;
// Fetch the header of the URL
$curlResponse = Network::curl($url, false, $redirects, ['novalidate' => true, 'nobody' => true]);
$curlResponse = Network::curl($url, false, ['novalidate' => true, 'nobody' => true]);
if ($curlResponse->isSuccess()) {
// Convert the header fields into an array

View File

@ -29,8 +29,8 @@ use Friendica\Util\Crypto;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Map;
use Friendica\Util\Security;
use Friendica\Util\Temporal;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
use Friendica\Util\XML;
function photos_init(App $a) {
@ -47,23 +47,21 @@ function photos_init(App $a) {
if ($a->argc > 1) {
$nick = $a->argv[1];
$user = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `blocked` = 0 LIMIT 1",
DBA::escape($nick)
);
$user = DBA::selectFirst('user', [], ['nickname' => $nick, 'blocked' => false]);
if (!DBA::isResult($user)) {
return;
}
$a->data['user'] = $user[0];
$a->profile_uid = $user[0]['uid'];
$a->data['user'] = $user;
$a->profile_uid = $user['uid'];
$is_owner = (local_user() && (local_user() == $a->profile_uid));
$profile = Profile::getByNickname($nick, $a->profile_uid);
$account_type = Contact::getAccountType($profile);
$tpl = Renderer::getMarkupTemplate("vcard-widget.tpl");
$tpl = Renderer::getMarkupTemplate("widget/vcard.tpl");
$vcard_widget = Renderer::replaceMacros($tpl, [
'$name' => $profile['name'],
@ -115,7 +113,6 @@ function photos_init(App $a) {
'$title' => L10n::t('Photo Albums'),
'$recent' => L10n::t('Recent Photos'),
'$albums' => $ret['albums'],
'$baseurl' => System::baseUrl(),
'$upload' => [L10n::t('Upload New Photos'), 'photos/' . $a->data['user']['nickname'] . '/upload'],
'$can_post' => $can_post
]);
@ -170,12 +167,7 @@ function photos_post(App $a)
}
if ($contact_id > 0) {
$r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($page_owner_uid)
);
if (DBA::isResult($r)) {
if (DBA::exists('contact', ['id' => $contact_id, 'uid' => $page_owner_uid, 'blocked' => false, 'pending' => false])) {
$can_post = true;
$visitor = $contact_id;
}
@ -196,6 +188,9 @@ function photos_post(App $a)
}
if ($a->argc > 3 && $a->argv[2] === 'album') {
if (!Strings::isHex($a->argv[3])) {
$a->internalRedirect('photos/' . $a->data['user']['nickname'] . '/album');
}
$album = hex2bin($a->argv[3]);
if ($album === L10n::t('Profile Photos') || $album === 'Contact Photos' || $album === L10n::t('Contact Photos')) {
@ -235,36 +230,12 @@ function photos_post(App $a)
}
/*
* DELETE photo album and all its photos
* DELETE all photos filed in a given album
*/
if ($_POST['dropalbum'] == L10n::t('Delete Album')) {
// Check if we should do HTML-based delete confirmation
if (!empty($_REQUEST['confirm'])) {
$drop_url = $a->query_string;
$extra_inputs = [
['name' => 'albumname', 'value' => $_POST['albumname']],
];
$a->page['content'] = Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [
'$method' => 'post',
'$message' => L10n::t('Do you really want to delete this photo album and all its photos?'),
'$extra_inputs' => $extra_inputs,
'$confirm' => L10n::t('Delete Album'),
'$confirm_url' => $drop_url,
'$confirm_name' => 'dropalbum', // Needed so that confirmation will bring us back into this if statement
'$cancel' => L10n::t('Cancel'),
]);
$a->error = 1; // Set $a->error so the other module functions don't execute
return;
}
if (!empty($_POST['dropalbum'])) {
$res = [];
// get the list of photos we are about to delete
if ($visitor) {
$r = q("SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `album` = '%s'",
intval($visitor),
@ -282,77 +253,57 @@ function photos_post(App $a)
foreach ($r as $rr) {
$res[] = $rr['rid'];
}
// remove the associated photos
Photo::delete(['resource-id' => $res, 'uid' => $page_owner_uid]);
// find and delete the corresponding item with all the comments and likes/dislikes
Item::deleteForUser(['resource-id' => $res, 'uid' => $page_owner_uid], $page_owner_uid);
// Update the photo albums cache
Photo::clearAlbumCache($page_owner_uid);
notice(L10n::t('Album successfully deleted'));
} else {
$a->internalRedirect($_SESSION['photo_return']);
return; // NOTREACHED
notice(L10n::t('Album was empty.'));
}
}
$a->internalRedirect('photos/' . $a->argv[1]);
}
if ($a->argc > 3 && $a->argv[2] === 'image') {
// Check if the user has responded to a delete confirmation query for a single photo
if (!empty($_POST['canceled'])) {
$a->internalRedirect('photos/' . $a->argv[1] . '/image/' . $a->argv[3]);
}
if (!empty($_POST['delete'])) {
// same as above but remove single photo
if ($visitor) {
$condition = ['contact-id' => $visitor, 'uid' => $page_owner_uid, 'resource-id' => $a->argv[3]];
} else {
$condition = ['uid' => local_user(), 'resource-id' => $a->argv[3]];
}
// remove the associated photos
Photo::delete(['resource-id' => $res, 'uid' => $page_owner_uid]);
$photo = DBA::selectFirst('photo', ['resource-id'], $condition);
// find and delete the corresponding item with all the comments and likes/dislikes
Item::deleteForUser(['resource-id' => $res, 'uid' => $page_owner_uid], $page_owner_uid);
if (DBA::isResult($photo)) {
Photo::delete(['uid' => $page_owner_uid, 'resource-id' => $photo['resource-id']]);
// Update the photo albums cache
Photo::clearAlbumCache($page_owner_uid);
Item::deleteForUser(['resource-id' => $photo['resource-id'], 'uid' => $page_owner_uid], $page_owner_uid);
// Update the photo albums cache
Photo::clearAlbumCache($page_owner_uid);
notice('Successfully deleted the photo.');
} else {
notice('Failed to delete the photo.');
$a->internalRedirect('photos/' . $a->argv[1] . '/image/' . $a->argv[3]);
}
$a->internalRedirect('photos/' . $a->argv[1]);
return; // NOTREACHED
}
$a->internalRedirect('photos/' . $a->data['user']['nickname']);
return; // NOTREACHED
}
// Check if the user has responded to a delete confirmation query for a single photo
if ($a->argc > 2 && !empty($_REQUEST['canceled'])) {
$a->internalRedirect($_SESSION['photo_return']);
}
if ($a->argc > 2 && defaults($_POST, 'delete', '') === L10n::t('Delete Photo')) {
// same as above but remove single photo
// Check if we should do HTML-based delete confirmation
if (!empty($_REQUEST['confirm'])) {
$drop_url = $a->query_string;
$a->page['content'] = Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [
'$method' => 'post',
'$message' => L10n::t('Do you really want to delete this photo?'),
'$extra_inputs' => [],
'$confirm' => L10n::t('Delete Photo'),
'$confirm_url' => $drop_url,
'$confirm_name' => 'delete', // Needed so that confirmation will bring us back into this if statement
'$cancel' => L10n::t('Cancel'),
]);
$a->error = 1; // Set $a->error so the other module functions don't execute
return;
}
if ($visitor) {
$r = q("SELECT `id`, `resource-id` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `resource-id` = '%s' LIMIT 1",
intval($visitor),
intval($page_owner_uid),
DBA::escape($a->argv[2])
);
} else {
$r = q("SELECT `id`, `resource-id` FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' LIMIT 1",
intval(local_user()),
DBA::escape($a->argv[2])
);
}
if (DBA::isResult($r)) {
Photo::delete(['uid' => $page_owner_uid, 'resource-id' => $r[0]['resource-id']]);
Item::deleteForUser(['resource-id' => $r[0]['resource-id'], 'uid' => $page_owner_uid], $page_owner_uid);
// Update the photo albums cache
Photo::clearAlbumCache($page_owner_uid);
}
$a->internalRedirect('photos/' . $a->data['user']['nickname']);
return; // NOTREACHED
}
if ($a->argc > 2 && (!empty($_POST['desc']) || !empty($_POST['newtag']) || isset($_POST['albname']))) {
@ -367,7 +318,7 @@ function photos_post(App $a)
$str_group_deny = !empty($_POST['group_deny']) ? perms2str($_POST['group_deny']) : '';
$str_contact_deny = !empty($_POST['contact_deny']) ? perms2str($_POST['contact_deny']) : '';
$resource_id = $a->argv[2];
$resource_id = $a->argv[3];
if (!strlen($albname)) {
$albname = DateTimeFormat::localNow('Y');
@ -470,10 +421,11 @@ function photos_post(App $a)
if ($item_id) {
$item = Item::selectFirst(['tag', 'inform'], ['id' => $item_id, 'uid' => $page_owner_uid]);
}
if (DBA::isResult($item)) {
$old_tag = $item['tag'];
$old_inform = $item['inform'];
if (DBA::isResult($item)) {
$old_tag = $item['tag'];
$old_inform = $item['inform'];
}
}
if (strlen($rawtags)) {
@ -493,6 +445,7 @@ function photos_post(App $a)
foreach ($tags as $tag) {
if (strpos($tag, '@') === 0) {
$profile = '';
$contact = null;
$name = substr($tag,1);
if ((strpos($name, '@')) || (strpos($name, 'http://'))) {
@ -527,34 +480,26 @@ function photos_post(App $a)
}
if ($tagcid) {
$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval($tagcid),
intval($page_owner_uid)
);
$contact = DBA::selectFirst('contact', [], ['id' => $tagcid, 'uid' => $page_owner_uid]);
} else {
$newname = str_replace('_',' ',$name);
//select someone from this user's contacts by name
$r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1",
DBA::escape($newname),
intval($page_owner_uid)
);
if (!DBA::isResult($r)) {
$contact = DBA::selectFirst('contact', [], ['name' => $newname, 'uid' => $page_owner_uid]);
if (!DBA::isResult($contact)) {
//select someone by attag or nick and the name passed in
$r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1",
DBA::escape($name),
DBA::escape($name),
intval($page_owner_uid)
$contact = DBA::selectFirst('contact', [],
['(`attag` = ? OR `nick` = ?) AND `uid` = ?', $name, $name, $page_owner_uid],
['order' => ['attag' => true]]
);
}
}
if (DBA::isResult($r)) {
$newname = $r[0]['name'];
$profile = $r[0]['url'];
if (DBA::isResult($contact)) {
$newname = $contact['name'];
$profile = $contact['url'];
$notify = 'cid:' . $r[0]['id'];
$notify = 'cid:' . $contact['id'];
if (strlen($inform)) {
$inform .= ',';
}
@ -563,8 +508,8 @@ function photos_post(App $a)
}
if ($profile) {
if (substr($notify, 0, 4) === 'cid:') {
$taginfo[] = [$newname, $profile, $notify, $r[0], '@[url=' . str_replace(',','%2c',$profile) . ']' . $newname . '[/url]'];
if (!empty($contact)) {
$taginfo[] = [$newname, $profile, $notify, $contact, '@[url=' . str_replace(',', '%2c', $profile) . ']' . $newname . '[/url]'];
} else {
$taginfo[] = [$newname, $profile, $notify, null, $str_tags .= '@[url=' . $profile . ']' . $newname . '[/url]'];
}
@ -583,13 +528,13 @@ function photos_post(App $a)
}
}
$newtag = $old_tag;
$newtag = $old_tag ?? '';
if (strlen($newtag) && strlen($str_tags)) {
$newtag .= ',';
}
$newtag .= $str_tags;
$newinform = $old_inform;
$newinform = $old_inform ?? '';
if (strlen($newinform) && strlen($inform)) {
$newinform .= ',';
}
@ -794,7 +739,7 @@ function photos_post(App $a)
@unlink($src);
$foo = 0;
Hook::callAll('photo_post_end',$foo);
exit();
return;
}
$exif = $image->orient($src);
@ -820,7 +765,7 @@ function photos_post(App $a)
if (!$r) {
Logger::log('mod/photos.php: photos_post(): image store failed', Logger::DEBUG);
notice(L10n::t('Image upload failed.') . EOL);
exit();
return;
}
if ($width > 640 || $height > 640) {
@ -896,8 +841,10 @@ function photos_content(App $a)
// photos/name/upload/xxxxx (xxxxx is album name)
// photos/name/album/xxxxx
// photos/name/album/xxxxx/edit
// photos/name/album/xxxxx/drop
// photos/name/image/xxxxx
// photos/name/image/xxxxx/edit
// photos/name/image/xxxxx/drop
if (Config::get('system', 'block_public') && !local_user() && !remote_user()) {
notice(L10n::t('Public access denied.') . EOL);
@ -936,7 +883,8 @@ function photos_content(App $a)
$contact = null;
$remote_contact = false;
$contact_id = 0;
$edit = false;
$edit = '';
$drop = '';
$owner_uid = $a->data['user']['uid'];
@ -954,15 +902,12 @@ function photos_content(App $a)
}
}
}
if ($contact_id) {
$r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($owner_uid)
);
if (DBA::isResult($r)) {
if ($contact_id) {
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]);
if (DBA::isResult($contact)) {
$can_post = true;
$contact = $r[0];
$remote_contact = true;
$visitor = $contact_id;
}
@ -983,16 +928,13 @@ function photos_content(App $a)
}
}
}
if ($contact_id) {
$groups = Group::getIdsByContactId($contact_id);
$r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($owner_uid)
);
if (DBA::isResult($r)) {
$contact = $r[0];
$remote_contact = true;
}
$contact = DBA::selectFirst('contact', [], ['id' => $contact_id, 'uid' => $owner_uid, 'blocked' => false, 'pending' => false]);
$remote_contact = DBA::isResult($contact);
}
}
@ -1012,7 +954,7 @@ function photos_content(App $a)
// tabs
$is_owner = (local_user() && (local_user() == $owner_uid));
$o .= Profile::getTabs($a, $is_owner, $a->data['user']['nickname']);
$o .= Profile::getTabs($a, 'photos', $is_owner, $a->data['user']['nickname']);
// Display upload form
if ($datatype === 'upload') {
@ -1021,7 +963,7 @@ function photos_content(App $a)
return;
}
$selname = $datum ? hex2bin($datum) : '';
$selname = Strings::isHex($datum) ? hex2bin($datum) : '';
$albumselect = '';
@ -1088,6 +1030,10 @@ function photos_content(App $a)
// Display a single photo album
if ($datatype === 'album') {
// if $datum is not a valid hex, redirect to the default page
if (!Strings::isHex($datum)) {
$a->internalRedirect('photos/' . $a->data['user']['nickname']. '/album');
}
$album = hex2bin($datum);
$total = 0;
@ -1121,6 +1067,24 @@ function photos_content(App $a)
$pager->getItemsPerPage()
);
if ($cmd === 'drop') {
$drop_url = $a->query_string;
$extra_inputs = [
['name' => 'albumname', 'value' => $_POST['albumname']],
];
return Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [
'$method' => 'post',
'$message' => L10n::t('Do you really want to delete this photo album and all its photos?'),
'$extra_inputs' => $extra_inputs,
'$confirm' => L10n::t('Delete Album'),
'$confirm_url' => $drop_url,
'$confirm_name' => 'dropalbum',
'$cancel' => L10n::t('Cancel'),
]);
}
// edit album name
if ($cmd === 'edit') {
if (($album !== L10n::t('Profile Photos')) && ($album !== 'Contact Photos') && ($album !== L10n::t('Contact Photos'))) {
@ -1142,6 +1106,7 @@ function photos_content(App $a)
} else {
if (($album !== L10n::t('Profile Photos')) && ($album !== 'Contact Photos') && ($album !== L10n::t('Contact Photos')) && $can_post) {
$edit = [L10n::t('Edit Album'), 'photos/' . $a->data['user']['nickname'] . '/album/' . bin2hex($album) . '/edit'];
$drop = [L10n::t('Drop Album'), 'photos/' . $a->data['user']['nickname'] . '/album/' . bin2hex($album) . '/drop'];
}
}
@ -1187,6 +1152,7 @@ function photos_content(App $a)
'$upload' => [L10n::t('Upload New Photos'), 'photos/' . $a->data['user']['nickname'] . '/upload/' . bin2hex($album)],
'$order' => $order,
'$edit' => $edit,
'$drop' => $drop,
'$paginate' => $pager->renderFull($total),
]);
@ -1204,12 +1170,7 @@ function photos_content(App $a)
);
if (!DBA::isResult($ph)) {
$ph = q("SELECT `id` FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s'
LIMIT 1",
intval($owner_uid),
DBA::escape($datum)
);
if (DBA::isResult($ph)) {
if (DBA::exists('photo', ['resource-id' => $datum, 'uid' => $owner_uid])) {
notice(L10n::t('Permission denied. Access to this item may be restricted.'));
} else {
notice(L10n::t('Photo not available') . EOL);
@ -1217,6 +1178,20 @@ function photos_content(App $a)
return;
}
if ($cmd === 'drop') {
$drop_url = $a->query_string;
return Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [
'$method' => 'post',
'$message' => L10n::t('Do you really want to delete this photo?'),
'$extra_inputs' => [],
'$confirm' => L10n::t('Delete Photo'),
'$confirm_url' => $drop_url,
'$confirm_name' => 'delete',
'$cancel' => L10n::t('Cancel'),
]);
}
$prevlink = '';
$nextlink = '';
@ -1225,7 +1200,7 @@ function photos_content(App $a)
* The query leads to a really intense used index.
* By now we hide it if someone wants to.
*/
if (!Config::get('system', 'no_count', false)) {
if ($cmd === 'view' && !Config::get('system', 'no_count', false)) {
$order_field = defaults($_GET, 'order', '');
if ($order_field === 'posted') {
@ -1256,12 +1231,26 @@ function photos_content(App $a)
break;
}
}
$edit_suffix = ((($cmd === 'edit') && $can_post) ? '/edit' : '');
if (!is_null($prv)) {
$prevlink = 'photos/' . $a->data['user']['nickname'] . '/image/' . $prvnxt[$prv]['resource-id'] . $edit_suffix . ($order_field === 'posted' ? '?f=&order=posted' : '');
$prevlink = 'photos/' . $a->data['user']['nickname'] . '/image/' . $prvnxt[$prv]['resource-id'] . ($order_field === 'posted' ? '?f=&order=posted' : '');
}
if (!is_null($nxt)) {
$nextlink = 'photos/' . $a->data['user']['nickname'] . '/image/' . $prvnxt[$nxt]['resource-id'] . $edit_suffix . ($order_field === 'posted' ? '?f=&order=posted' : '');
$nextlink = 'photos/' . $a->data['user']['nickname'] . '/image/' . $prvnxt[$nxt]['resource-id'] . ($order_field === 'posted' ? '?f=&order=posted' : '');
}
$tpl = Renderer::getMarkupTemplate('photo_edit_head.tpl');
$a->page['htmlhead'] .= Renderer::replaceMacros($tpl,[
'$prevlink' => $prevlink,
'$nextlink' => $nextlink
]);
if ($prevlink) {
$prevlink = [$prevlink, '<div class="icon prev"></div>'];
}
if ($nextlink) {
$nextlink = [$nextlink, '<div class="icon next"></div>'];
}
}
}
@ -1283,33 +1272,23 @@ function photos_content(App $a)
$album_link = 'photos/' . $a->data['user']['nickname'] . '/album/' . bin2hex($ph[0]['album']);
$tools = null;
$lock = null;
if ($can_post && ($ph[0]['uid'] == $owner_uid)) {
$tools = [
'edit' => ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum . (($cmd === 'edit') ? '' : '/edit'), (($cmd === 'edit') ? L10n::t('View photo') : L10n::t('Edit photo'))],
'profile'=>['profile_photo/use/'.$ph[0]['resource-id'], L10n::t('Use as profile photo')],
];
$tools = [];
if ($cmd === 'edit') {
$tools['view'] = ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum, L10n::t('View photo')];
} else {
$tools['edit'] = ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum . '/edit', L10n::t('Edit photo')];
$tools['delete'] = ['photos/' . $a->data['user']['nickname'] . '/image/' . $datum . '/drop', L10n::t('Delete photo')];
$tools['profile'] = ['profile_photo/use/'.$ph[0]['resource-id'], L10n::t('Use as profile photo')];
}
// lock
$lock = ((($ph[0]['uid'] == local_user()) && (strlen($ph[0]['allow_cid']) || strlen($ph[0]['allow_gid'])
|| strlen($ph[0]['deny_cid']) || strlen($ph[0]['deny_gid'])))
? L10n::t('Private Message')
: Null);
}
if ($cmd === 'edit') {
$tpl = Renderer::getMarkupTemplate('photo_edit_head.tpl');
$a->page['htmlhead'] .= Renderer::replaceMacros($tpl,[
'$prevlink' => $prevlink,
'$nextlink' => $nextlink
]);
}
if ($prevlink) {
$prevlink = [$prevlink, '<div class="icon prev"></div>'];
if (
$ph[0]['uid'] == local_user()
&& (strlen($ph[0]['allow_cid']) || strlen($ph[0]['allow_gid']) || strlen($ph[0]['deny_cid']) || strlen($ph[0]['deny_gid']))
) {
$tools['lock'] = L10n::t('Private Photo');
}
}
$photo = [
@ -1322,11 +1301,6 @@ function photos_content(App $a)
'filename' => $hires['filename'],
];
if ($nextlink) {
$nextlink = [$nextlink, '<div class="icon next"></div>'];
}
// Do we have an item for this photo?
// FIXME! - replace following code to display the conversation with our normal
@ -1431,7 +1405,7 @@ function photos_content(App $a)
$tpl = Renderer::getMarkupTemplate('photo_item.tpl');
$return_path = $a->cmd;
if ($can_post || Security::canWriteToUserWall($owner_uid)) {
if ($cmd === 'view' && ($can_post || Security::canWriteToUserWall($owner_uid))) {
$like_tpl = Renderer::getMarkupTemplate('like_noshare.tpl');
$likebuttons = Renderer::replaceMacros($like_tpl, [
'$id' => $link_item['id'],
@ -1510,7 +1484,7 @@ function photos_content(App $a)
continue;
}
$profile_url = Contact::MagicLinkById($item['author-id']);
$profile_url = Contact::magicLinkbyId($item['author-id']);
if (strpos($profile_url, 'redir/') === 0) {
$sparkle = ' sparkle';
} else {
@ -1537,7 +1511,7 @@ function photos_content(App $a)
'$title' => $title_e,
'$body' => $body_e,
'$ago' => Temporal::getRelativeDate($item['created']),
'$indent' => (($item['parent'] != $item['item_id']) ? ' comment' : ''),
'$indent' => (($item['parent'] != $item['id']) ? ' comment' : ''),
'$drop' => $drop,
'$comment' => $comment
]);
@ -1546,7 +1520,7 @@ function photos_content(App $a)
$comments .= Renderer::replaceMacros($cmnt_tpl, [
'$return_path' => '',
'$jsreload' => $return_path,
'$id' => $item['item_id'],
'$id' => $item['id'],
'$parent' => $item['parent'],
'$profile_uid' => $owner_uid,
'$mylink' => $contact['url'],
@ -1574,7 +1548,6 @@ function photos_content(App $a)
'$id' => $ph[0]['id'],
'$album' => [$album_link, $ph[0]['album']],
'$tools' => $tools,
'$lock' => $lock,
'$photo' => $photo,
'$prevlink' => $prevlink,
'$nextlink' => $nextlink,

View File

@ -1,14 +0,0 @@
<?php
/**
* @file mod/phpinfo.php
*/
function phpinfo_content()
{
if (!is_site_admin()) {
return false;
}
phpinfo();
exit();
}

View File

@ -313,14 +313,7 @@ function ping_init(App $a)
usort($notifs, $sort_function);
if (DBA::isResult($notifs)) {
// Are the nofications called from the regular process or via the friendica app?
$regularnotifications = (!empty($_GET['uid']) && !empty($_GET['_']));
foreach ($notifs as $notif) {
if ($a->isFriendicaApp() || !$regularnotifications) {
$notif['message'] = str_replace("{0}", $notif['name'], $notif['message']);
}
$contact = Contact::getDetailsByURL($notif['url']);
if (isset($contact['micro'])) {
$notif['photo'] = ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO);

View File

@ -22,7 +22,7 @@ function poco_init(App $a) {
$system_mode = false;
if (intval(Config::get('system', 'block_public')) || (Config::get('system', 'block_local_dir'))) {
System::httpExit(401);
throw new \Friendica\Network\HTTPException\ForbiddenException();
}
if ($a->argc > 1) {
@ -31,7 +31,7 @@ function poco_init(App $a) {
if (empty($nickname)) {
$c = q("SELECT * FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1");
if (!DBA::isResult($c)) {
System::httpExit(401);
throw new \Friendica\Network\HTTPException\ForbiddenException();
}
$system_mode = true;
}
@ -73,7 +73,7 @@ function poco_init(App $a) {
DBA::escape($nickname)
);
if (! DBA::isResult($users) || $users[0]['hidewall'] || $users[0]['hide-friends']) {
System::httpExit(404);
throw new \Friendica\Network\HTTPException\NotFoundException();
}
$user = $users[0];
@ -371,8 +371,9 @@ function poco_init(App $a) {
$ret['entry'][] = [];
}
} else {
System::httpExit(500);
throw new \Friendica\Network\HTTPException\InternalServerErrorException();
}
Logger::log("End of poco", Logger::DEBUG);
if ($format === 'xml') {
@ -385,6 +386,6 @@ function poco_init(App $a) {
echo json_encode($ret);
exit();
} else {
System::httpExit(500);
throw new \Friendica\Network\HTTPException\InternalServerErrorException();
}
}

View File

@ -154,15 +154,11 @@ function poke_content(App $a)
$name = $contact['name'];
$id = $contact['id'];
$base = System::baseUrl();
$head_tpl = Renderer::getMarkupTemplate('poke_head.tpl');
$a->page['htmlhead'] .= Renderer::replaceMacros($head_tpl,[
'$baseurl' => System::baseUrl(true),
'$base' => $base
]);
$parent = (!empty($_GET['parent']) ? intval($_GET['parent']) : '0');

View File

@ -1,25 +0,0 @@
<?php
use Friendica\App;
use Friendica\Core\Theme;
function pretheme_init(App $a) {
if ($_REQUEST['theme']) {
$theme = $_REQUEST['theme'];
$info = Theme::getInfo($theme);
if ($info) {
// unfortunately there will be no translation for this string
$desc = $info['description'];
$version = $info['version'];
$credits = $info['credits'];
} else {
$desc = '';
$version = '';
$credits = '';
}
echo json_encode(['img' => Theme::getScreenshot($theme), 'desc' => $desc, 'version' => $version, 'credits' => $credits]);
}
exit();
}

View File

@ -1,37 +0,0 @@
<?php
/**
* @file mod/probe.php
*/
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Network\Probe;
function probe_content(App $a)
{
if (!local_user()) {
System::httpExit(403, ["title" => L10n::t("Public access denied."),
"description" => L10n::t("Only logged in users are permitted to perform a probing.")]);
exit();
}
$o = '<div class="generic-page-wrapper">';
$o .= '<h3>Probe Diagnostic</h3>';
$o .= '<form action="probe" method="get">';
$o .= 'Lookup address: <input type="text" style="width: 250px;" name="addr" value="' . defaults($_GET, 'addr', '') . '" />';
$o .= '<input type="submit" name="submit" value="Submit" /></form>';
$o .= '<br /><br />';
if (!empty($_GET['addr'])) {
$addr = trim($_GET['addr']);
$res = Probe::uri($addr, "", 0, false);
$o .= '<pre>';
$o .= str_replace("\n", '<br />', print_r($res, true));
$o .= '</pre>';
}
$o .= '</div>';
return $o;
}

View File

@ -12,10 +12,9 @@ use Friendica\Core\System;
function hub_return($valid, $body)
{
if ($valid) {
header($_SERVER["SERVER_PROTOCOL"] . ' 200 OK');
echo $body;
} else {
System::httpExit(404);
throw new \Friendica\Network\HTTPException\NotFoundException();
}
exit();
}
@ -24,7 +23,7 @@ function hub_return($valid, $body)
function hub_post_return()
{
System::httpExit(200);
throw new \Friendica\Network\HTTPException\OKException();
}
function pubsub_init(App $a)

Some files were not shown because too many files have changed in this diff Show More