Merge remote-tracking branch 'upstream/develop' into sanitize-gcontact

This commit is contained in:
Michael 2019-10-15 10:10:12 +00:00
commit f1e7d97b8c
1219 changed files with 241816 additions and 178090 deletions

View file

@ -1,36 +1,14 @@
codecov:
branch: develop
comment: off
ci:
- drone.friendi.ca
coverage:
precision: 2
round: down
range: "70...100"
status:
patch:
default: off
source:
target: 80%
flags: source
backend:
target: 80%
flags: backend
project:
default: off
source:
flags: source
backend:
flags: backend
project: off
patch: off
flags:
source:
paths:
- src/
backend:
paths:
- mod/
- include/
binary:
paths:
- bin/
tests:
paths:
- tests/
comment: off

439
.drone.yml Normal file
View file

@ -0,0 +1,439 @@
kind: pipeline
name: mysql8.0-php7.1
steps:
- name: mysql8.0-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mysql8.0-php7.2
steps:
- name: mysql8.0-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mysql8.0-php7.3
steps:
- name: mysql8.0-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true ./autotest.sh mysql
environment:
MYSQL_USERNAME: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mysql
services:
- name: mysql
image: mysql:8.0
command: [ "--default-authentication-plugin=mysql_native_password" ]
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.1
steps:
- name: mariadb10.1-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- ./autotest.sh mariadb
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.2
steps:
- name: mariadb10.1-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true ./autotest.sh mariadb
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: mariadb10.1-php7.3
steps:
- name: mariadb10.1-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true ./autotest.sh mariadb
environment:
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
MYSQL_HOST: mariadb
services:
- name: mariadb
image: mariadb:10.1
environment:
MYSQL_ROOT_PASSWORD: friendica
MYSQL_USER: friendica
MYSQL_PASSWORD: friendica
MYSQL_DATABASE: friendica
volumes:
- name: cache
path: /var/lib/mysql
volumes:
- name: cache
temp: {}
---
kind: pipeline
name: redis-php7.1
steps:
- name: redis-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: redis-php7.2
steps:
- name: redis-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: redis-php7.3
steps:
- name: redis-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=REDIS ./autotest.sh mysql
environment:
REDIS_HOST: redis
services:
- name: redis
image: redis
---
kind: pipeline
name: memcache-php7.1
steps:
- name: memcache-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcache-php7.2
steps:
- name: memcache-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcache-php7.3
steps:
- name: memcache-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHE ./autotest.sh mysql
environment:
MEMCACHE_HOST: memcached
services:
- name: memcached
image: memcached
---
kind: pipeline
name: memcached-php7.1
steps:
- name: memcached-php7.1
image: friendicaci/php7.1:php7.1.32
commands:
- phpenmod xdebug
- sleep 20
- NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
- wget https://codecov.io/bash -O codecov.sh
- sh -c "if [ '$DRONE_BUILD_EVENT' = 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -P $DRONE_PULL_REQUEST -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
- sh -c "if [ '$DRONE_BUILD_EVENT' != 'pull_request' ]; then bash codecov.sh -B $DRONE_BRANCH -C $DRONE_COMMIT -t 5ce7d64e-07b4-4adf-8700-e2eae27e14ec -f tests/autotest-clover.xml; fi"
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcached-php7.2
steps:
- name: memcached-php7.2
image: friendicaci/php7.2:php7.2.22
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached
trigger:
branch:
- master
- develop
- "*-rc"
event:
- pull_request
- push
---
kind: pipeline
name: memcached-php7.3
steps:
- name: memcached-php7.3
image: friendicaci/php7.3:php7.3.9
commands:
- NOCOVERAGE=true NOINSTALL=true TEST_SELECTION=MEMCACHED ./autotest.sh mysql
environment:
MEMCACHED_HOST: memcached
services:
- name: memcached
image: memcached

13
.gitignore vendored
View file

@ -1,16 +1,17 @@
favicon.*
.htconfig.php
.htpreconfig.php
/.htconfig.php
/.htpreconfig.php
\#*
*.log
*.out
*.version*
home.html
*~
robots.txt
#ignore local config
/config/local.config.php
/config/addon.config.php
/config/local.ini.php
/config/addon.ini.php
@ -69,3 +70,9 @@ venv/
#ignore .htaccess
.htaccess
#ignore filesystem storage default path
/storage
#Ignore log folder
/log

View file

@ -1,11 +1,10 @@
---
language: php
## Friendica supports PHP version >= 5.6.1
## Friendica officially supports PHP version >= 7.1
php:
- 5.6
- 7.0
- 7.1
- 7.2
- 7.3
services:
- mysql
@ -17,9 +16,14 @@ env:
install:
- composer install
before_script:
- cp config/local-sample.ini.php config/local.ini.php
- 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
after_success: bash <(curl -s https://codecov.io/bash)
- 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
script: vendor/bin/phpunit --configuration tests/phpunit.xml

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

@ -3,7 +3,7 @@ host = https://www.transifex.com
[friendica.messagespo]
file_filter = view/lang/<lang>/messages.po
source_file = util/messages.po
source_file = view/lang/C/messages.po
source_lang = en
type = PO

349
CHANGELOG
View file

@ -1,3 +1,352 @@
Version 2019.12-dev (unreleased)
Friendica Core:
Enhanced the manage functionality [annando]
Fixed some problems with the remote auth functionality [annando]
Added router configuration file [nupplaphil]
Added drone.io as CI service [nupplaphil]
Friendica Addons:
mailstream:
Support for new img format was added [mexon]
BB Code is now included as plaintext [mexon]
Logging format is enhanced [mexon]
ActivityPub "announce" notifications are not included [mexon]
Closed Issues:
1071, 7548, 7657, 7681
Version 2019.09 (2019-09-29)
Friendica Core:
Update to the translations (CS, DE, EN GB, EN US, FR, JA, NL, PL) [translation teams]
Update to the themes (frio, vier) [JeroenED, MrPetovan, tobiasd, vinzv]
Update to the documentation [annando, tobiasd, guzzisti, vinzv]
Enhanced the log output of the background process [annando]
Enhanced the vcard translation in the profile [JeroenED]
Enhanced the delivery count [annando]
Enhanced ActivityPub envelopes [MrPetovan]
Enhanced communication about deleted accounts via AP [annando]
Enhanced the following process [annando]
Enhanced the tests [nupplaphil]
Enhanced the front-end worker [annando]
Enhanced the img format to allow alternative texts [annando]
Enhanced the detection of supported protocols for contacts [annando]
Enhanced the re-share of items [annando]
Enhanced 2FA process [MrPetovan]
Enhanced server wide theme settings [MrPetovan]
Enhanced config loading process [MrPetovan, nupplaphil]
Enhanced handling of emoticons [MrPetovan]
Enhanced performance [annando]
Fixed a bug in the admin panel leading to orphaned options [tobiasd]
Fixed a problem that could lead to duplicated Pleroma contacts [annando]
Fixed a problem with the hide profile setting [annando]
Fixed the problem sending out the post when hitting the enter key in the ACL dialog [MrPetovan]
Fixed a bug in HTML special character escaping of event titles [MrPetovan]
Fixed a bug in HTML special character conversion in item titles [MrPetovan]
Fixed a bug in the auto linker for URLs [MrPetovan]
Fixed a bug that prevented the display of images in some postings from diaspora* [MrPetovan]
Fixed a bug in setting the permissions on uploaded images [annando]
Fixed a bug that lead to potentially unwanted importing threads started by contacts of contacts [annando]
Fixed implicit self mentions [MrPetovan]
Fixed display of register links on closed nodes landing pages [MrPetovan]
Fixed the display of [spoiler] tags [MrPetovan]
Fixed an issue with photo permissions in private mails [annando]
Fixed a bug in the process of following Pleroma accounts [annando]
Fixed a bug that caused notifications about locally deleted items [annando]
Fixed the link to the source of an event [MrPetovan]
Fixed a problem that caused authors from twitter postings having no profile pic [annando]
Fixed a bug in BBCode -> Markdown conversation for font size [annando]
Fixed a BBCode parser problem with the audio tag [MrPetovan]
Fixed a session problem [annando]
Fixed a problem with the auto-installer [nupplaphil]
Fixed a bug with magic links redirection for non profiles [annando]
General code cleaning [annando, MrPetovan, nupplaphil]
Removed contacts auto completion (in /contacts [MrPetovan]
Replaced FontAwesome by ForkAwesome in frio theme [vinzv]
Added new compose page for the frio theme [MrPetovan]
Added new console command: lock [nupplaphil]
Added new additional feature to show trending tags on community page [MrPetovan]
Added support of image descriptions [annando]
Added support of wildcards to server block lists [MrPetovan]
Added app specific passwords when using 2FA [MrPetovan]
Added fetching of postings via URL to interact with public postings [annando]
Added opt-out flag for federated search engines and associated header information for profiles [annando]
Friendica Addons:
Update to the translation (CS, DE, EN GB, EN US, ES, FR, JA, NL SV) [translation teams]
General code cleanup [nupplaphil, Quix0r]
blockbot:
Added translations
Added more bots [annando]
Added admin panel settings [annando]
tumblr:
Changed used URLs to https adopting tumblrs change [annando]
twitter:
Enhanced handling of multi image postings [annando]
Enhanced display of quoted tweets [MrPetovan]
Added alternative text support for images [annando]
Closed Issues:
870, 1605, 2199, 3239, 3816, 4117, 4815, 5721, 6384, 6521, 6553,
6675, 7212, 7235, 7285, 7293, 7314, 7317, 7337, 7338, 7346, 7350,
7367, 7383, 7396, 7397, 7401, 7406, 7408, 7426, 7428, 7456, 7442,
7457, 7468, 7471, 7473, 7488, 7497, 7498, 7501, 7507, 7521, 7526,
7527, 7536, 7542, 7545, 7576, 7586, 7594, 7597, 7603, 7610, 7618,
7629, 7635, 7638, 7663, 7665, 7672
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]
Added native reshares and reshare count [annando]
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:
838, 1012, 2209, 2528, 3309, 3717, 3816, 3869, 4453, 4999, 5011,
5047, 5276, 5850, 5983, 6245, 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, 7012, 7020, 7023, 7031, 7036, 7047, 7106, 7110, 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]
Update to the documentation [Aditoo17, JeroenED, m4sk1n, softmetz, tobiasd]
Update to the themes (duepuntozero, frio, smoothy, quattro, vier) [lxiter, MrPetovan, nupplaphil, rabuzarus, tobiasd]
Enhancements to the API [jasonscheng]
Enhancements to the Vagrant development VM [JeroenED]
Enhancements to the storage of gender, sexual preferences and maritial status [JeroenED]
Enhancements to the wording of notifications [MrPetovan]
Enhancements to the display of contacts in the profile [MrPetovan]
Enhancements to the handling of local links [lxiter]
Enhancements to the explicit and implicit mentioning in conversations [annando, MrPetovan]
Enhancements to the warnings in the admin panel [tobiasd]
Enhancements to the AP implementation [annando]
Enhancements to the worker process [annando]
Enhancements to the testing process [MrPetovan, nupplaphil]
Enhancements to the LibreJS compatibility [tobiasd]
Enhancements to the federated display of postings [MrPetovan]
Enhancements to the photo menu [annando]
Enhancements to the probing of contacts [annando]
Fixed several bugs with weird tagging in code blocks [lxiter]
Fixed a bug during contact entries update [rabuzarus]
Fixed several PHP warnings and errors [annando, MrPetovan, tobiasd]
Fixed an issue when Friendica is installed in a subdirectory [rabuzarus]
Fixed several issues in the handling of the Markdown parsing from and to d* [lxiter, MrPetovan]
Fixed a bug that prevented blocked contacts from being removed from groups [MrPetovan]
Fixed a bug in the ACL with preselected items [lxiter]
Fixed an issue with polling Events via AP [annando]
Fixed a memory issue with the JSON-LD parser [annando]
Fixed an issue with the forced DB structure update [nupplaphil]
Fixed an issue with wrongly encoded HTML entities in URLs [annando]
Fixed an issue with the rotation of images in the gallery [nupplaphil]
Fixed issues with redirs in the photo menu of Friendica contacts [tobiasd]
Fixed an issue with sending out notification mails to the admin [nupplaphil]
Fixed an the issue, that the API was ignoring the globalsilence setting [nupplaphil]
Fixed issues with the autolinker of URLs in postings [MrPetovan]
Fixed an issue resulting in multible emails after successful updates of the database [nupplaphil]
Fixed a timeout issue during detection process of the remote profile [annando]
Fixed an issue with postings from blocked servers [annando, MrPetovan]
Fixed an issue with the paging of stored folders [MrPetovan]
Fixed an issue with notifications about interactions with Friendica contacts [annando]
Fixed an issue that caused double postings of images uploaded to the gallery [annando]
Fixed an issue handling legacy config files [nupplaphil]
Fixed an issue that caused notifications about interaction with a locally deleted posting [annando]
If the node does not want to publish information, nodeinfo now returns 404 instead of non-existing entries [nupplaphil]
General Code cleaning and restructuring [annando, JeroenED, MrPetovan, nupplaphil]
Switched logging engine to monolog [nupplaphil]
Added plugable storage backend [fabrixxm, nupplaphil]
Added item delivery indicator to posting header [MrPetovan]
Added URL parameter to force a specific language [JeroenED]
Added live preview of attachments to frio [rabuzarus]
Added a "friendica_author" field to the API results which holds the real author [annando]
Added support for AP with forum postings [annando]
Added a summary of articles send over AP [annando]
Friendica Addons:
Updates to the translations (CS, DE, EN-GB, ES, FR, NL, PL, SV) [translation teams]
Updated documentation [softmetz, tobiasd]
blackout:
Fix applying the translations [JeroenED, tobiasd]
Fixed some templating of the settings [tobiasd]
blogger:
The addon was marked as unsupported as it does currently not work (needs OAuth support) [annando]
cookienotice:
Added new addon to display a cookie usage notice in the browser [lxiter]
forumdirectory:
Fixed a theming issue with frio [rabuzarus]
js_upload:
Fixed a missing extionsion index [nupplaphil]
mailstream:
Fixed a curl issue [MrPetovan]
piwik:
Make it clear that Piwik is now Matomo but the addon supports both [tobiasd]
securemail:
updated the addon dependencies [MrPetovan]
twitter:
@ mentions are now stripped from the posts send to Twitter [MrPetovan]
Closed Issues:
1777, 2487, 3218, 3506, 3837, 4496, 5884, 6087, 6161, 6167, 6205,
6232, 6263, 6274, 6292, 6337, 6338, 6375, 6378, 6382, 6384, 6386,
6403, 6405, 6449, 6468, 6472, 6489, 6491, 6492, 6495, 6498, 6501,
6503, 6505, 6511, 6514, 6521, 6522, 6529, 6532, 6533, 6544, 6545,
6551, 6553, 6537, 6558, 6552, 6561, 6570, 6575, 6585, 6603, 6610,
6629, 6630, 6633, 6635, 6652, 6656, 6658, 6667, 6668, 6669, 6672,
6674, 6676, 6677, 6679, 6691, 6710, 6711, 6714, 6716, 6733, 6758,
6772, 6778, 6785, 6788, 6800, 6805, 6812, 6819, 6822, 6823, 6840,
6855, 6866, 6874, 6891, 6901, 6913
Version 2019.01 (2019-01-21)
Friendica Core:
Update to the translation (CS, DE, EN-UK, EN-US, FR, NB-NO, NL, PL) [translation teams]
Update to the documentation [AndyHee, FiXato, hoergen, JeroenED, MrPetovan, rebeka-catalina, tobiasd, wouter705]
Enhancements to the themes (frio, vier) [annando, JonnyTischbein, MrPetovan, rabuzarus]
Enhancements to the usage of MagicLinks [annando, rabuzarus]
Enhancements to the escaping of user submitted content [annando, MrPetovan, tobiasd]
Enhancements to the installation wizard [annando, JonnyTischbein, vinzv]
Enhancements to the OWA compatibility with Hubzilla [annando]
Enhancements to Friendica on the iOS Home Screen [MrPetovan]
Enhancements to the Welcome email after registration [MrPetovan]
Enhancements to the API [annando]
Enhancements to the methods to find potentially interesting contacts [MrPetovan]
Enhancements to the remote detection of already existing relationships [MrPetovan]
Enhancements to the handling of large posts [annando]
Enhancements to the user removal process [annando, MrPetovan]
Enhancements to the generation of HTTP error messages [annando]
Enhancements to the admin panel [AndyHee, annando]
Enhancements to the display of birthday reminders [MrPetovan]
Enhancements to the display of the group filter [annando]
Enhancements to the Worker [annando]
Enhancements to the exported Atom feeds [Alkarex]
Enhancements to the Vagrant VM [fabrixxm, tobiasd]
Enhancements to the tests [nupplaphil]
Enhancements to the node info [annando]
Enhancements to the DBclean process [annando]
Enhancements to the PasswordExposedChecker [MrPetovan]
Enhancements to the BBCode handling [MrPetovan]
Enhancements to the diaspora* protocol implementation [annando]
Enhancements to the automatic installation [nupplaphil]
Fixed various PHP notice occurrences [annando, MrPetovan]
Fixed the display of private postings in contact overview [annando]
Fixed a problem with the display of forums in the widget [annando]
Fixed a bug in the email support [MrPetovan]
Fixed a bug in the endless scroll of the network stream [MrPetovan]
Fixed a style problem with iOS mobile browser [MrPetovan]
Fixed a bug handling links to Hubzilla forums [MrPetovan]
Fixed a bug in the character set detection [MrPetovan]
Fixed a bug with the display of private notes [annando]
Fixed a bug in setting the photo permissions [JonnyTischbein]
Fixed a bug that caused some photo albums having no permissions [JonnyTischbein]
Fixed a problem adding multiple hashtags [JonnyTischbein]
Fixed a bug when subscribing to OStatus accounts [MrPetovan]
Fixed a bug in SQL grammar [Alkarex]
Fixed a bug with WebSub [Alkarex]
Fixed a bug in the generated node info JSON [fabrixxm]
Fixed a bug displaying videos when using the frio theme [JeroenED]
Moved config format to PHP arrays [MrPetovan]
Moved several additional features back to the default features [annando]
Started to deprecate the Google+ support [annando]
Added support of ActivityPub (tested with Hubzilla, Mastodon, Nextcloud Social, Osada, PeerTube, Pixelfed, Pleroma) [annando]
Added support for custom emojis [annando, MrPetovan]
The util folder was removed and the content restructured elsewhere [MrPetovan]
Removed the old /p endpoint from diaspora* compatibility [annando]
Friendica Addons:
Updating the translations (DE, FR) [translation teams]
twitter:
use original URL for link display [MrPetovan]
enhancements to shares [MrPetovan]
leistungsschutzrecht:
show preview pictures of videos [annando]
optionally suppress pictures [annando]
wordpress:
posting should work again [annando]
forumdirectory:
paging enhancements [MrPetovan]
mathjax:
addon rewritten [MrPetovan]
highlightjs:
added addon to highlight source code [MrPetovan]
Closed Issues:
1430, 1495, 1572, 1575, 1580, 1581, 2123, 2893, 3016, 3466, 3777,
3870, 3897, 4242, 4584, 4592, 4609, 4688, 4708, 4715, 4738, 4804,
5264, 5368, 5547, 5596, 5627, 5716, 5723, 5737, 5757, 5771, 5779,
5797, 5798, 5811, 5809, 5814, 5820, 5834, 5847, 5801, 5805, 5857,
5858, 5859, 5863, 5875, 5879, 5886, 5890, 5893, 5896, 5908, 5911,
5915, 5913, 5924, 5932, 5934, 5943, 5955, 5956, 5960, 5966, 5968,
5971, 5975, 5992, 5994, 5996, 6006, 6010, 6015, 6027, 6032, 6036,
6038, 6047, 6081, 6100, 6109, 6119, 6124, 6125, 6128, 6140, 6149,
6157, 6173, 6202, 6211, 6212, 6213, 6236, 6243, 6255, 6257, 6259,
6268, 6282, 6283, 6208, 6289, 6294, 6308, 6309, 6313, 6316, 6323,
6329, 6334, 6344, 6347, 6343, 6349, 6350, 6355, 6358, 6360, 6361,
6363, 6368, 6370, 6391, 6394, 6424, 6425, 6439, 6459
Version 2018.09 (2018-09-23)
Friendica Core:
Update to the translation (CS, DE, EN-US, FI, IT, NL, PL, ZH-CN) [translation teams]

View file

@ -1,11 +1,13 @@
23n
Abinoam P. Marques Jr.
Abraham Pérez Hernández
Abrax
Adam Clark
Adam Jurkiewicz
Adam Magness
Aditoo
Aditoo17
AgnesElisa
Albert
Alberto Díaz Tormo
@ -21,12 +23,13 @@ Andreas Neustifter
Andrej Stieben
André Alves
André Lohan
Andy H3
Andy
Andy Hee
AndyHee
Angristan
Anthronaut
Antron Samurai
Arian - Cazare Muncitori
Asher Pen
Athalbert
aweiher
axelt
@ -38,6 +41,8 @@ Beluga
Ben
Ben Roberts
ben-utzer
BinkaDroid
Bjoessi
bufalo1973
Calango Jr
Carlos Solís
@ -49,6 +54,7 @@ Christian M. Grube
Christian Vogeley
Cohan Robinson
Copiis Praeesse
CrystalStiletto
Cyboulette
Cyryl Sochacki
czarnystokrotek
@ -78,6 +84,7 @@ Fabian Dost
Fabio Comuni
felixgilles
Filip Bugaj
Filip H.F. "FiXato" Slagter
FlxAlbroscheit
foss
Francesco Apruzzese
@ -89,13 +96,13 @@ Gert Cauwenberg
GLComo
greeneyedred
Gregory Smith
guzzisti
Haakon Meland Eriksen
Hans Meine
hauke
Hauke
Hauke Altmann
Hauke Zühl
Herbert Thielen
hlad
hoergen
Hubert Kościański
Hypolite Petovan
@ -108,9 +115,11 @@ Jens Tautenhahn
jensp
Jeroen De Meerleer
jeroenpraat
JOduMonT
Johannes Schwab
John Brazil
Jonatan Nyberg
Jonny Tischbein
Josef Moravek
juanman
julia.domagalska
@ -131,7 +140,9 @@ Magdalena Gazda
Mai Anh Nguyen
Manuel Pérez Monís
Marcin Klessa
Marcin Mikołajczak
Marcus Müller
Marie Olive
Mariusz Pisz
marmor
Marquis_de_Carabas
@ -157,12 +168,15 @@ Oliver
Olivier
Olivier Mehani
Olivier Migeot
Ozero Dien
Paolo Wave
Pascal
Pascal Deklerck
Pavel Morozov
PerigGouanvic
Peter Liebetrau
peturisfeld
Phigger Phigger
Philipp
Philipp Holzer
Pierre Rudloff
@ -172,16 +186,20 @@ R C
Rabuzarus
Radek
Rafael Garau
Rain Hawk
Rainulf Pineda
Ralf Thees
Ralph
Ratten
rcmaniac
rebeka-catalina
repat
Ricardo Pereira
Rik 4
RJ Madsen
Roland Häder
Rui Andrada
rwa
RyDroid
S.Krumbholz
Sakałoŭ Alaksiej
@ -195,6 +213,7 @@ Seth
Silke Meyer
Simon L'nu
Simó Albert i Beltran
softmetz
soko1
St John Karp
Stanislav N.
@ -202,6 +221,7 @@ Steffen K9
StefOfficiel
Sveinn í Felli
Sven Anders
Sylke Vicious
Sylvain Lagacé
szymon.filip
Sérgio Lima
@ -212,6 +232,8 @@ Thecross
Thomas
Thomas Willingham
thorsten23
Tim Stahel
TiMESPLiNTER
Tino
Tobias Diekershoff
Tobias Hößl
@ -219,6 +241,7 @@ tomacat
tomamplius
tomtom84
Tony Baldwin
Torbjörn Andersson
TORminator
trebor
tschlotfeldt
@ -226,13 +249,20 @@ Tubuntu
Tupambae.org
U-SOUND\mike
ufic
Ulf Rompe
Unknown
Valvin
Valvin A
Vasudev Kamath
Vasya Novikov
Vinzenz Vietzke
vislav
vladimir N
Vladimir Núñez
VVelox
Vít Šesták 'v6ak'
Waldemar Stoczkowski
Wouter Broers
Yasen Pramatarov
ylms
Zach Prezkuta
@ -243,4 +273,4 @@ zottel
Zvi ben Yaakov (a.k.a rdc)
Михаил
Олексій Замковий
朱陈锬
朱陈锬

View file

@ -1,9 +1,9 @@
INPUT = README.md index.php boot.php testargs.php update.php mod/ object/ include/ js/ util/ view/ src/ version.inc
INPUT = README.md index.php boot.php update.php bin/ mod/ include/ view/ src/ VERSION
RECURSIVE = YES
PROJECT_NAME = "Friendica"
PROJECT_LOGO = images/friendica-64.jpg
EXCLUDE = .htconfig.php config/ library/ doc/ .git/ log/ util/zotsh/easywebdav/ addon/ report/ privacy_image_cache/ photo/ proxy/ local/
EXCLUDE_PATTERNS = *smarty3* *strings.php*.log *.out *test*
EXCLUDE = .htconfig.php config/ library/ doc/ .git/ log/ addon/ report/ privacy_image_cache/ photo/ proxy/ local/
EXCLUDE_PATTERNS = *smarty3* strings.php *.log *.out *test*
OUTPUT_DIRECTORY = doc
GENERATE_HTML = YES
HTML_OUTPUT = html/
@ -15,7 +15,6 @@ GENERATE_TODOLIST = YES
USE_MDFILE_AS_MAINPAGE = README.md
REFERENCED_BY_RELATION = YES
GENERATE_TREEVIEW = YES
HTML_FOOTER = util/Doxygen.footer
ALIASES += "license=@par License:\n"
ALIASES += "fixme=\xrefitem fixme \"Fixme\" \"Fixme List\""
ALIASES += "FIXME=\fixme"

View file

@ -1,364 +0,0 @@
Friendica Installation
We've tried very hard to ensure that Friendica will run on commodity hosting
platforms - such as those used to host Wordpress blogs and Drupal websites.
But be aware that Friendica is more than a simple web application. It is a
complex communications system which more closely resembles an email server
than a web server. For reliability and performance, messages are delivered in
the background and are queued for later delivery when sites are down. This
kind of functionality requires a bit more of the host system than the typical
blog. Not every PHP/MySQL hosting provider will be able to support Friendica.
Many will. But please review the requirements and confirm these with your
hosting provider prior to installation.
Before you begin: Choose a domain name or subdomain name for your server.
Put some thought into this - because changing it is currently not-supported.
Things will break, and some of your friends may have difficulty communicating
with you. We plan to address this limitation in a future release. Also decide
if you wish to connect with members of the Diaspora network, as this will
impact the installation requirements.
Decide if you will use SSL and obtain an SSL cert. Communications with the
Diaspora network MAY require both SSL AND an SSL cert signed by a CA which is
recognised by the major browsers. Friendica will work with self-signed certs
but Diaspora communication may not. For best results, install your cert PRIOR
to installing Friendica and when visiting your site for the initial
installation in step 5, please use the https: link. (Use the http: or non-SSL
link if your cert 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 recommended for performance).
- PHP *command line* access with register_argc_argv set to true in the
php.ini file [or see 'poormancron' in section 8]
- 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
- The POSIX module of PHP needs to be activated (e.g. RHEL, CentOS have disabled it)
- Mysql 5.5.3+ or an equivalant alternative for MySQL (MariaDB, Percona Server etc.)
- ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks
(Windows) [Note: other options are presented in Section 8 of this document]
- Installation into a top-level domain or sub-domain (without a
directory/path component in the URL) is preferred. This is REQUIRED if
you wish to communicate with the Diaspora network.
- For alternative server configurations (such as Nginx server and MariaDB
database engine), refer to the wiki at https://github.com/friendica/friendica/wiki
This guide will walk you through the manual installation process of Friendica.
If this is nothing for you, you might be interested in
* the Friendica Docker image (https://github.com/friendica/docker) or
* how install Friendica with YunoHost (https://github.com/YunoHost-Apps/friendica_ynh).
2. Unpack the Friendica files into the root of your web server document area.
- If you copy the directory tree to your webserver, make sure
that you also copy .htaccess - as "dot" files are often hidden
and aren't normally copied.
OR
2b. Clone the friendica/friendica GitHub repository and import dependencies
git clone https://github.com/friendica/friendica -b master [web server folder]
cd [web server folder]
php bin/composer.phar install
Make sure the folder view/smarty3 exists and is writable by the webserver
user, in this case `www-data`
mkdir view/smarty3
chown www-data:www-data view/smarty3
chmod 775 view/smarty3
Get the addons by going into your website folder.
cd mywebsite
Clone the addon repository (separately):
git clone https://github.com/friendica/friendica-addons.git -b master addon
If you copy the directory tree to your webserver, make sure that you also
copy .htaccess - as "dot" files are often hidden and aren't normally copied.
If you want to use the development version of Friendica you can switch to
the devel branch in the repository by running
git checkout develop
bin/composer.phar install
cd addon
git checkout develop
please be aware that the develop branch may break your Friendica node at any
time. If you encounter a bug, please let us know.
3. Create an empty database and note the access details (hostname, username,
password, database name).
- Friendica needs the permission to create and delete fields and tables in its own database.
- Please check the additional notes if running on MySQ 5.7.17 or newer
4. If you know in advance that it will be impossible for the web server to
write or create files in the config/ subfolder, create an empty file called
local.ini.php and make it writable by the web server.
5. Visit your website with a web browser and follow the instructions. Please
note any error messages and correct these before continuing.
If you are using SSL with a known signature authority (recommended), use the
https: link to your website. If you are using a self-signed cert or no cert,
use the http: link.
If you need to specify a port for the connection to the database, you can do
so in the host name setting for the database.
6. *If* the automated installation fails for any reason, check the following:
- "config/local.ini.php" exists
If not, edit local-sample.ini.php and change system settings. Rename
to local.ini.php
- Database is populated.
If not, import the contents of "database.sql" with phpmyadmin
or mysql command line
7. At this point visit your website again, and register your personal account.
Registration errors should all be recoverable automatically.
If you get any *critical* failure at this point, it generally indicates the
database was not installed correctly. You might wish to move/rename
local.ini.php to another name and empty (called 'dropping') the database
tables, so that you can start fresh.
****************************************************************************
****************************************************************************
******** THIS NEXT STEP IS IMPORTANT!!!! ***********
****************************************************************************
****************************************************************************
8. Set up a cron job or scheduled task to run the worker once every 5-10
minutes to pick up the recent "public" postings of your friends. Example:
cd /base/directory; /path/to/php bin/worker.php
Change "/base/directory", and "/path/to/php" as appropriate for your situation.
If you are using a Linux server, run "crontab -e" and add a line like the
one shown, substituting for your unique paths and settings:
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php bin/worker.php
You can generally find the location of PHP by executing "which php". If you
have troubles with this section please contact your hosting provider for
assistance. Friendica will not work correctly if you cannot perform this step.
You should also be sure that $a->config['php_path'] is set correctly, it should
look like (changing it to the correct PHP location)
$a->config['php_path'] = '/usr/local/php56/bin/php'
Alternative: If you cannot use a cron job as described above, you can use
the frontend worker and an external cron service to trigger the execution
of the worker script. You can enable the frontend worker after the installation
from the admin panel of your node and call
https://example.com/worker
with the service of your choice.
9. (Recommended) Set up a backup plan
Bad things will happen. Let there be a hardware failure, a corrupted
database or whatever you can think of. So once the installation of your
Friendica node is done, you should make yoursef a backup plan.
The most important file is the `config/local.ini.php` file in the base directory.
As it stores all your data, you should also have a recent dump of your
Friendica database at hand, should you have to recover your node.
10. (Optional) Reverse-proxying and HTTPS
Friendica looks for some well-known HTTP headers indicating a reverse-proxy
terminating an HTTPS connection. While the standard from RFC 7239 specifies
the use of the `Forwaded` header.
Forwarded: for=192.0.2.1; proto=https; by=192.0.2.2
Friendica also supports a number on non-standard headers in common use.
X-Forwarded-Proto: https
Front-End-Https: on
X-Forwarded-Ssl: on
It is however preferable to use the standard approach if configuring a new server.
#####################################################################
If things don't work...
#####################################################################
#####################################################################
- If you get the message
"System is currently unavailable. Please try again later"
#####################################################################
Check your database settings. It usually means your database could not
be opened or accessed. If the database resides on the same machine, check that
the database server name is "localhost".
#####################################################################
- 500 Internal Error
#####################################################################
This could be the result of one of our Apache directives not being
supported by your version of Apache. Examine your apache server logs.
You might remove the line "Options -Indexes" from the .htaccess file if
you are using a Windows server as this has been known to cause problems.
Also check your file permissions. Your website and all contents must generally
be world-readable.
It is likely that your web server reported the source of the problem in
its error log files. Please review these system error logs to determine what
caused the problem. Often this will need to be resolved with your hosting
provider or (if self-hosted) your web server configuration.
#####################################################################
- 400 and 4xx "File not found" errors
#####################################################################
First check your file permissions. Your website and all contents must
generally be world-readable.
Ensure that mod-rewite is installed and working, and that your
.htaccess file is being used. To verify the latter, create a file test.out
containing the word "test" in the top directory of Friendica, make it world
readable and point your web browser to
http://yoursitenamehere.com/test.out
This file should be blocked. You should get a permission denied message.
If you see the word "test" your Apache configuration is not allowing
your .htaccess file to be used (there are rules in this file to block access
to any file with .out at the end, as these are typically used for system logs).
Make certain the .htaccess file exists and is readable by everybody, then
look for the existence of "AllowOverride None" in the Apache server
configuration for your site. This will need to be changed to
"AllowOverride All".
If you do not see the word "test", your .htaccess is working, but it is
likely that mod-rewrite is not installed in your web server or is not working.
On most flavour of Linux,
% a2enmod rewrite
% /etc/init.d/apache2 restart
Consult your hosting provider, experts on your particular Linux
distribution or (if Windows) the provider of your Apache server software if
you need to change either of these and can not figure out how. There is
a lot of help available on the web. Google "mod-rewrite" along with the
name of your operating system distribution or Apache package (if using
Windows).
#####################################################################
- If you are unable to write the file config/local.ini.php during installation
due to permissions issues:
#####################################################################
create an empty file with that name and give it world-write permission.
For Linux:
% touch config/local.ini.php
% chmod 664 config/local.ini.php
Retry the installation. As soon as the database has been created,
******* this is important *********
% chmod 644 config/local.ini.php
#####################################################################
- Some configurations with "suhosin" security are configured without
an ability to run external processes. Friendica requires this ability.
Following are some notes provided by one of our members.
#####################################################################
On my server I use the php protection system Suhosin
[http://www.hardened-php.net/suhosin/]. One of the things it does is to block
certain functions like proc_open, as configured in /etc/php5/conf.d/suhosin.ini:
suhosin.executor.func.blacklist = proc_open, ...
For those sites like Friendica that really need these functions they can be
enabled, e.g. in /etc/apache2/sites-available/friendica:
<Directory /var/www/friendica/>
php_admin_value suhosin.executor.func.blacklist none
php_admin_value suhosin.executor.eval.blacklist none
</Directory>
This enables every function for Friendica if accessed via browser, but not for
the cronjob that is called via php command line. I attempted to enable it for
cron by using something like
*/10 * * * * cd /var/www/friendica/friendica/ && sudo -u www-data /usr/bin/php
-d suhosin.executor.func.blacklist=none -d suhosin.executor.eval.blacklist=none
-f bin/worker.php
This worked well for simple test cases, but the friendica-cron still failed with
a fatal error:
suhosin[22962]: ALERT - function within blacklist called: proc_open() (attacker
'REMOTE_ADDR not set', file '/var/www/friendica/friendica/boot.php', line 1341)
After a while I noticed, that bin/worker.php calls further php script via
proc_open. These scripts themselves also use proc_open and fail, because they
are NOT called with -d suhosin.executor.func.blacklist=none.
So the simple solution is to put the correct parameters into config/local.ini.php:
[config]
; Location of PHP command line processor
php_path = "/usr/bin/php -d suhosin.executor.func.blacklist=none -d suhosin.executor.eval.blacklist=none"
This is obvious as soon as you notice that the friendica-cron uses proc_open to
execute php-scripts that also use proc_open, but it took me quite some time to
find that out. I hope this saves some time for other people using suhosin with
function blacklists.
########################################################################
Unable to create all mysql tables on MySQL 5.7.17 or newer
#######################################################################
If the setup fails to create all the database tables and/or manual
creation from the command line fails, with this error:
ERROR 1067 (42000) at line XX: Invalid default value for 'created'
You need to adjust your my.cnf and add the following setting under
the [mysqld] section :
sql_mode = '';
After that, restart mysql and try again.

View file

@ -1,5 +1,5 @@
Friendica Communications Server
Copyright (c) 2010-2018 the Friendica Project
Copyright (c) 2010-2019 the Friendica Project
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by

View file

@ -13,29 +13,30 @@ With Friendica, you can also fully interact with anyone on Twitter, post on Face
Join today and [get your Friendica profile!](https://dir.friendica.social/servers 'Join Friendica today!')
Have a look at the [installation documentation](doc/Install.md) for further information about installing and using Friendica.
### 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,101 +0,0 @@
Friendica translations
======================
Translation Process
-------------------
The strings used in the UI of Friendica is translated at [Transifex] [1] and then included in the git repository at github.
If you want to help with translation for any language, be it correcting terms or translating friendica to a currently not supported language, please register an account at transifex.com and contact the friendica translation team there.
Translating friendica is simple.
Just use the online tool at transifex.
If you don't want to deal with git & co. that is fine, we check the status of the translations regularly and import them into the source tree at github so that others can use them.
We do not include every translation from transifex in the source tree to avoid a scattered and disturbed overall experience.
As an uneducated guess we have a lower limit of 50% translated strings before we include the language (for the core messages.po file, addont translation will be included once all strings of an addon are translated.
This limit is judging only by the amount of translated strings under the assumption that the most prominent strings for the UI will be translated first by a translation team.
If you feel your translation useable before this limit, please contact us and we will probably include your teams work in the source tree.
If you want to help translating, please concentrate on the core messages.po file first.
We will only include translations with a sufficient translated messages.po file.
Translations of addons will only be included, when the core file is included as well.
If you want to get your work into the source tree yourself, feel free to do so and contact us with and question that arises.
The process is simple and friendica ships with all the tools necessary.
The location of the translated files in the source tree is
/view/lang/LNG-CODE/
where LNG-CODE is the language code used, e.g. de for German or fr for French.
The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses.
To do so, place the file in the directory mentioned above and use the "po2php" command from the console.
*Please note that the console tool has to be called from the base directory of your Friendica installation.*
Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following.
1. Navigate at the command prompt to the base directory of your
friendica installation
2. Execute the po2php command, which will place the translation
in the strings.php file that is used by friendica.
$> php bin/console.php po2php view/lang/de/messages.po
The output of the script will be placed at view/lang/de/strings.php where
friendica is expecting it, so you can test your translation immediately.
3. Visit your friendica page to check if it still works in the language you
just translated. If not try to find the error, most likely PHP will give
you a hint in the log/warnings.about the error.
For debugging you can also try to "run" the file with PHP. This should
not give any output if the file is ok but might give a hint for
searching the bug in the file.
$> php view/lang/de/strings.php
4. commit the two files with a meaningful commit message to your git
repository, push it to your fork of the friendica repository at github and
issue a pull request for that commit.
You should translate the PO files at Transifex.
Otherwise your work might get lost, when the translation from Transifex is included to the Friendica repository after it was updated there.
Utilities
---------
Additional to the po2php command there are some more utilities for translation in the console.
If you only want to translate friendica into another language you wont need any of these tools most likely but it gives you an idea how the translation process of friendica works.
For further information see the utils/README file.
Transifex-Client
----------------
Transifex has a client program which let you interact with the translation files in a similar way to git.
Help for the client can be found at the [Transifex Help Center] [2].
Here we will only cover basic usage.
After installation of the client, you should have a `tx` command available on your system.
To use it, first create a configuration file with your credentials.
On Linux this file should be placed into your home directory `~/.transifexrc`.
The content of the file should be something like the following:
[https://www.transifex.com]
username = user
token =
password = p@ssw0rd
hostname = https://www.transifex.com
Since Friendica version 3.5.1 we ship configuration files for the Transifex client in the core repository and the addon repository.
To update the translation files after you have translated strings of e.g. Esperanto in the web-UI of transifex you can use `tx` to download the file.
$> tx pull -l eo
And then use the `po2php` command described above to convert the `messages.po` file to the `strings.php` file Friendica is loading.
$> php bin/console.php po2php view/lang/eo/messages.po
Afterwards, just commit the two changed files to a feature branch of your Friendica repository, push the changes to github and open a pull request for your changes.
[1]: https://www.transifex.com/projects/p/friendica/
[2]: https://docs.transifex.com/client/introduction

View file

@ -1 +1 @@
2018.12-dev
2019.12-dev

4
Vagrantfile vendored
View file

@ -6,8 +6,8 @@ server_timezone = "UTC"
public_folder = "/vagrant"
Vagrant.configure(2) do |config|
# Set server to Ubuntu 16.04
config.vm.box = "ubuntu/xenial64"
# Set server to Debian 10 / Buster 64bit
config.vm.box = "debian/buster64"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs

279
autotest.sh Executable file
View file

@ -0,0 +1,279 @@
#!/usr/bin/env bash
#
# This script is used for autotesting the Friendica codebase with different
# types of tests and environments.
#
# Currently, there are three types of autotesting possibilities:
# - "USEDOCKER=true ./autotest.sh" will start a database docker container for testing
# - "./autotest.sh" on the Drone CI environment will use the database container of the drone CI pipeline
# - "./autotest.sh" on a local environment will try to use the local database instance for testing
#
# You can specify a database (mysql, mariadb currently) for the db backend of Friendica ("./autotest.sh mysql")
# And you can specify some parameters for the test, like:
# - NOCOVERAGE=true ... Don't create a coverage XML (this is only useful if you will send coverage to codecov.io)
# - NOINSTALL=true ... Skip the whole Friendica installation process (e.g. you just test Caching drivers)
# - TEST_SELECTION= ... Specify which tests are used to run (based on the test-labeling)
# - XDEBUG_CONFIG= ... Set some XDEBUG specific environment settings for development
DATABASENAME=${MYSQL_DATABASE:-test}
DATABASEUSER=${MYSQL_USERNAME:-friendica}
DATABASEHOST=${MYSQL_HOST:-localhost}
BASEDIR=$PWD
DBCONFIGS="mysql mariadb"
TESTS="REDIS MEMCACHE MEMCACHED APCU NODB"
export MYSQL_DATABASE="$DATABASENAME"
export MYSQL_USERNAME="$DATABASEUSER"
export MYSQL_PASSWORD="friendica"
if [ -z "$PHP_EXE" ]; then
PHP_EXE=php
fi
PHP=$(which "$PHP_EXE")
# Use the Friendica internal composer
COMPOSER="$BASEDIR/bin/composer.phar"
set -e
_XDEBUG_CONFIG=$XDEBUG_CONFIG
unset XDEBUG_CONFIG
function show_syntax() {
echo -e "Syntax: ./autotest.sh [dbconfigname] [testfile]\n" >&2
echo -e "\t\"dbconfigname\" can be one of: $DBCONFIGS" >&2
echo -e "\t\"testfile\" is the name of a test file, for example lib/template.php" >&2
echo -e "\nDatabase environment variables:\n" >&2
echo -e "\t\"MYSQL_HOST\" Mysql Hostname (Default: localhost)" >&2
echo -e "\t\"MYSQL_USDRNAME\" Mysql Username (Default: friendica)" >&2
echo -e "\t\"MYSQL_DATABASE\" Mysql Database (Default: test)" >&2
echo -e "\nOther environment variables:\n" >&2
echo -e "\t\"TEST_SELECTION\" test a specific group of tests, can be one of: $TESTS" >&2
echo -e "\t\"NOINSTALL\" If set to true, skip the db and install process" >&2
echo -e "\t\"NOCOVERAGE\" If set to true, don't create a coverage output" >&2
echo -e "\t\"USEDOCKER\" If set to true, the DB server will be executed inside a docker container" >&2
echo -e "\nExample: NOCOVERAGE=true ./autotest.sh mysql src/Core/Cache/MemcacheTest.php" >&2
echo "will run the test suite from \"tests/src/Core/Cache/MemcacheTest.php\" without a Coverage" >&2
echo -e "\nIf no arguments are specified, all tests will be run with all database configs" >&2
}
if [ -x "$PHP" ]; then
echo "Using PHP executable $PHP"
else
echo "Could not find PHP executable $PHP_EXE" >&2
exit 3
fi
echo "Installing depdendencies"
$PHP "$COMPOSER" install
PHPUNIT="$BASEDIR/vendor/bin/phpunit"
if [ -x "$PHPUNIT" ]; then
echo "Using PHPUnit executable $PHPUNIT"
else
echo "Could not find PHPUnit executable after composer $PHPUNIT" >&2
exit 3
fi
if ! [ \( -w config -a ! -f config/local.config.php \) -o \( -f config/local.config.php -a -w config/local.config.php \) ]; then
echo "Please enable write permissions on config and config/config.php" >&2
exit 1
fi
if [ "$1" ]; then
FOUND=0
for DBCONFIG in $DBCONFIGS; do
if [ "$1" = "$DBCONFIG" ]; then
FOUND=1
break
fi
done
if [ $FOUND = 0 ]; then
echo -e "Unknown database config name \"$1\"\n" >&2
show_syntax
exit 2
fi
fi
# Back up existing (dev) config if one exists and backup not already there
if [ -f config/local.config.php ] && [ ! -f config/local.config-autotest-backup.php ]; then
mv config/local.config.php config/local.config-autotest-backup.php
fi
function cleanup_config() {
if [ -n "$DOCKER_CONTAINER_ID" ]; then
echo "Kill the docker $DOCKER_CONTAINER_ID"
docker stop "$DOCKER_CONTAINER_ID"
docker rm -f "$DOCKER_CONTAINER_ID"
fi
cd "$BASEDIR"
# Restore existing config
if [ -f config/local.config-autotest-backup.php ]; then
mv config/local.config-autotest-backup.php config/local.config.php
fi
}
# restore config on exit
trap cleanup_config EXIT
function execute_tests() {
DB=$1
echo "Setup environment for $DB testing ..."
# back to root folder
cd "$BASEDIR"
# backup current config
if [ -f config/local.config.php ]; then
mv config/local.config.php config/local.config-autotest-backup.php
fi
if [ -z "$NOINSTALL" ]; then
#drop database
if [ "$DB" == "mysql" ]; then
if [ -n "$USEDOCKER" ]; then
echo "Fire up the mysql docker"
DOCKER_CONTAINER_ID=$(docker run \
-e MYSQL_ROOT_PASSWORD=friendica \
-e MYSQL_USER="$DATABASEUSER" \
-e MYSQL_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-d mysql)
DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID")
else
if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI
if [ "mysql" != "$(mysql --version | grep -o mysql)" ]; then
echo "Your mysql binary is not provided by mysql"
echo "To use the docker container set the USEDOCKER environment variable"
exit 3
fi
mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true
mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST
else
DATABASEHOST=mysql
fi
fi
echo "Waiting for MySQL $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
echo "[ERROR] Waited 300 seconds, no response" >&2
exit 1
fi
echo "MySQL is up."
fi
if [ "$DB" == "mariadb" ]; then
if [ -n "$USEDOCKER" ]; then
echo "Fire up the mariadb docker"
DOCKER_CONTAINER_ID=$(docker run \
-e MYSQL_ROOT_PASSWORD=friendica \
-e MYSQL_USER="$DATABASEUSER" \
-e MYSQL_PASSWORD=friendica \
-e MYSQL_DATABASE="$DATABASENAME" \
-d mariadb)
DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID")
else
if [ -z "$DRONE" ]; then # no need to drop the DB when we are on CI
if [ "MariaDB" != "$(mysql --version | grep -o MariaDB)" ]; then
echo "Your mysql binary is not provided by mysql"
echo "To use the docker container set the USEDOCKER environment variable"
exit 3
fi
mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME" -h $DATABASEHOST || true
mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" -h $DATABASEHOST
else
DATABASEHOST=mariadb
fi
fi
echo "Waiting for MariaDB $DATABASEHOST initialization..."
if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
echo "[ERROR] Waited 300 seconds, no response" >&2
exit 1
fi
echo "MariaDB is up."
fi
if [ -n "$USEDOCKER" ]; then
echo "Initialize database..."
docker exec $DOCKER_CONTAINER_ID mysql -u root -pfriendica -e 'CREATE DATABASE IF NOT EXISTS $DATABASENAME;'
fi
export MYSQL_HOST="$DATABASEHOST"
#call installer
echo "Installing Friendica..."
"$PHP" ./bin/console.php autoinstall --dbuser="$DATABASEUSER" --dbpass=friendica --dbdata="$DATABASENAME" --dbhost="$DATABASEHOST" --url=https://friendica.local --admin=admin@friendica.local
fi
#test execution
echo "Testing..."
rm -fr "coverage-html"
mkdir "coverage-html"
if [[ "$_XDEBUG_CONFIG" ]]; then
export XDEBUG_CONFIG=$_XDEBUG_CONFIG
fi
COVER=''
if [ -z "$NOCOVERAGE" ]; then
COVER="--coverage-clover tests/autotest-clover.xml"
else
echo "No coverage"
fi
# per default, there is no cache installed
GROUP='--exclude-group REDIS,MEMCACHE,MEMCACHED,APCU'
if [ "$TEST_SELECTION" == "REDIS" ]; then
GROUP="--group REDIS"
fi
if [ "$TEST_SELECTION" == "MEMCACHE" ]; then
GROUP="--group MEMCACHE"
fi
if [ "$TEST_SELECTION" == "MEMCACHED" ]; then
GROUP="--group MEMCACHED"
fi
if [ "$TEST_SELECTION" == "APCU" ]; then
GROUP="--group APCU"
fi
if [ "$TEST_SELECTION" == "NODB" ]; then
GROUP="--exclude-group DB,SLOWDB"
fi
INPUT="$BASEDIR/tests"
if [ -n "$2" ]; then
INPUT="$INPUT/$2"
fi
echo "${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3"
"${PHPUNIT[@]}" --configuration tests/phpunit.xml $GROUP $COVER --log-junit "autotest-results.xml" "$INPUT" "$3"
RESULT=$?
if [ -n "$DOCKER_CONTAINER_ID" ]; then
echo "Kill the docker $DOCKER_CONTAINER_ID"
docker stop $DOCKER_CONTAINER_ID
docker rm -f $DOCKER_CONTAINER_ID
unset $DOCKER_CONTAINER_ID
fi
}
#
# Start the test execution
#
if [ -z "$1" ] && [ -n "$TEST_SELECTION" ]; then
# run all known database configs
for DBCONFIG in $DBCONFIGS; do
execute_tests "$DBCONFIG"
done
else
FILENAME="$2"
if [ -n "$2" ] && [ ! -f "tests/$FILENAME" ] && [ "${FILENAME:0:2}" != "--" ]; then
FILENAME="../$FILENAME"
fi
execute_tests "$1" "$FILENAME" "$3"
fi

View file

@ -32,8 +32,11 @@
*
*/
use Friendica\App;
use Dice\Dice;
use Friendica\App\Mode;
use Friendica\BaseObject;
use Friendica\Util\ExAuth;
use Psr\Log\LoggerInterface;
if (sizeof($_SERVER["argv"]) == 0) {
die();
@ -49,12 +52,16 @@ $directory = realpath($directory . DIRECTORY_SEPARATOR . "..");
chdir($directory);
require_once "boot.php";
require_once "include/dba.php";
require dirname(__DIR__) . '/vendor/autoload.php';
$a = new App(dirname(__DIR__));
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabberd']]);
if ($a->getMode()->isNormal()) {
BaseObject::setDependencyInjection($dice);
$appMode = $dice->create(Mode::class);
if ($appMode->isNormal()) {
$oAuth = new ExAuth();
$oAuth->readStdin();
}

View file

@ -1,9 +1,12 @@
#!/usr/bin/env php
<?php
include_once dirname(__DIR__) . '/boot.php';
use Dice\Dice;
use Psr\Log\LoggerInterface;
$a = new Friendica\App(dirname(__DIR__));
\Friendica\BaseObject::setApp($a);
require dirname(__DIR__) . '/vendor/autoload.php';
(new Friendica\Core\Console($argv))->execute();
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]);
(new Friendica\Core\Console($dice, $argv))->execute();

View file

@ -7,10 +7,12 @@
* This script was taken from http://php.net/manual/en/function.pcntl-fork.php
*/
use Friendica\App;
use Dice\Dice;
use Friendica\Core\Config;
use Friendica\Core\Logger;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Psr\Log\LoggerInterface;
// Get options
$shortopts = 'f';
@ -29,10 +31,13 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
chdir($directory);
}
require_once "boot.php";
require_once "include/dba.php";
require dirname(__DIR__) . '/vendor/autoload.php';
$a = new App(dirname(__DIR__));
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']]);
\Friendica\BaseObject::setDependencyInjection($dice);
$a = \Friendica\BaseObject::getApp();
if ($a->getMode()->isInstall()) {
die("Friendica isn't properly installed yet.\n");
@ -41,9 +46,14 @@ if ($a->getMode()->isInstall()) {
Config::load();
if (empty(Config::get('system', 'pidfile'))) {
die('Please set system.pidfile in config/local.ini.php. For example:'."\n".
'[system]'."\n".
'pidfile = /path/to/daemon.pid'."\n");
die(<<<TXT
Please set system.pidfile in config/local.config.php. For example:
'system' => [
'pidfile' => '/path/to/daemon.pid',
],
TXT
);
}
$pidfile = Config::get('system', 'pidfile');
@ -97,7 +107,7 @@ if ($mode == "stop") {
unlink($pidfile);
logger("Worker daemon process $pid was killed.", LOGGER_DEBUG);
Logger::notice("Worker daemon process was killed", ["pid" => $pid]);
Config::set('system', 'worker_daemon_mode', false);
die("Worker daemon process $pid was killed.\n");
@ -107,7 +117,7 @@ if (!empty($pid) && posix_kill($pid, 0)) {
die("Daemon process $pid is already running.\n");
}
logger('Starting worker daemon.', LOGGER_DEBUG);
Logger::notice('Starting worker daemon.', ["pid" => $pid]);
if (!$foreground) {
echo "Starting worker daemon.\n";
@ -139,7 +149,7 @@ if (!$foreground) {
file_put_contents($pidfile, $pid);
// We lose the database connection upon forking
$a->loadDatabase();
DBA::reconnect();
}
Config::set('system', 'worker_daemon_mode', true);
@ -155,7 +165,7 @@ $last_cron = 0;
// Now running as a daemon.
while (true) {
if (!$do_cron && ($last_cron + $wait_interval) < time()) {
logger('Forcing cron worker call.', LOGGER_DEBUG);
Logger::info('Forcing cron worker call.', ["pid" => $pid]);
$do_cron = true;
}
@ -169,7 +179,7 @@ while (true) {
$last_cron = time();
}
logger("Sleeping", LOGGER_DEBUG);
Logger::info("Sleeping", ["pid" => $pid]);
$start = time();
do {
$seconds = (time() - $start);
@ -186,10 +196,10 @@ while (true) {
if ($timeout) {
$do_cron = true;
logger("Woke up after $wait_interval seconds.", LOGGER_DEBUG);
Logger::info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
} else {
$do_cron = false;
logger("Worker jobs are calling to be forked.", LOGGER_DEBUG);
Logger::info("Worker jobs are calling to be forked.", ["pid" => $pid]);
}
}

View file

@ -1,241 +0,0 @@
#!/usr/bin/python
#
# Script to convert Friendica internal template files into Smarty template files
# Copyright 2013 Zach Prezkuta
# Licensed under GPL v3
import os, re, string
import sys, getopt
ldelim = '{{'
rdelim = '}}'
addheader = True
def fToSmarty(matches):
match = matches.group(0)
if match == '$j':
return match
match = string.replace(match, '[', '')
match = string.replace(match, ']', '')
ldel = ldelim
rdel = rdelim
if match.find("'") > -1:
match = string.replace(match, "'", '')
ldel = "'" + ldel
rdel = rdel + "'"
elif match.find('"') > -1:
match = string.replace(match, '"', '')
ldel = '"' + ldel
rdel = rdel + '"'
return ldel + match + rdel
def fix_element(element):
# Much of the positioning here is important, e.g. if you do element.find('if ') before you do
# element.find('endif'), then you may get some multiply-replaced delimiters
if element.find('endif') > -1:
element = ldelim + '/if' + rdelim
return element
if element.find('if ') > -1:
element = string.replace(element, '{{ if', ldelim + 'if')
element = string.replace(element, '{{if', ldelim + 'if')
element = string.replace(element, ' }}', rdelim)
element = string.replace(element, '}}', rdelim)
return element
if element.find('else') > -1:
element = ldelim + 'else' + rdelim
return element
if element.find('endfor') > -1:
element = ldelim + '/foreach' + rdelim
return element
if element.find('for ') > -1:
element = string.replace(element, '{{ for ', ldelim + 'foreach ')
element = string.replace(element, '{{for ', ldelim + 'foreach ')
element = string.replace(element, ' }}', rdelim)
element = string.replace(element, '}}', rdelim)
return element
if element.find('endinc') > -1:
element = ''
return element
if element.find('inc ') > -1:
parts = element.split(' ')
element = ldelim + 'include file="'
# We need to find the file name. It'll either be in parts[1] if the element was written as {{ inc file.tpl }}
# or it'll be in parts[2] if the element was written as {{inc file.tpl}}
if parts[0].find('inc') > -1:
first = 0
else:
first = 1
if parts[first+1][0] == '$':
# This takes care of elements where the filename is a variable, e.g. {{ inc $file }}
element += ldelim + parts[first+1].rstrip('}') + rdelim
else:
# This takes care of elements where the filename is a path, e.g. {{ inc file.tpl }}
element += parts[first+1].rstrip('}')
element += '"'
if len(parts) > first + 1 and parts[first+2] == 'with':
# Take care of variable substitutions, e.g. {{ inc file.tpl with $var=this_var }}
element += ' ' + parts[first+3].rstrip('}')[1:]
element += rdelim
return element
def convert(filename, tofilename, php_tpl):
if addheader:
header = ldelim + "*\n *\tAUTOMATICALLY GENERATED TEMPLATE\n *\tDO NOT EDIT THIS FILE, CHANGES WILL BE OVERWRITTEN\n *\n *" + rdelim + "\n"
tofilename.write(header)
for line in filename:
newline = ''
st_pos = 0
brack_pos = line.find('{{')
if php_tpl:
# If php_tpl is True, this script will only convert variables in quotes, like '$variable'
# or "$variable". This is for .tpl files that produce PHP scripts, where you don't want
# all the PHP variables converted into Smarty variables
pattern1 = re.compile(r"""
([\'\"]\$\[[a-zA-Z]\w*
(\.
(\d+|[a-zA-Z][\w-]*)
)*
(\|[\w\$:\.]*)*
\][\'\"])
""", re.VERBOSE)
pattern2 = re.compile(r"""
([\'\"]\$[a-zA-Z]\w*
(\.
(\d+|[a-zA-Z][\w-]*)
)*
(\|[\w\$:\.]*)*
[\'\"])
""", re.VERBOSE)
else:
# Compile the pattern for bracket-style variables, e.g. $[variable.key|filter:arg1:arg2|filter2:arg1:arg2]
# Note that dashes are only allowed in array keys if the key doesn't start
# with a number, e.g. $[variable.key-id] is ok but $[variable.12-id] isn't
#
# Doesn't currently process the argument position key 'x', i.e. filter:arg1:x:arg2 doesn't get
# changed to arg1|filter:variable:arg2 like Smarty requires
#
# Filter arguments can be variables, e.g. $variable, but currently can't have array keys with dashes
# like filter:$variable.key-name
pattern1 = re.compile(r"""
(\$\[[a-zA-Z]\w*
(\.
(\d+|[a-zA-Z][\w-]*)
)*
(\|[\w\$:\.]*)*
\])
""", re.VERBOSE)
# Compile the pattern for normal style variables, e.g. $variable.key
pattern2 = re.compile(r"""
(\$[a-zA-Z]\w*
(\.
(\d+|[a-zA-Z][\w-]*)
)*
(\|[\w\$:\.]*)*
)
""", re.VERBOSE)
while brack_pos > -1:
if brack_pos > st_pos:
line_segment = line[st_pos:brack_pos]
line_segment = pattern2.sub(fToSmarty, line_segment)
newline += pattern1.sub(fToSmarty, line_segment)
end_brack_pos = line.find('}}', brack_pos)
if end_brack_pos < 0:
print "Error: no matching bracket found"
newline += fix_element(line[brack_pos:end_brack_pos + 2])
st_pos = end_brack_pos + 2
brack_pos = line.find('{{', st_pos)
line_segment = line[st_pos:]
line_segment = pattern2.sub(fToSmarty, line_segment)
newline += pattern1.sub(fToSmarty, line_segment)
newline = newline.replace("{#", ldelim + "*")
newline = newline.replace("#}", "*" + rdelim)
tofilename.write(newline)
def help(pname):
print "\nUsage:"
print "\t" + pname + " -h\n\n\t\t\tShow this help screen\n"
print "\t" + pname + " -p directory\n\n\t\t\tConvert all .tpl files in directory to\n\t\t\tSmarty templates in directory/smarty3/\n"
print "\t" + pname + "\n\n\t\t\tInteractive mode\n"
#
# Main script
#
path = ''
try:
opts, args = getopt.getopt(sys.argv[1:], "hp:", ['no-header'])
for opt, arg in opts:
if opt == '-h':
help(sys.argv[0])
sys.exit()
elif opt == '-p':
path = arg
elif opt == '--no-header':
addheader = False
except getopt.GetoptError:
help(sys.argv[0])
sys.exit(2)
if path == '':
path = raw_input('Path to template folder to convert: ')
if path[-1:] != '/':
path = path + '/'
outpath = path + 'smarty3/'
if not os.path.exists(outpath):
os.makedirs(outpath)
files = os.listdir(path)
for a_file in files:
if a_file == 'local.ini.tpl':
php_tpl = True
else:
php_tpl = False
filename = os.path.join(path,a_file)
ext = a_file.split('.')[-1]
if os.path.isfile(filename) and ext == 'tpl':
f = open(filename, 'r')
newfilename = os.path.join(outpath,a_file)
outf = open(newfilename, 'w')
print "Converting " + filename + " to " + newfilename
convert(f, outf, php_tpl)
outf.close()
f.close()

View file

@ -5,7 +5,7 @@
This script will collect the contributors to friendica and its translations from
* the git log of the friendica core and addons repositories
* the translated messages.po from core and the addons.
The collected names will be saved in /util/credits.txt which is also parsed from
The collected names will be saved in CREDITS.txt which is also parsed from
yourfriendica.tld/credits.
The output is not perfect, so remember to open a fresh (re)created credits.txt file
@ -23,10 +23,12 @@ import os, glob, subprocess
# not work in some cases.
dontinclude = ['root', 'friendica', 'bavatar', 'tony baldwin', 'Taek', 'silke m',
'leberwurscht', 'abinoam', 'fabrixxm', 'FULL NAME', 'Hauke Zuehl',
'Michal Supler', 'michal_s', 'Manuel Pérez', 'rabuzarus', 'Alberto Díaz']
'Michal Supler', 'michal_s', 'Manuel Pérez', 'rabuzarus',
'Alberto Díaz', 'hoergen oostende', 'Friendica', 'vinzv',
'Vincent Vindarel']
# this script is in the /util sub-directory of the friendica installation
# this script is in the /bin/dev directory of the friendica installation
# so the friendica path is the 0th argument of calling this script but we
# need to remove the name of the file and the name of the directory
path = os.path.abspath(argv[0].split('bin/dev/make_credits.py')[0])
@ -88,10 +90,14 @@ for f in glob.glob(path+'/addon/*/lang/*/messages.po'):
for ll in l:
if intrans and ll.strip()=='':
intrans = False;
if intrans and ll[0]=='#':
name = ll.split('# ')[1].split(',')[0].split(' <')[0]
if not name in contributors and name not in dontinclude:
contributors.append(name)
# at this point Transifex sometimes includes a "#, fuzzy" we eill
# ignore all lines starting with "#," as they do not contains any
# "Name email, year" information.
if not "#," in ll:
if intrans and ll[0]=='#':
name = ll.split('# ')[1].split(',')[0].split(' <')[0]
if not name in contributors and name not in dontinclude:
contributors.append(name)
if "# Translators:" in ll:
intrans = True
# done with the translators
@ -101,7 +107,7 @@ print(' > found %d translators' % (n3-n2))
print('> found a total of %d contributors and translators' % n3)
contributors.sort(key=str.lower)
f = open(path+'/util/credits.txt', 'w')
f = open(path+'/CREDITS.txt', 'w')
f.write("\n".join(contributors))
f.close()
print('> list saved to util/credits.txt')
print('> list saved to CREDITS.txt')

View file

@ -1,64 +0,0 @@
#!/usr/bin/python
#
# Script to update Smarty template files from all internal templates
# Copyright 2013 Zach Prezkuta
# Licensed under GPL v3
import os
import sys, getopt
import subprocess
def help(pname):
print "\nUsage:"
print "\t" + pname + " -h\n\n\t\t\tShow this help screen\n"
print "\t" + pname + " -p directory\n\n\t\t\tConvert all .tpl files in top-level\n\t\t\tFriendica directory to Smarty templates\n"
print "\t" + pname + "\n\n\t\t\tInteractive mode\n"
#
# Main script
#
path = ''
try:
opts, args = getopt.getopt(sys.argv[1:], "hp:")
for opt, arg in opts:
if opt == '-h':
help(sys.argv[0])
sys.exit()
elif opt == '-p':
path = arg
except getopt.GetoptError:
help(sys.argv[0])
sys.exit(2)
if path == '':
path = raw_input('Path to top-level Friendica directory: ')
if path[-1:] != '/':
path = path + '/'
tplpaths = ['view/']
names = os.listdir(path + 'view/')
for name in names:
if os.path.isdir(path + 'view/' + name):
if name != 'smarty3' and name != 'theme':
tplpaths.append('view/' + name + '/')
names = os.listdir(path + 'view/theme/')
for name in names:
if os.path.isdir(path + 'view/theme/' + name):
tplpaths.append('view/theme/' + name + '/')
fnull = open(os.devnull, "w")
for tplpath in tplpaths:
print "Converting " + path + tplpath
subprocess.call(['python', path + 'util/friendica-to-smarty-tpl.py', '-p', path + tplpath], stdout = fnull)
fnull.close()

View file

@ -37,9 +37,9 @@ sudo apt-get install -y apache2
sudo a2enmod rewrite actions ssl
sudo cp /vagrant/bin/dev/vagrant_vhost.sh /usr/local/bin/vhost
sudo chmod guo+x /usr/local/bin/vhost
sudo vhost -s 192.168.22.10.xip.io -d /var/www -p /etc/ssl/xip.io -c xip.io -a friendica.local
sudo a2dissite 000-default
sudo service apache2 restart
sudo vhost -s 192.168.22.10.xip.io -d /var/www -p /etc/ssl/xip.io -c xip.io -a friendica.local
sudo a2dissite 000-default
sudo service apache2 restart
#Install php
echo ">>> Installing PHP7"
@ -48,9 +48,9 @@ sudo systemctl restart apache2
#Install mysql
echo ">>> Installing Mysql"
sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password root"
sudo debconf-set-selections <<< "mysql-server mysql-server/root_password_again password root"
sudo apt-get install -qq mysql-server
sudo debconf-set-selections <<< "mariadb-server mariadb-server/root_password password root"
sudo debconf-set-selections <<< "mariadb-server mariadb-server/root_password_again password root"
sudo apt-get install -qq mariadb-server
# enable remote access
# setting the mysql bind-address to allow connections from everywhere
sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
@ -76,6 +76,9 @@ debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'
sudo apt-get install -y postfix mailutils libmailutils-dev
sudo echo -e "friendica1: vagrant\nfriendica2: vagrant\nfriendica3: vagrant\nfriendica4: vagrant\nfriendica5: vagrant" >> /etc/aliases && sudo newaliases
# Friendica needs git for fetching some dependencies
sudo apt-get install -y git
#make the vagrant directory the docroot
sudo rm -rf /var/www/
sudo ln -fs /vagrant /var/www
@ -83,11 +86,13 @@ sudo ln -fs /vagrant /var/www
# install deps with composer
sudo apt install unzip
cd /var/www
php bin/composer.phar install
sudo -u www-data php bin/composer.phar install
# initial config file for friendica in vagrant
#cp /vagrant/util/htconfig.vagrant.php /vagrant/.htconfig.php
cp /vagrant/util/local.ini.vagrant.php /vagrant/config/local.ini.php
cp /vagrant/mods/local.config.vagrant.php /vagrant/config/local.config.php
# copy the .htaccess-dist file to .htaccess so that rewrite rules work
cp /vagrant/.htaccess-dist /vagrant/.htaccess
# create the friendica database
echo "create database friendica DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci" | $MYSQL -u root -proot

View file

@ -45,7 +45,7 @@ case "$MODE" in
;;
'default')
cd "$FULLPATH/.."
OUTFILE="$FULLPATH/../util/messages.po"
OUTFILE="$FULLPATH/../view/lang/C/messages.po"
FINDSTARTDIR="."
# skip addon folder
FINDOPTS="( -wholename */addon -or -wholename */addons -or -wholename */addons-extra -or -wholename */smarty3 ) -prune -o"

45
bin/wait-for-connection Executable file
View file

@ -0,0 +1,45 @@
#!/usr/bin/php
#
# This script tries to connect to a database for a given interval
# Useful in case of installation e.g. to wait for the database to not generate unnecessary errors
#
# Usage: php bin/wait-for-connection {HOST} {PORT} [{TIMEOUT}]
<?php
$timeout = 60;
switch ($argc) {
case 4:
$timeout = (float)$argv[3];
case 3:
$host = $argv[1];
$port = (int)$argv[2];
break;
default:
fwrite(STDERR, 'Usage: '.$argv[0].' host port [timeout]'."\n");
exit(2);
}
if ($timeout < 0) {
fwrite(STDERR, 'Timeout must be greater than zero'."\n");
exit(2);
}
if ($port < 1) {
fwrite(STDERR, 'Port must be an integer greater than zero'."\n");
exit(2);
}
$socketTimeout = (float)ini_get('default_socket_timeout');
if ($socketTimeout > $timeout) {
$socketTimeout = $timeout;
}
$stopTime = time() + $timeout;
do {
$sock = @fsockopen($host, $port, $errno, $errstr, $socketTimeout);
if ($sock !== false) {
fclose($sock);
fwrite(STDOUT, "\n");
exit(0);
}
sleep(1);
fwrite(STDOUT, '.');
} while (time() < $stopTime);
fwrite(STDOUT, "\n");
exit(1);

View file

@ -4,9 +4,14 @@
* @file bin/worker.php
* @brief Starts the background processing
*/
use Dice\Dice;
use Friendica\App;
use Friendica\BaseObject;
use Friendica\Core\Config;
use Friendica\Core\Update;
use Friendica\Core\Worker;
use Psr\Log\LoggerInterface;
// Get options
$shortopts = 'sn';
@ -25,12 +30,16 @@ if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
chdir($directory);
}
require_once "boot.php";
require dirname(__DIR__) . '/vendor/autoload.php';
$a = new App(dirname(__DIR__));
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']]);
BaseObject::setDependencyInjection($dice);
$a = BaseObject::getApp();
// Check the database structure and possibly fixes it
check_db(true);
Update::check($a->getBasePath(), true, $a->getMode());
// Quit when in maintenance
if (!$a->getMode()->has(App\Mode::MAINTENANCEDISABLED)) {
@ -43,7 +52,7 @@ $spawn = array_key_exists('s', $options) || array_key_exists('spawn', $options);
if ($spawn) {
Worker::spawnWorker();
killme();
exit();
}
$run_cron = !array_key_exists('n', $options) && !array_key_exists('no_cron', $options);

470
boot.php
View file

@ -17,39 +17,25 @@
* easily as email does today.
*/
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
use Friendica\App;
use Friendica\BaseObject;
use Friendica\Core\Addon;
use Friendica\Core\Cache;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Model\Contact;
use Friendica\Model\Conversation;
use Friendica\Model\Term;
use Friendica\Util\BasePath;
use Friendica\Util\DateTimeFormat;
require_once 'include/text.php';
define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily');
define('FRIENDICA_VERSION', '2018.12-dev');
define('FRIENDICA_CODENAME', 'Dalmatian Bellflower');
define('FRIENDICA_VERSION', '2019.12-dev');
define('DFRN_PROTOCOL_VERSION', '2.23');
define('NEW_UPDATE_ROUTINE_VERSION', 1170);
/**
* @brief Constants for the database update check
*/
const DB_UPDATE_NOT_CHECKED = 0; // Database check wasn't executed before
const DB_UPDATE_SUCCESSFUL = 1; // Database check was successful
const DB_UPDATE_FAILED = 2; // Database check failed
/**
* @brief Constant with a HTML line break.
*
@ -63,13 +49,13 @@ define('EOL', "<br />\r\n");
* @brief Image storage quality.
*
* Lower numbers save space at cost of image detail.
* For ease of upgrade, please do not change here. Set [system] jpegquality = n in config/local.ini.php,
* For ease of upgrade, please do not change here. Set system.jpegquality = n in config/local.config.php,
* where n is between 1 and 100, and with very poor results below about 50
*/
define('JPEG_QUALITY', 100);
/**
* [system] png_quality = n where is between 0 (uncompressed) to 9
* system.png_quality = n where is between 0 (uncompressed) to 9
*/
define('PNG_QUALITY', 8);
@ -80,10 +66,12 @@ define('PNG_QUALITY', 8);
* this length (on the longest side, the other side will be scaled appropriately).
* Modify this value using
*
* [system]
* max_image_length = n;
* 'system' => [
* 'max_image_length' => 'n',
* ...
* ],
*
* in config/local.ini.php
* in config/local.config.php
*
* If you don't want to set a maximum length, set to -1. The default value is
* defined by 'MAX_IMAGE_LENGTH' below.
@ -95,55 +83,12 @@ 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);
/* @}*/
/**
* @name Logger
*
* log levels
* @{
*/
define('LOGGER_WARNING', 0);
define('LOGGER_INFO', 1);
define('LOGGER_TRACE', 2);
define('LOGGER_DEBUG', 3);
define('LOGGER_DATA', 4);
define('LOGGER_ALL', 5);
/* @}*/
/**
* @name Register
*
* Registration policies
* @{
*/
define('REGISTER_CLOSED', 0);
define('REGISTER_APPROVE', 1);
define('REGISTER_OPEN', 2);
/**
* @}
*/
/**
* @name Update
*
* DB update return values
* @{
*/
define('UPDATE_SUCCESS', 0);
define('UPDATE_FAILED', 1);
/**
* @}
*/
/** @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 */
define('REGISTER_APPROVE', \Friendica\Module\Register::APPROVE);
/** @deprecated since version 2019.03, please use \Friendica\Module\Register::OPEN instead */
define('REGISTER_OPEN', \Friendica\Module\Register::OPEN);
/**
* @name CP
@ -199,41 +144,45 @@ define('MAX_LIKERS', 75);
* Email notification options
* @{
*/
define('NOTIFY_INTRO', 0x0001);
define('NOTIFY_CONFIRM', 0x0002);
define('NOTIFY_WALL', 0x0004);
define('NOTIFY_COMMENT', 0x0008);
define('NOTIFY_MAIL', 0x0010);
define('NOTIFY_SUGGEST', 0x0020);
define('NOTIFY_PROFILE', 0x0040);
define('NOTIFY_TAGSELF', 0x0080);
define('NOTIFY_TAGSHARE', 0x0100);
define('NOTIFY_POKE', 0x0200);
define('NOTIFY_SHARE', 0x0400);
define('NOTIFY_INTRO', 1);
define('NOTIFY_CONFIRM', 2);
define('NOTIFY_WALL', 4);
define('NOTIFY_COMMENT', 8);
define('NOTIFY_MAIL', 16);
define('NOTIFY_SUGGEST', 32);
define('NOTIFY_PROFILE', 64);
define('NOTIFY_TAGSELF', 128);
define('NOTIFY_TAGSHARE', 256);
define('NOTIFY_POKE', 512);
define('NOTIFY_SHARE', 1024);
define('SYSTEM_EMAIL', 0x4000);
define('SYSTEM_EMAIL', 16384);
define('NOTIFY_SYSTEM', 0x8000);
define('NOTIFY_SYSTEM', 32768);
/* @}*/
/**
* @name Term
*
* Tag/term types
* @{
*/
define('TERM_UNKNOWN', 0);
define('TERM_HASHTAG', 1);
define('TERM_MENTION', 2);
define('TERM_CATEGORY', 3);
define('TERM_PCATEGORY', 4);
define('TERM_FILE', 5);
define('TERM_SAVEDSEARCH', 6);
define('TERM_CONVERSATION', 7);
/** @deprecated since 2019.03, use Term::UNKNOWN instead */
define('TERM_UNKNOWN', Term::UNKNOWN);
/** @deprecated since 2019.03, use Term::HASHTAG instead */
define('TERM_HASHTAG', Term::HASHTAG);
/** @deprecated since 2019.03, use Term::MENTION instead */
define('TERM_MENTION', Term::MENTION);
/** @deprecated since 2019.03, use Term::CATEGORY instead */
define('TERM_CATEGORY', Term::CATEGORY);
/** @deprecated since 2019.03, use Term::PCATEGORY instead */
define('TERM_PCATEGORY', Term::PCATEGORY);
/** @deprecated since 2019.03, use Term::FILE instead */
define('TERM_FILE', Term::FILE);
/** @deprecated since 2019.03, use Term::SAVEDSEARCH instead */
define('TERM_SAVEDSEARCH', Term::SAVEDSEARCH);
/** @deprecated since 2019.03, use Term::CONVERSATION instead */
define('TERM_CONVERSATION', Term::CONVERSATION);
define('TERM_OBJ_POST', 1);
define('TERM_OBJ_PHOTO', 2);
/** @deprecated since 2019.03, use Term::OBJECT_TYPE_POST instead */
define('TERM_OBJ_POST', Term::OBJECT_TYPE_POST);
/** @deprecated since 2019.03, use Term::OBJECT_TYPE_PHOTO instead */
define('TERM_OBJ_PHOTO', Term::OBJECT_TYPE_PHOTO);
/**
* @name Namespaces
@ -245,6 +194,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');
@ -287,6 +237,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');
@ -362,6 +313,8 @@ if (!defined('CURLE_OPERATION_TIMEDOUT')) {
*
* Useful in functions which require it but don't get it passed to them
*
* @deprecated since version 2018.09
* @see BaseObject::getApp()
* @return App
*/
function get_app()
@ -369,41 +322,6 @@ function get_app()
return BaseObject::getApp();
}
/**
* @brief Multi-purpose function to check variable state.
*
* Usage: x($var) or $x($array, 'key')
*
* returns false if variable/key is not set
* if variable is set, returns 1 if has 'non-zero' value, otherwise returns 0.
* e.g. x('') or x(0) returns 0;
*
* @param string|array $s variable to check
* @param string $k key inside the array to check
*
* @return bool|int
*/
function x($s, $k = null)
{
if ($k != null) {
if ((is_array($s)) && (array_key_exists($k, $s))) {
if ($s[$k]) {
return (int) 1;
}
return (int) 0;
}
return false;
} else {
if (isset($s)) {
if ($s) {
return (int) 1;
}
return (int) 0;
}
return false;
}
}
/**
* Return the provided variable value if it exists and is truthy or the provided
* default value instead.
@ -414,13 +332,13 @@ function x($s, $k = null)
* - defaults($var, $default)
* - defaults($array, 'key', $default)
*
* @param array $args
* @brief Returns a defaut value if the provided variable or array key is falsy
* @see x()
* @return mixed
* @deprecated since version 2019.06, use native coalesce operator (??) instead
*/
function defaults() {
$args = func_get_args();
function defaults(...$args)
{
if (count($args) < 2) {
throw new BadFunctionCallException('defaults() requires at least 2 parameters');
}
@ -431,158 +349,20 @@ function defaults() {
throw new BadFunctionCallException('defaults($arr, $key, $def) $key is null');
}
$default = array_pop($args);
// The default value always is the last argument
$return = array_pop($args);
if (call_user_func_array('x', $args)) {
if (count($args) === 1) {
$return = $args[0];
} else {
$return = $args[0][$args[1]];
}
} else {
$return = $default;
if (count($args) == 2 && is_array($args[0]) && !empty($args[0][$args[1]])) {
$return = $args[0][$args[1]];
}
if (count($args) == 1 && !empty($args[0])) {
$return = $args[0];
}
return $return;
}
/**
* @brief Function to check if request was an AJAX (xmlhttprequest) request.
*
* @param boolean $via_worker boolean Is the check run via the worker?
*/
function check_db($via_worker)
{
$build = Config::get('system', 'build');
if (empty($build)) {
Config::set('system', 'build', DB_UPDATE_VERSION - 1);
$build = DB_UPDATE_VERSION - 1;
}
// We don't support upgrading from very old versions anymore
if ($build < NEW_UPDATE_ROUTINE_VERSION) {
die('You try to update from a version prior to database version 1170. The direct upgrade path is not supported. Please update to version 3.5.4 before updating to this version.');
}
if ($build < DB_UPDATE_VERSION) {
// When we cannot execute the database update via the worker, we will do it directly
if (!Worker::add(PRIORITY_CRITICAL, 'DBUpdate') && $via_worker) {
update_db();
}
}
}
/**
* @brief Automatic database updates
* @param object $a App
*/
function update_db()
{
$build = Config::get('system', 'build');
if (empty($build) || ($build > DB_UPDATE_VERSION)) {
$build = DB_UPDATE_VERSION - 1;
Config::set('system', 'build', $build);
}
if ($build != DB_UPDATE_VERSION) {
require_once 'update.php';
$stored = intval($build);
$current = intval(DB_UPDATE_VERSION);
if ($stored < $current) {
Config::load('database');
// Compare the current structure with the defined structure
$t = Config::get('database', 'dbupdate_' . DB_UPDATE_VERSION);
if (!is_null($t)) {
return;
}
// run the pre_update_nnnn functions in update.php
for ($x = $stored + 1; $x <= $current; $x++) {
$r = run_update_function($x, 'pre_update');
if (!$r) {
break;
}
}
Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, time());
// update the structure in one call
$retval = DBStructure::update(false, true);
if ($retval) {
DBStructure::updateFail(
DB_UPDATE_VERSION,
$retval
);
return;
} else {
Config::set('database', 'dbupdate_' . DB_UPDATE_VERSION, 'success');
}
// run the update_nnnn functions in update.php
for ($x = $stored + 1; $x <= $current; $x++) {
$r = run_update_function($x, 'update');
if (!$r) {
break;
}
}
}
}
return;
}
function run_update_function($x, $prefix)
{
$funcname = $prefix . '_' . $x;
if (function_exists($funcname)) {
// There could be a lot of processes running or about to run.
// We want exactly one process to run the update command.
// So store the fact that we're taking responsibility
// after first checking to see if somebody else already has.
// If the update fails or times-out completely you may need to
// delete the config entry to try again.
$t = Config::get('database', $funcname);
if (!is_null($t)) {
return false;
}
Config::set('database', $funcname, time());
// call the specific update
$retval = $funcname();
if ($retval) {
//send the administrator an e-mail
DBStructure::updateFail(
$x,
L10n::t('Update %s failed. See error logs.', $x)
);
return false;
} else {
Config::set('database', $funcname, 'success');
if ($prefix == 'update') {
Config::set('system', 'build', $x);
}
return true;
}
} else {
Config::set('database', $funcname, 'success');
if ($prefix == 'update') {
Config::set('system', 'build', $x);
}
return true;
}
}
/**
* @brief Used to end the current process, after saving session state.
* @deprecated
@ -614,15 +394,15 @@ function public_contact()
{
static $public_contact_id = false;
if (!$public_contact_id && x($_SESSION, 'authenticated')) {
if (x($_SESSION, 'my_address')) {
if (!$public_contact_id && !empty($_SESSION['authenticated'])) {
if (!empty($_SESSION['my_address'])) {
// Local user
$public_contact_id = intval(Contact::getIdForURL($_SESSION['my_address'], 0, true));
} elseif (x($_SESSION, 'visitor_home')) {
} elseif (!empty($_SESSION['visitor_home'])) {
// Remote user
$public_contact_id = intval(Contact::getIdForURL($_SESSION['visitor_home'], 0, true));
}
} elseif (!x($_SESSION, 'authenticated')) {
} elseif (empty($_SESSION['authenticated'])) {
$public_contact_id = false;
}
@ -636,20 +416,14 @@ function public_contact()
*/
function remote_user()
{
// You cannot be both local and remote.
// Unncommented by rabuzarus because remote authentication to local
// profiles wasn't possible anymore (2018-04-12).
// if (local_user()) {
// return false;
// }
if (empty($_SESSION)) {
if (empty($_SESSION['authenticated'])) {
return false;
}
if (x($_SESSION, 'authenticated') && x($_SESSION, 'visitor_id')) {
if (!empty($_SESSION['visitor_id'])) {
return intval($_SESSION['visitor_id']);
}
return false;
}
@ -666,8 +440,8 @@ function notice($s)
return;
}
$a = get_app();
if (!x($_SESSION, 'sysmsg')) {
$a = \get_app();
if (empty($_SESSION['sysmsg'])) {
$_SESSION['sysmsg'] = [];
}
if ($a->interactive) {
@ -684,13 +458,13 @@ function notice($s)
*/
function info($s)
{
$a = get_app();
$a = \get_app();
if (local_user() && PConfig::get(local_user(), 'system', 'ignore_info')) {
return;
}
if (!x($_SESSION, 'sysmsg_info')) {
if (empty($_SESSION['sysmsg_info'])) {
$_SESSION['sysmsg_info'] = [];
}
if ($a->interactive) {
@ -747,46 +521,13 @@ function feed_birthday($uid, $tz)
*/
function is_site_admin()
{
$a = get_app();
$a = \get_app();
$admin_email = Config::get('config', 'admin_email');
$adminlist = explode(',', str_replace(' ', '', $admin_email));
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;
return local_user() && $admin_email && in_array($a->user['email'] ?? '', $adminlist);
}
function explode_querystring($query)
@ -843,16 +584,6 @@ function curPageURL()
return $pageURL;
}
function random_digits($digits)
{
$rn = '';
for ($i = 0; $i < $digits; $i++) {
/// @TODO Avoid rand/mt_rand, when it comes to cryptography, they are generating predictable (seedable) numbers.
$rn .= rand(0, 9);
}
return $rn;
}
function get_server()
{
$server = Config::get("system", "directory");
@ -866,22 +597,22 @@ function get_server()
function get_temppath()
{
$a = get_app();
$a = \get_app();
$temppath = Config::get("system", "temppath");
if (($temppath != "") && App::isDirectoryUsable($temppath)) {
if (($temppath != "") && System::isDirectoryUsable($temppath)) {
// We have a temp path and it is usable
return App::getRealPath($temppath);
return BasePath::getRealPath($temppath);
}
// We don't have a working preconfigured temp path, so we take the system path.
$temppath = sys_get_temp_dir();
// Check if it is usable
if (($temppath != "") && App::isDirectoryUsable($temppath)) {
if (($temppath != "") && System::isDirectoryUsable($temppath)) {
// Always store the real path, not the path through symlinks
$temppath = App::getRealPath($temppath);
$temppath = BasePath::getRealPath($temppath);
// To avoid any interferences with other systems we create our own directory
$new_temppath = $temppath . "/" . $a->getHostName();
@ -890,7 +621,7 @@ function get_temppath()
mkdir($new_temppath);
}
if (App::isDirectoryUsable($new_temppath)) {
if (System::isDirectoryUsable($new_temppath)) {
// The new path is usable, we are happy
Config::set("system", "temppath", $new_temppath);
return $new_temppath;
@ -972,8 +703,8 @@ function get_itemcachepath()
}
$itemcache = Config::get('system', 'itemcache');
if (($itemcache != "") && App::isDirectoryUsable($itemcache)) {
return App::getRealPath($itemcache);
if (($itemcache != "") && System::isDirectoryUsable($itemcache)) {
return BasePath::getRealPath($itemcache);
}
$temppath = get_temppath();
@ -984,7 +715,7 @@ function get_itemcachepath()
mkdir($itemcache);
}
if (App::isDirectoryUsable($itemcache)) {
if (System::isDirectoryUsable($itemcache)) {
Config::set("system", "itemcache", $itemcache);
return $itemcache;
}
@ -1000,7 +731,7 @@ function get_itemcachepath()
function get_spoolpath()
{
$spoolpath = Config::get('system', 'spoolpath');
if (($spoolpath != "") && App::isDirectoryUsable($spoolpath)) {
if (($spoolpath != "") && System::isDirectoryUsable($spoolpath)) {
// We have a spool path and it is usable
return $spoolpath;
}
@ -1015,7 +746,7 @@ function get_spoolpath()
mkdir($spoolpath);
}
if (App::isDirectoryUsable($spoolpath)) {
if (System::isDirectoryUsable($spoolpath)) {
// The new path is usable, we are happy
Config::set("system", "spoolpath", $spoolpath);
return $spoolpath;
@ -1069,3 +800,22 @@ function validate_include(&$file)
// Simply return flag
return $valid;
}
/**
* PHP 5 compatible dirname() with count parameter
*
* @see http://php.net/manual/en/function.dirname.php#113193
*
* @deprecated with PHP 7
* @param string $path
* @param int $levels
* @return string
*/
function rdirname($path, $levels = 1)
{
if ($levels > 1) {
return dirname(rdirname($path, --$levels));
} else {
return dirname($path);
}
}

View file

@ -13,32 +13,55 @@
"issues": "https://github.com/friendica/friendica/issues"
},
"require": {
"php": ">=5.6.1",
"php": ">=7.0",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"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",
"league/html-to-markdown": "~4.8.0",
"level-2/dice": ">1.0",
"lightopenid/lightopenid": "dev-master",
"michelf/php-markdown": "^1.7",
"mobiledetect/mobiledetectlib": "2.8.*",
"paragonie/random_compat": "^2.0",
"pear/Text_LanguageDetect": "1.*",
"monolog/monolog": "^1.24",
"nikic/fast-route": "^1.3",
"paragonie/hidden-string": "^1.0",
"pear/console_table": "^1.3",
"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/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",
"npm-asset/jquery-colorbox": "^1.6",
"npm-asset/jquery-datetimepicker": "^2.4.0",
"npm-asset/jgrowl": "^1.4",
"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",
"npm-asset/typeahead.js": "^0.11.1",
"bower-asset/fork-awesome": "^1.1"
},
"repositories": [
{
@ -49,11 +72,20 @@
"autoload": {
"psr-4": {
"Friendica\\": "src/",
"Friendica\\Test\\": "tests/"
"Friendica\\Test\\": "tests/",
"Friendica\\Addon\\": "addon/"
},
"psr-0": {
"": "library/"
}
},
"files": [
"include/conversation.php",
"include/dba.php",
"include/enotify.php",
"include/items.php",
"include/text.php",
"boot.php"
]
},
"config": {
"autoloader-suffix": "Friendica",
@ -68,15 +100,27 @@
},
"archive": {
"exclude": [
"log", "cache", "/photo", "/proxy"
"/.*",
"/*file",
"!/.htaccess-dist",
"/tests",
"/*.xml",
"/composer.*",
"/log",
"/cache",
"/photo",
"/proxy",
"/addon",
"!/vendor",
"!/view/asset"
]
},
"require-dev": {
"phpunit/dbunit": "^2.0",
"phpdocumentor/reflection-docblock": "^3.0.2",
"phpunit/php-token-stream": "^1.4.2",
"mikey179/vfsStream": "^1.6",
"mockery/mockery": "^1.2"
"mikey179/vfsstream": "^1.6",
"mockery/mockery": "^1.2",
"johnkary/phpunit-speedtrap": "1.1"
},
"scripts": {
"test": "phpunit"

1395
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
<?php
// Addon configuration
// Copy this configuration file to addon.config.php and edit it if you want to configure addons, see below example for the twitter addon
return [
'twitter' => [
'consumerkey' => '1234567890',
'consumersecret' => 'ABCDEFGHIJKLMONPQRSTUVWXYZ',
],
];

View file

@ -1,10 +0,0 @@
<?php return <<<INI
; Copy this configuration file to addon.ini.php and edit it if you want to configure addons, see below example for the twitter addon
;[twitter]
;consumerkey = localhost
;consumersecret = mysqlusername
INI;
// Keep this line

View file

@ -1,429 +0,0 @@
<?php return <<<INI
; CONFIG.INI.PHP
; This file declares the default values for the base config of Friendica.
; These configuration values aren't accessible from the admin settings page and custom values must be set in config/local.ini.php
; Please don't edit this file directly as its content may change in the upcoming versions.
[database]
; host (String)
; Hostname or IP address of the database server.
; Can contain the port number with the syntax "hostname:port".
hostname =
; user (String)
; Database user name. Please don't use "root".
username =
; pass (String)
; Database user password. Please don't use empty passwords.
password =
; base (String)
; Database name.
database =
; charset (String)
; Database connexion charset. Changing this value will likely corrupt special characters.
charset = utf8mb4
[config]
; admin_email (Comma-separated list)
; In order to perform system administration via the admin panel, this must precisely match the email address of the person logged in.
admin_email =
; admin_nickname (String)
; Nickname of the main admin user, used if there are more than one admin user defined in config.admin_email.
admin_nickname =
; max_import_size (Integer)
; Maximum body size of DFRN and Mail messages in characters. 0 is unlimited.
max_import_size = 200000
; php_path (String)
; Location of PHP command line processor.
php_path = php
[system]
; allowed_link_protocols (Array)
; Allowed protocols in links URLs, add at your own risk. http is always allowed.
allowed_link_protocols[0] = ftp
allowed_link_protocols[1] = ftps
allowed_link_protocols[2] = mailto
allowed_link_protocols[3] = cid
allowed_link_protocols[4] = gopher
; always_show_preview (Boolean)
; Only show small preview picures.
always_show_preview = false
; archival_days (Integer)
; Number of days that we try to deliver content before we archive a contact.
archival_days = 32
; auth_cookie_lifetime (Integer)
; Number of days that should pass without any activity before a user who chose "Remember me" when logging in is considered logged out.
auth_cookie_lifetime = 7
; block_local_dir (Boolean)
; Deny public access to the local user directory.
block_local_dir = false
; cache_driver (database|memcache|memcached|redis)
; Whether to use Memcache or Memcached or Redis to store temporary cache.
cache_driver = database
; config_adapter (jit|preload)
; Allow to switch the configuration adapter to improve performances at the cost of memory consumption.
config_adapter = jit
; curl_range_bytes (Integer)
; Maximum number of bytes that should be fetched. Default is 0, which mean "no limit".
curl_range_bytes = 0
; crawl_permit_period (Integer)
; Period in seconds between allowed searches when the number of free searches is reached and "permit_crawling" is activated.
crawl_permit_period = 60
; db_log (Path)
; Name of a logfile to log slow database queries.
db_log =
; db_log_index (Path)
; Name of a logfile to log queries with bad indexes.
db_log_index =
; db_log_index_watch (Comma-separated list)
; Watchlist of indexes to watch.
db_log_index_watch =
; db_log_index_blacklist (Comma-separated list)
; Blacklist of indexes that shouldn't be watched.
db_log_index_blacklist =
; db_loglimit (Integer)
; If a database call lasts longer than this value in seconds it is logged.
; Inactive if system.db_log is empty.
db_loglimit = 10
; db_loglimit_index (Integer)
; Number of index rows needed to be logged for indexes on the watchlist. 0 to disable.
db_loglimit_index = 0
; db_loglimit_index_high (Integer)
; Number of index rows to be logged anyway (for any index). 0 to disable.
db_loglimit_index_high = 0
; dbclean_expire_conversation (Integer)
; When DBClean is enabled, any entry in the conversation table will be deleted after this many days.
: This data is used for ActivityPub, so it shouldn't be lower than the average duration of a discussion.
dbclean_expire_conversation = 90
; dbclean-expire-limit (Integer)
; This defines the number of items that are to be deleted in a single call.
; Reduce this value when you are getting memory issues.
dbclean-expire-limit = 1000
; diaspora_test (Boolean)
; For development only. Disables the message transfer.
diaspora_test = false
; disable_email_validation (Boolean)
; Disables the check if a mail address is in a valid format and can be resolved via DNS.
disable_email_validation = false
; disable_url_validation (Boolean)
; Disables the DNS lookup of an URL.
disable_url_validation = false
; disable_password_exposed (Boolean)
; Disable the exposition check against the remote haveibeenpwned API on password change.
disable_password_exposed = false
; disable_polling (Boolean)
; Disable the polling of DFRN and OStatus contacts through onepoll.php.
disable_polling = false
; dlogfile (Path)
; location of the developer log file.
dlogfile =
; dlogip (String)
; restricts develop log writes to requests originating from this IP address.
dlogip =
; free_crawls (Integer)
; Number of "free" searches when system.permit_crawling is activated.
free_crawls = 10
; frontend_worker_timeout (Integer)
; Value in minutes after we think that a frontend task was killed by the webserver.
frontend_worker_timeout = 10
; groupedit_image_limit (Integer)
; Number of contacts at which the group editor should switch from display the profile pictures of the contacts to only display the names.
; This can alternatively be set on a per account basis in the pconfig table.
groupedit_image_limit = 400
; hsts (Boolean)
; Enables the sending of HTTP Strict Transport Security headers.
hsts = false
; ignore_cache (Boolean)
; For development only. Disables the item cache.
ignore_cache = false
; instances_social_key (String)
; Key to the API of https://instances.social which retrieves data about mastodon servers.
; See https://instances.social/api/token to get an API key.
instances_social_key =
; ipv4_resolve (Boolean)
; Resolve IPV4 addresses only. Don't resolve to IPV6.
ipv4_resolve = false
; invitation_only (Boolean)
; If set true registration is only possible after a current member of the node has send an invitation.
invitation_only = false
; like_no_comment (Boolean)
; Don't update the "commented" value of an item when it is liked.
like_no_comment = false
; local_block (Boolean)
; Used in conjunction with "block_public".
local_block = false
; local_search (Boolean)
; Blocks search for users who are not logged in to prevent crawlers from blocking your system.
local_search = false
; local_tags (Boolean)
; If activated, all hashtags will point to the local server.
local_tags = false
; max_batch_queue (Integer)
; Maximum number of batched queue items for a single contact before subsequent messages are discarded.
max_batch_queue = 1000
; max_connections (Integer)
; The maximum number of database connections which can be in use before the worker process is deferred to its next interval.
; When the system can't detect the maximum numbers of connection then this value can be used. Use 0 for auto-detection.
max_connections = 0
; max_connections_level (Integer 0-100)
; The maximum percentage of connections that are allowed to let the worker start.
max_connections_level = 75
; max_contact_queue (Integer)
; Maximum number of queue items for a single contact before subsequent messages are discarded.
max_contact_queue = 500
; max_image_length (Integer)
; An alternate way of limiting picture upload sizes.
; Specify the maximum pixel length that pictures are allowed to be (for non-square pictures, it will apply to the longest side).
; Pictures longer than this length will be resized to be this length (on the longest side, the other side will be scaled appropriately).
; If you don't want to set a maximum length, set to -1.
max_image_length = -1
; max_processes_backend (Integer)
; Maximum number of concurrent database processes for background tasks.
max_processes_backend = 5
; max_processes_frontend (Integer)
; Maximum number of concurrent database processes for foreground tasks.
max_processes_frontend = 20
; maximagesize (Integer)
; Maximum size in bytes of an uploaded photo.
maximagesize = 800000
; memcache_host (String)
; Host name of the memcache daemon.
memcache_host = 127.0.0.1
; memcache_port (Integer)
; Port number of the memcache daemon.
memcache_port = 11211
; memcached_hosts (Array)
; Array of Memcached servers info "host, port(, weight)".
memcached_hosts[0] = 127.0.0.1,11211
; min_poll_interval (Integer)
; minimal distance in minutes between two polls for a contact. Reasonable values are between 1 and 59.
min_poll_interval = 1
; no_count (Boolean)
; Don't do count calculations (currently only when showing albums).
no_count = false
; no_oembed (Boolean)
; Don't use OEmbed to fetch more information about a link.
no_oembed = false
; no_smilies (Boolean)
; Don't show smilies.
no_smilies = false
; no_view_full_size (Boolean)
; Don't add the link "View full size" under a resized image.
no_view_full_size = false
; optimize_items (Boolean)
; Triggers an SQL command to optimize the item table before expiring items.
optimize_items = false
; paranoia (Boolean)
; Log out users if their IP address changed.
paranoia = false
; permit_crawling (Boolean)
; Restricts the search for not logged in users to one search per minute.
permit_crawling = false
; pidfile (Path)
; Daemon pid file path. For example: pidfile = /path/to/daemon.pid
pidfile =
; png_quality (Integer)
; Sets the ImageMagick compression level for PNG images. Values ranges from 0 (uncompressed) to 9 (most compressed).
png_quality = 8
; profiler (Boolean)
; Enable internal timings to help optimize code. Needed for "rendertime" addon.
profiler = false
; proxy_cache_time (Integer)
; Period in seconds after which the cache is cleared.
proxy_cache_time = 86400
; pushpoll_frequency (Integer)
; Frequency of contact poll for subhub contact using the DFRM or OStatus network.
; Available values:
; - 5 = every month
; - 4 = every week
; - 3 = every day
; - 2 = twice a day
; - 1 = every hour
; - 0 = every minute
pushpoll_frequency = 3
; queue_no_dead_check (Boolean)
; Ignore if the target contact or server seems to be dead during queue delivery.
queue_no_dead_check = false
; redis_host (String)
; Host name of the redis daemon.
redis_host = 127.0.0.1
; redis_port (String)
; Port number of the redis daemon.
redis_port = 6379
; session_handler (database|cache|native)
; Whether to use Cache to store session data or to use PHP native session storage.
session_handler = database
; remove_multiplicated_lines (Boolean)
; If enabled, multiple linefeeds in items are stripped to a single one.
remove_multiplicated_lines = false
; sendmail_params (Boolean)
; Normal sendmail command parameters will be added when the PHP mail() function is called for sending e-mails.
; This ensures the Sender Email address setting is applied to the message envelope rather than the host's default address.
; Set to false if your non-sendmail agent is incompatible, or to restore old behavior of using the host address.
sendmail_params = true
; show_global_community_hint (Boolean)
; When the global community page is enabled, use this option to display a hint above the stream, that this is a collection of all public top-level postings that arrive on your node.
show_global_community_hint = false
; show_unsupported_addons (Boolean)
; Show all addons including the unsupported ones.
show_unsupported_addons = false
; show_unsupported_themes (Boolean)
; Show all themes including the unsupported ones.
show_unsupported_themes = false
; throttle_limit_day (Integer)
; Maximum number of posts that a user can send per day with the API. 0 to disable daily throttling.
throttle_limit_day = 0
; throttle_limit_week (Integer)
; Maximum number of posts that a user can send per week with the API. 0 to disable weekly throttling.
throttle_limit_week = 0
; throttle_limit_month (Integer)
; 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.
; Minimum for this config value is 1. Maximum is 64 as the resulting profile URL mustn't be longer than 255 chars.
username_min_length = 3
; username_max_length (Integer)
; The maximum character length a username can be.
; This length is check once the username has been trimmed and multiple spaces have been collapsed into one.
; Minimum for this config value is 1. Maximum is 64 as the resulting profile URL mustn't be longer than 255 chars.
username_max_length = 48
; worker_cooldown (Integer)
; Cooldown period in seconds after each worker function call.
worker_cooldown = 0
; worker_debug (Boolean)
; If enabled, it prints out the number of running processes split by priority.
worker_debug = false
; worker_fetch_limit (Integer)
; Number of worker tasks that are fetched in a single query.
worker_fetch_limit = 1
; worker_load_exponent (Integer)
; Default 3, which allows only 25% of the maximum worker queues when server load reaches around 37% of maximum load.
; For a linear response where 25% of worker queues are allowed at 75% of maximum load, set this to 1.
; Setting 0 would allow maximum worker queues at all times, which is not recommended.
worker_load_exponent = 3
; xrd_timeout (Integer)
; Timeout in seconds for fetching the XRD links.
xrd_timeout = 20
[experimental]
; exp_themes (Boolean)
; Show experimental themes in user settings.
exp_themes = false
[theme]
; hide_eventlist (Boolean)
; Don't show the birthdays and events on the profile and network page.
hide_eventlist = false
[jabber]
; debug (Boolean)
; Enable debug level for the jabber account synchronisation.
debug = false
; lockpath (Path)
; Must be writable by the ejabberd process. if set then it will prevent the running of multiple processes.
lockpath =
INI;
// Keep this line

View file

@ -0,0 +1,44 @@
<?php
// Local configuration
/* If automatic system installation fails:
*
* Copy this file to local.config.php
*
* Why local.config.php? Because it contains sensitive information which could
* give somebody complete control of your database. Apache's default
* configuration will interpret any .php file as a script and won't show the values
*
* Then set the following for your MySQL installation
*
* If you're unsure about what any of the config keys below do, please check the static/defaults.config.php file for
* detailed documentation of their data type and behavior.
*/
return [
'database' => [
'hostname' => 'localhost',
'username' => 'mysqlusername',
'password' => 'mysqlpassword',
'database' => 'mysqldatabasename',
'charset' => 'utf8mb4',
],
// ****************************************************************
// The configuration below will be overruled by the admin panel.
// Changes made below will only have an effect if the database does
// not contain any configuration for the friendica system.
// ****************************************************************
'config' => [
'admin_email' => '',
'sitename' => 'Friendica Social Network',
'register_policy' => \Friendica\Module\Register::OPEN,
'register_text' => '',
],
'system' => [
'default_timezone' => 'UTC',
'language' => 'en',
],
];

View file

@ -1,41 +0,0 @@
<?php return <<<INI
; If automatic system installation fails:
; Copy this file to local.ini.php
; Why local.ini.php? Because it contains sensitive information which could
; give somebody complete control of your database. Apache's default
; configuration will interpret any .php file as a script and won't show the values
; Then set the following for your MySQL installation
[database]
hostname = localhost
username = mysqlusername
password = mysqlpassword
database = mysqldatabasename
charset = utf8mb4
; ****************************************************************
; The configuration below will be overruled by the admin panel.
; Changes made below will only have an effect if the database does
; not contain any configuration for the friendica system.
; ****************************************************************
[config]
admin_email =
sitename = Friendica Social Network
register_policy = REGISTER_OPEN
register_text =
[system]
default_timezone = UTC
language = en
INI;
// Keep this line

View file

@ -1,112 +0,0 @@
<?php return <<<INI
; SETTINGS.INI.PHP
; This file declares the default values for the admin settings of Friendica.
; These values will be overriden by the admin settings page.
; Please don't edit this file directly as its content may change in the upcoming versions.
[config]
; info (String)
; Plaintext description of this node, used in the /friendica module.
info =
; register_policy (Constant)
; Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED.
; Be certain to create your own personal account before setting REGISTER_CLOSED.
; REGISTER_APPROVE requires you set system.admin_email to the email address of an already registered person who can authorize and/or approve/deny the request.
register_policy = REGISTER_CLOSED
; register_text (String)
; Will be displayed prominently on the registration page.
register_text = ''
; sitename (String)
; Displayed server name.
sitename = "Friendica Social Network"
[system]
; account_abandon_days (Integer)
; Will not waste system resources polling external sites for abandonded accounts.
; Enter 0 for no time limit.
account_abandon_days = 0
; addon (Comma-separated list)
; Manual list of addons which are enabled on this system.
addon =
; allowed_themes (Comma-separated list)
; Themes users can change to in their settings.
allowed_themes = 'quattro,vier,duepuntozero,smoothly'
; default_timezone (String)
; Choose a default timezone. See https://secure.php.net/manual/en/timezones.php
; It only applies to timestamps for anonymous viewers.
default_timezone = UTC
; directory (String)
; URL of the global directory.
directory = https://dir.friendica.social
; forbidden_nicknames (Comma-separated list)
; Prevents users from registering the specified nicknames on this node.
; Default value comprises classic role names from RFC 2142.
forbidden_nicknames = info, marketing, sales, support, abuse, noc, security, postmaster, hostmaster, usenet, news, webmaster, www, uucp, ftp, root, sysop
; jpeg_quality (Integer)
; Sets the ImageMagick quality level for JPEG images. Values ranges from 50 (awful) to 100 (near perfect).
jpeg_quality = 100
; language (String)
; System default languague, inluding admin-created user default language.
; Two-letters ISO 639-1 code.
language = en
; max_image_length (Integer)
; An alternate way of limiting picture upload sizes.
; Specify the maximum pixel length that pictures are allowed to be (for non-square pictures, it will apply to the longest side).
; Pictures longer than this length will be resized to be this length (on the longest side, the other side will be scaled appropriately).
; If you don't want to set a maximum length, set to -1.
max_image_length = -1
; maximagesize (Integer)
; Maximum size in bytes of an uploaded photo.
maximagesize = 800000
; no_regfullname (Boolean)
; Allow pseudonyms (true) or enforce a space between firstname and lastname in Full name, as an antispam measure (false).
no_regfullname = true
; optimize_max_tablesize (Integer)
; Maximum table size (in MB) for the automatic optimization.
; -1 to disable automatic optimization.
; 0 to use internal default (100MB)
optimize_max_tablesize = -1
; rino_encrypt (Integer)
; Server-to-server private message encryption (RINO).
; Encryption will only be provided if this setting is set to a non zero value on both servers.
; Set to 0 to disable, 2 to enable, 1 is deprecated but wont need mcrypt.
rino_encrypt = 2
; temppath (String)
; Custom temporary file directory
temppath =
; theme (String)
; System theme name.
theme = vier
; url (String)
; The fully-qualified URL of this Friendica node.
; Used by the worker in a non-HTTP execution environment.
url =
; Used in the admin settings to lock certain features
[featurelock]
INI;
// Keep this line

View file

@ -1,9 +1,34 @@
-- ------------------------------------------
-- Friendica 2018.12-dev (The Tazmans Flax-lily)
-- DB_UPDATE_VERSION 1287
-- Friendica 2019.09-rc (Dalmatian Bellflower)
-- DB_UPDATE_VERSION 1322
-- ------------------------------------------
--
-- TABLE 2fa_app_specific_password
--
CREATE TABLE IF NOT EXISTS `2fa_app_specific_password` (
`id` mediumint unsigned NOT NULL auto_increment COMMENT 'Password ID for revocation',
`uid` mediumint unsigned NOT NULL COMMENT 'User ID',
`description` varchar(255) COMMENT 'Description of the usage of the password',
`hashed_password` varchar(255) NOT NULL COMMENT 'Hashed password',
`generated` datetime NOT NULL COMMENT 'Datetime the password was generated',
`last_used` datetime COMMENT 'Datetime the password was last used',
PRIMARY KEY(`id`),
INDEX `uid_description` (`uid`,`description`(190))
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Two-factor app-specific _password';
--
-- TABLE 2fa_recovery_codes
--
CREATE TABLE IF NOT EXISTS `2fa_recovery_codes` (
`uid` mediumint unsigned NOT NULL COMMENT 'User ID',
`code` varchar(50) NOT NULL COMMENT 'Recovery code string',
`generated` datetime NOT NULL COMMENT 'Datetime the code was generated',
`used` datetime COMMENT 'Datetime the code was used',
PRIMARY KEY(`uid`,`code`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Two-factor authentication recovery codes';
--
-- TABLE addon
--
@ -31,6 +56,7 @@ CREATE TABLE IF NOT EXISTS `apcontact` (
`inbox` varchar(255) NOT NULL COMMENT '',
`outbox` varchar(255) COMMENT '',
`sharedinbox` varchar(255) COMMENT '',
`manually-approve` boolean COMMENT '',
`nick` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`name` varchar(255) COMMENT '',
`about` text COMMENT '',
@ -39,9 +65,11 @@ 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)),
INDEX `alias` (`alias`(190)),
INDEX `url` (`followers`(190))
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='ActivityPub compatible contacts - used in the ActivityPub implementation';
@ -62,6 +90,8 @@ CREATE TABLE IF NOT EXISTS `attach` (
`allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups',
`deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id',
`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',
PRIMARY KEY(`id`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='file attachments';
@ -134,14 +164,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 '',
@ -180,7 +212,8 @@ CREATE TABLE IF NOT EXISTS `contact` (
`term-date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last-item` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'date of the last post',
`priority` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
`blocked` boolean NOT NULL DEFAULT '1' COMMENT '',
`blocked` boolean NOT NULL DEFAULT '1' COMMENT 'Node-wide block status',
`block_reason` text COMMENT 'Node-wide block reason',
`readonly` boolean NOT NULL DEFAULT '0' COMMENT 'posts of the contact are readonly',
`writable` boolean NOT NULL DEFAULT '0' COMMENT '',
`forum` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a forum',
@ -191,6 +224,9 @@ CREATE TABLE IF NOT EXISTS `contact` (
`pending` boolean NOT NULL DEFAULT '1' COMMENT '',
`deleted` boolean NOT NULL DEFAULT '0' COMMENT 'Contact has been deleted',
`rating` tinyint NOT NULL DEFAULT 0 COMMENT '',
`unsearchable` boolean NOT NULL DEFAULT '0' COMMENT 'Contact prefers to not be searchable',
`sensitive` boolean NOT NULL DEFAULT '0' COMMENT 'Contact posts sensitive content',
`baseurl` varchar(255) DEFAULT '' COMMENT 'baseurl of the contact',
`reason` text COMMENT '',
`closeness` tinyint unsigned NOT NULL DEFAULT 99 COMMENT '',
`info` mediumtext COMMENT '',
@ -353,6 +389,8 @@ CREATE TABLE IF NOT EXISTS `gcontact` (
`updated` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_failure` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`archive_date` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`archived` boolean NOT NULL DEFAULT '0' COMMENT '',
`location` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`about` text COMMENT '',
`keywords` text COMMENT 'puplic keywords (interests)',
@ -466,6 +504,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
--
@ -567,16 +619,17 @@ CREATE TABLE IF NOT EXISTS `item` (
INDEX `extid` (`extid`(191)),
INDEX `uid_id` (`uid`,`id`),
INDEX `uid_contactid_id` (`uid`,`contact-id`,`id`),
INDEX `uid_created` (`uid`,`created`),
INDEX `uid_received` (`uid`,`received`),
INDEX `uid_commented` (`uid`,`commented`),
INDEX `uid_unseen_contactid` (`uid`,`unseen`,`contact-id`),
INDEX `uid_network_received` (`uid`,`network`,`received`),
INDEX `uid_network_commented` (`uid`,`network`,`commented`),
INDEX `uid_thrparent` (`uid`,`thr-parent`(190)),
INDEX `uid_parenturi` (`uid`,`parent-uri`(190)),
INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`),
INDEX `authorid_created` (`author-id`,`created`),
INDEX `uid_contactid_received` (`uid`,`contact-id`,`received`),
INDEX `authorid_received` (`author-id`,`received`),
INDEX `ownerid` (`owner-id`),
INDEX `contact-id` (`contact-id`),
INDEX `uid_uri` (`uid`,`uri`(190)),
INDEX `resource-id` (`resource-id`),
INDEX `deleted_changed` (`deleted`,`changed`),
@ -598,7 +651,8 @@ CREATE TABLE IF NOT EXISTS `item-activity` (
`activity` smallint unsigned NOT NULL DEFAULT 0 COMMENT '',
PRIMARY KEY(`id`),
UNIQUE INDEX `uri-hash` (`uri-hash`),
INDEX `uri` (`uri`(191))
INDEX `uri` (`uri`(191)),
INDEX `uri-id` (`uri-id`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Activities for items';
--
@ -626,7 +680,9 @@ CREATE TABLE IF NOT EXISTS `item-content` (
`verb` varchar(100) NOT NULL DEFAULT '' COMMENT 'ActivityStreams verb',
PRIMARY KEY(`id`),
UNIQUE INDEX `uri-plink-hash` (`uri-plink-hash`),
INDEX `uri` (`uri`(191))
INDEX `uri` (`uri`(191)),
INDEX `plink` (`plink`(191)),
INDEX `uri-id` (`uri-id`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Content for all posts';
--
@ -636,6 +692,14 @@ CREATE TABLE IF NOT EXISTS `item-delivery-data` (
`iid` int unsigned NOT NULL COMMENT 'Item id',
`postopts` text COMMENT 'External post connectors add their network name to this comma-separated string to identify that they should be delivered to these networks during delivery',
`inform` mediumtext COMMENT 'Additional receivers of the linked item',
`queue_count` mediumint NOT NULL DEFAULT 0 COMMENT 'Initial number of delivery recipients, used as item.delivery_queue_count',
`queue_done` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries, used as item.delivery_queue_done',
`queue_failed` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of unsuccessful deliveries, used as item.delivery_queue_failed',
`activitypub` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via ActivityPub',
`dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via DFRN',
`legacy_dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via legacy DFRN',
`diaspora` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via Diaspora',
`ostatus` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via OStatus',
PRIMARY KEY(`iid`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Delivery data for items';
@ -810,7 +874,9 @@ CREATE TABLE IF NOT EXISTS `participation` (
`server` varchar(60) NOT NULL COMMENT '',
`cid` int unsigned NOT NULL COMMENT '',
`fid` int unsigned NOT NULL COMMENT '',
PRIMARY KEY(`iid`,`server`)
PRIMARY KEY(`iid`,`server`),
INDEX `cid` (`cid`),
INDEX `fid` (`fid`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Storage for participation messages from Diaspora';
--
@ -866,6 +932,9 @@ CREATE TABLE IF NOT EXISTS `photo` (
`allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups',
`deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id',
`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 '',
PRIMARY KEY(`id`),
INDEX `contactid` (`contact-id`),
INDEX `uid_contactid` (`uid`,`contact-id`),
@ -964,7 +1033,8 @@ CREATE TABLE IF NOT EXISTS `profile` (
`publish` boolean NOT NULL DEFAULT '0' COMMENT 'publish default profile in local directory',
`net-publish` boolean NOT NULL DEFAULT '0' COMMENT 'publish profile in global directory',
PRIMARY KEY(`id`),
INDEX `uid_is-default` (`uid`,`is-default`)
INDEX `uid_is-default` (`uid`,`is-default`),
FULLTEXT INDEX `pub_keywords` (`pub_keywords`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='user profiles data';
--
@ -998,25 +1068,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
--
@ -1084,6 +1135,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)),
@ -1121,15 +1173,15 @@ CREATE TABLE IF NOT EXISTS `thread` (
`bookmark` boolean COMMENT '',
PRIMARY KEY(`iid`),
INDEX `uid_network_commented` (`uid`,`network`,`commented`),
INDEX `uid_network_created` (`uid`,`network`,`created`),
INDEX `uid_network_received` (`uid`,`network`,`received`),
INDEX `uid_contactid_commented` (`uid`,`contact-id`,`commented`),
INDEX `uid_contactid_created` (`uid`,`contact-id`,`created`),
INDEX `uid_contactid_received` (`uid`,`contact-id`,`received`),
INDEX `contactid` (`contact-id`),
INDEX `ownerid` (`owner-id`),
INDEX `authorid` (`author-id`),
INDEX `uid_created` (`uid`,`created`),
INDEX `uid_received` (`uid`,`received`),
INDEX `uid_commented` (`uid`,`commented`),
INDEX `uid_wall_created` (`uid`,`wall`,`created`),
INDEX `uid_wall_received` (`uid`,`wall`,`received`),
INDEX `private_wall_origin_commented` (`private`,`wall`,`origin`,`commented`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Thread related data';
@ -1246,7 +1298,7 @@ CREATE TABLE IF NOT EXISTS `worker-ipc` (
--
CREATE TABLE IF NOT EXISTS `workerqueue` (
`id` int unsigned NOT NULL auto_increment COMMENT 'Auto incremented worker task id',
`parameter` mediumblob COMMENT 'Task command',
`parameter` mediumtext COMMENT 'Task command',
`priority` tinyint unsigned NOT NULL DEFAULT 0 COMMENT 'Task priority',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation date',
`pid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Process id of the worker',
@ -1255,10 +1307,21 @@ 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_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_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';
--
-- TABLE storage
--
CREATE TABLE IF NOT EXISTS `storage` (
`id` int unsigned NOT NULL auto_increment COMMENT 'Auto incremented image data id',
`data` longblob NOT NULL COMMENT 'file data',
PRIMARY KEY(`id`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Data stored by Database storage backend';

View file

@ -46,6 +46,7 @@ General
* i - Only show ignored contacts
* y - Only show archived contacts
* h - Only show hidden contacts
* e - Edit contact groups
../contacts (single contact view)
-------------------------------

204
doc/AddonStorageBackend.md Normal file
View file

@ -0,0 +1,204 @@
Friendica Storage Backend Addon development
===========================================
* [Home](help)
Storage backends can be added via addons.
A storage backend is implemented as a class, and the plugin register the class to make it avaiable to the system.
## The Storage Backend Class
The class must live in `Friendica\Addon\youraddonname` namespace, where `youraddonname` the folder name of your addon.
The class must implement `Friendica\Model\Storage\IStorage` interface. All method in the interface must be implemented:
namespace Friendica\Model\Storage;
```php
interface IStorage
{
public static function get($ref);
public static function put($data, $ref = "");
public static function delete($ref);
public static function getOptions();
public static function saveOptions($data);
}
```
- `get($ref)` returns data pointed by `$ref`
- `put($data, $ref)` saves data in `$data` to position `$ref`, or a new position if `$ref` is empty.
- `delete($ref)` delete data pointed by `$ref`
Each storage backend can have options the admin can set in admin page.
- `getOptions()` returns an array with details about each option to build the interface.
- `saveOptions($data)` get `$data` from admin page, validate it and save it.
The array returned by `getOptions()` is defined as:
[
'option1name' => [ ..info.. ],
'option2name' => [ ..info.. ],
...
]
An empty array can be returned if backend doesn't have any options.
The info array for each option is defined as:
[
'type',
define the field used in form, and the type of data.
one of 'checkbox', 'combobox', 'custom', 'datetime', 'input', 'intcheckbox', 'password', 'radio', 'richtext', 'select', 'select_raw', 'textarea', 'yesno'
'label',
Translatable label of the field. This label will be shown in admin page
value,
Current value of the option
'help text',
Translatable description for the field. Will be shown in admin page
extra data
Optional. Depends on which 'type' this option is:
- 'select': array `[ value => label ]` of choices
- 'intcheckbox': value of input element
- 'select_raw': prebuild html string of `<option >` tags
- 'yesno': array `[ 'label no', 'label yes']`
Each label should be translatable
];
See doxygen documentation of `IStorage` interface for details about each method.
## Register a storage backend class
Each backend must be registered in the system when the plugin is installed, to be aviable.
`Friendica\Core\StorageManager::register($name, $class)` is used to register the backend class.
The `$name` must be univocal and will be shown to admin.
When the plugin is uninstalled, registered backends must be unregistered using
`Friendica\Core\StorageManager::unregister($class)`.
## Example
Here an hypotetical addon which register an unusefull storage backend.
Let's call it `samplestorage`.
This backend will discard all data we try to save and will return always the same image when we ask for some data.
The image returned can be set by the administrator in admin page.
First, the backend class.
The file will be `addon/samplestorage/SampleStorageBackend.php`:
```php
<?php
namespace Friendica\Addon\samplestorage;
use Friendica\Model\Storage\IStorage;
use Friendica\Core\Config;
use Friendica\Core\L10n;
class SampleStorageBackend implements IStorage
{
public static function get($ref)
{
// we return alwais the same image data. Which file we load is defined by
// a config key
$filename = Config::get("storage", "samplestorage", "sample.jpg");
return file_get_contents($filename);
}
public static function put($data, $ref = "")
{
if ($ref === "") {
$ref = "sample";
}
// we don't save $data !
return $ref;
}
public static function delete($ref)
{
// we pretend to delete the data
return true;
}
public static function getOptions()
{
$filename = Config::get("storage", "samplestorage", "sample.jpg");
return [
"filename" => [
"input", // will use a simple text input
L10n::t("The file to return"), // the label
$filename, // the current value
L10n::t("Enter the path to a file"), // the help text
// no extra data for "input" type..
];
}
public static function saveOptions($data)
{
// the keys in $data are the same keys we defined in getOptions()
$newfilename = trim($data["filename"]);
// this function should always validate the data.
// in this example we check if file exists
if (!file_exists($newfilename)) {
// in case of error we return an array with
// ["optionname" => "error message"]
return ["filename" => "The file doesn't exists"];
}
Config::set("storage", "samplestorage", $newfilename);
// no errors, return empty array
return [];
}
}
```
Now the plugin main file. Here we register and unregister the backend class.
The file is `addon/samplestorage/samplestorage.php`
```php
<?php
/**
* Name: Sample Storage Addon
* Description: A sample addon which implements an unusefull storage backend
* Version: 1.0.0
* Author: Alice <https://alice.social/~alice>
*/
use Friendica\Core\StorageManager;
use Friendica\Addon\samplestorage\SampleStorageBackend;
function samplestorage_install()
{
// on addon install, we register our class with name "Sample Storage".
// note: we use `::class` property, which returns full class name as string
// this save us the problem of correctly escape backslashes in class name
StorageManager::register("Sample Storage", SampleStorageBackend::class);
}
function samplestorage_unistall()
{
// when the plugin is uninstalled, we unregister the backend.
StorageManager::unregister("Sample Storage");
}
```

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.
Addon::registerHook($hookname, $file, $function);
\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:
@ -74,7 +97,7 @@ If your addon requires adding a stylesheet on all pages of Friendica, add the fo
```php
function <addon>_install()
{
Addon::registerHook('head', __FILE__, '<addon>_head');
\Friendica\Core\Hook::register('head', __FILE__, '<addon>_head');
...
}
@ -97,7 +120,7 @@ If your addon requires adding a script on all pages of Friendica, add the follow
```php
function <addon>_install()
{
Addon::registerHook('footer', __FILE__, '<addon>_footer');
\Friendica\Core\Hook::register('footer', __FILE__, '<addon>_footer');
...
}
@ -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,11 +183,11 @@ 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 = get_markup_template('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
$output = replace_macros($tpl, array(
$output = Renderer::replaceMacros($tpl, array(
'title' => 'My beautiful addon',
));
```
@ -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,316 +436,343 @@ 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.
### index.php
Addon::callHooks('init_1');
Addon::callHooks('app_menu', $arr);
Addon::callHooks('page_content_top', $a->page['content']);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_post', $_POST);
Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
Addon::callHooks($a->module.'_mod_content', $arr);
Addon::callHooks($a->module.'_mod_aftercontent', $arr);
Addon::callHooks('page_end', $a->page['content']);
Hook::callAll('init_1');
Hook::callAll('app_menu', $arr);
Hook::callAll('page_content_top', $a->page['content']);
Hook::callAll($a->module.'_mod_init', $placeholder);
Hook::callAll($a->module.'_mod_init', $placeholder);
Hook::callAll($a->module.'_mod_post', $_POST);
Hook::callAll($a->module.'_mod_afterpost', $placeholder);
Hook::callAll($a->module.'_mod_content', $arr);
Hook::callAll($a->module.'_mod_aftercontent', $arr);
Hook::callAll('page_end', $a->page['content']);
### include/api.php
Addon::callHooks('logged_in', $a->user);
Addon::callHooks('authenticate', $addon_auth);
Addon::callHooks('logged_in', $a->user);
Hook::callAll('logged_in', $a->user);
Hook::callAll('authenticate', $addon_auth);
Hook::callAll('logged_in', $a->user);
### include/enotify.php
Addon::callHooks('enotify', $h);
Addon::callHooks('enotify_store', $datarray);
Addon::callHooks('enotify_mail', $datarray);
Addon::callHooks('check_item_notification', $notification_data);
Hook::callAll('enotify', $h);
Hook::callAll('enotify_store', $datarray);
Hook::callAll('enotify_mail', $datarray);
Hook::callAll('check_item_notification', $notification_data);
### include/conversation.php
Addon::callHooks('conversation_start', $cb);
Addon::callHooks('render_location', $locate);
Addon::callHooks('display_item', $arr);
Addon::callHooks('display_item', $arr);
Addon::callHooks('item_photo_menu', $args);
Addon::callHooks('jot_tool', $jotplugins);
Hook::callAll('conversation_start', $cb);
Hook::callAll('render_location', $locate);
Hook::callAll('display_item', $arr);
Hook::callAll('display_item', $arr);
Hook::callAll('item_photo_menu', $args);
Hook::callAll('jot_tool', $jotplugins);
### include/text.php
Addon::callHooks('contact_block_end', $arr);
Addon::callHooks('poke_verbs', $arr);
Addon::callHooks('put_item_in_cache', $hook_data);
Addon::callHooks('prepare_body_init', $item);
Addon::callHooks('prepare_body_content_filter', $hook_data);
Addon::callHooks('prepare_body', $hook_data);
Addon::callHooks('prepare_body_final', $hook_data);
Hook::callAll('contact_block_end', $arr);
Hook::callAll('poke_verbs', $arr);
Hook::callAll('put_item_in_cache', $hook_data);
Hook::callAll('prepare_body_init', $item);
Hook::callAll('prepare_body_content_filter', $hook_data);
Hook::callAll('prepare_body', $hook_data);
Hook::callAll('prepare_body_final', $hook_data);
### include/items.php
Addon::callHooks('page_info_data', $data);
Hook::callAll('page_info_data', $data);
### mod/directory.php
Addon::callHooks('directory_item', $arr);
Hook::callAll('directory_item', $arr);
### mod/xrd.php
Addon::callHooks('personal_xrd', $arr);
Hook::callAll('personal_xrd', $arr);
### mod/ping.php
Addon::callHooks('network_ping', $arr);
Hook::callAll('network_ping', $arr);
### mod/parse_url.php
Addon::callHooks("parse_link", $arr);
Hook::callAll("parse_link", $arr);
### mod/manage.php
### src/Module/Delegation.php
Addon::callHooks('home_init', $ret);
Hook::callAll('home_init', $ret);
### mod/acl.php
Addon::callHooks('acl_lookup_end', $results);
Hook::callAll('acl_lookup_end', $results);
### mod/network.php
Addon::callHooks('network_content_init', $arr);
Addon::callHooks('network_tabs', $arr);
Hook::callAll('network_content_init', $arr);
Hook::callAll('network_tabs', $arr);
### mod/friendica.php
Addon::callHooks('about_hook', $o);
Hook::callAll('about_hook', $o);
### mod/subthread.php
Addon::callHooks('post_local_end', $arr);
Hook::callAll('post_local_end', $arr);
### mod/profiles.php
Addon::callHooks('profile_post', $_POST);
Addon::callHooks('profile_edit', $arr);
Hook::callAll('profile_post', $_POST);
Hook::callAll('profile_edit', $arr);
### mod/settings.php
Addon::callHooks('addon_settings_post', $_POST);
Addon::callHooks('connector_settings_post', $_POST);
Addon::callHooks('display_settings_post', $_POST);
Addon::callHooks('settings_post', $_POST);
Addon::callHooks('addon_settings', $settings_addons);
Addon::callHooks('connector_settings', $settings_connectors);
Addon::callHooks('display_settings', $o);
Addon::callHooks('settings_form', $o);
Hook::callAll('addon_settings_post', $_POST);
Hook::callAll('connector_settings_post', $_POST);
Hook::callAll('display_settings_post', $_POST);
Hook::callAll('settings_post', $_POST);
Hook::callAll('addon_settings', $settings_addons);
Hook::callAll('connector_settings', $settings_connectors);
Hook::callAll('display_settings', $o);
Hook::callAll('settings_form', $o);
### mod/photos.php
Addon::callHooks('photo_post_init', $_POST);
Addon::callHooks('photo_post_file', $ret);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', intval($item_id));
Addon::callHooks('photo_upload_form', $ret);
Hook::callAll('photo_post_init', $_POST);
Hook::callAll('photo_post_file', $ret);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', intval($item_id));
Hook::callAll('photo_upload_form', $ret);
### mod/profile.php
Addon::callHooks('profile_advanced', $o);
Hook::callAll('profile_advanced', $o);
### mod/home.php
Addon::callHooks('home_init', $ret);
Addon::callHooks("home_content", $content);
Hook::callAll('home_init', $ret);
Hook::callAll("home_content", $content);
### mod/poke.php
Addon::callHooks('post_local_end', $arr);
Hook::callAll('post_local_end', $arr);
### mod/contacts.php
Addon::callHooks('contact_edit_post', $_POST);
Addon::callHooks('contact_edit', $arr);
Hook::callAll('contact_edit_post', $_POST);
Hook::callAll('contact_edit', $arr);
### mod/tagger.php
Addon::callHooks('post_local_end', $arr);
Hook::callAll('post_local_end', $arr);
### mod/lockview.php
Addon::callHooks('lockview_content', $item);
Hook::callAll('lockview_content', $item);
### mod/uexport.php
Addon::callHooks('uexport_options', $options);
Hook::callAll('uexport_options', $options);
### mod/register.php
Addon::callHooks('register_post', $arr);
Addon::callHooks('register_form', $arr);
Hook::callAll('register_post', $arr);
Hook::callAll('register_form', $arr);
### mod/item.php
Addon::callHooks('post_local_start', $_REQUEST);
Addon::callHooks('post_local', $datarray);
Addon::callHooks('post_local_end', $datarray);
Hook::callAll('post_local_start', $_REQUEST);
Hook::callAll('post_local', $datarray);
Hook::callAll('post_local_end', $datarray);
### mod/editpost.php
Addon::callHooks('jot_tool', $jotplugins);
Hook::callAll('jot_tool', $jotplugins);
### src/Network/FKOAuth1.php
Addon::callHooks('logged_in', $a->user);
Hook::callAll('logged_in', $a->user);
### src/Render/FriendicaSmartyEngine.php
Addon::callHooks("template_vars", $arr);
Hook::callAll("template_vars", $arr);
### src/App.php
Addon::callHooks('load_config');
Addon::callHooks('head');
Addon::callHooks('footer');
Hook::callAll('load_config');
Hook::callAll('head');
Hook::callAll('footer');
Hook::callAll('route_collection');
### src/Model/Item.php
Addon::callHooks('post_local', $item);
Addon::callHooks('post_remote', $item);
Addon::callHooks('post_local_end', $posted_item);
Addon::callHooks('post_remote_end', $posted_item);
Addon::callHooks('tagged', $arr);
Addon::callHooks('post_local_end', $new_item);
Hook::callAll('post_local', $item);
Hook::callAll('post_remote', $item);
Hook::callAll('post_local_end', $posted_item);
Hook::callAll('post_remote_end', $posted_item);
Hook::callAll('tagged', $arr);
Hook::callAll('post_local_end', $new_item);
### src/Model/Contact.php
Addon::callHooks('contact_photo_menu', $args);
Addon::callHooks('follow', $arr);
Hook::callAll('contact_photo_menu', $args);
Hook::callAll('follow', $arr);
### src/Model/Profile.php
Addon::callHooks('profile_sidebar_enter', $profile);
Addon::callHooks('profile_sidebar', $arr);
Addon::callHooks('profile_tabs', $arr);
Addon::callHooks('zrl_init', $arr);
Addon::callHooks('magic_auth_success', $arr);
Hook::callAll('profile_sidebar_enter', $profile);
Hook::callAll('profile_sidebar', $arr);
Hook::callAll('profile_tabs', $arr);
Hook::callAll('zrl_init', $arr);
Hook::callAll('magic_auth_success', $arr);
### src/Model/Event.php
Addon::callHooks('event_updated', $event['id']);
Addon::callHooks("event_created", $event['id']);
Hook::callAll('event_updated', $event['id']);
Hook::callAll("event_created", $event['id']);
### src/Model/User.php
Addon::callHooks('register_account', $uid);
Addon::callHooks('remove_user', $user);
Hook::callAll('register_account', $uid);
Hook::callAll('remove_user', $user);
### src/Content/Text/BBCode.php
Addon::callHooks('bbcode', $text);
Addon::callHooks('bb2diaspora', $text);
Hook::callAll('bbcode', $text);
Hook::callAll('bb2diaspora', $text);
### src/Content/Text/HTML.php
Addon::callHooks('html2bbcode', $message);
Hook::callAll('html2bbcode', $message);
### src/Content/Smilies.php
Addon::callHooks('smilie', $params);
Hook::callAll('smilie', $params);
### src/Content/Feature.php
Addon::callHooks('isEnabled', $arr);
Addon::callHooks('get', $arr);
Hook::callAll('isEnabled', $arr);
Hook::callAll('get', $arr);
### src/Content/ContactSelector.php
Addon::callHooks('network_to_name', $nets);
Addon::callHooks('gender_selector', $select);
Addon::callHooks('sexpref_selector', $select);
Addon::callHooks('marital_selector', $select);
Hook::callAll('network_to_name', $nets);
Hook::callAll('gender_selector', $select);
Hook::callAll('sexpref_selector', $select);
Hook::callAll('marital_selector', $select);
### src/Content/OEmbed.php
Addon::callHooks('oembed_fetch_url', $embedurl, $j);
Hook::callAll('oembed_fetch_url', $embedurl, $j);
### src/Content/Nav.php
Addon::callHooks('page_header', $a->page['nav']);
Addon::callHooks('nav_info', $nav);
Hook::callAll('page_header', $a->page['nav']);
Hook::callAll('nav_info', $nav);
### src/Worker/Directory.php
Addon::callHooks('globaldir_update', $arr);
Hook::callAll('globaldir_update', $arr);
### src/Worker/Notifier.php
Addon::callHooks('notifier_end', $target_item);
### src/Worker/Queue.php
Addon::callHooks('queue_predeliver', $r);
Addon::callHooks('queue_deliver', $params);
Hook::callAll('notifier_end', $target_item);
### src/Module/Login.php
Addon::callHooks('authenticate', $addon_auth);
Addon::callHooks('login_hook', $o);
Hook::callAll('authenticate', $addon_auth);
Hook::callAll('login_hook', $o);
### src/Module/Logout.php
Addon::callHooks("logging_out");
Hook::callAll("logging_out");
### src/Object/Post.php
Addon::callHooks('render_location', $locate);
Addon::callHooks('display_item', $arr);
Hook::callAll('render_location', $locate);
Hook::callAll('display_item', $arr);
### src/Core/ACL.php
Addon::callHooks('contact_select_options', $x);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks('jot_networks', $jotnets);
Hook::callAll('contact_select_options', $x);
Hook::callAll($a->module.'_pre_'.$selname, $arr);
Hook::callAll($a->module.'_post_'.$selname, $o);
Hook::callAll($a->module.'_pre_'.$selname, $arr);
Hook::callAll($a->module.'_post_'.$selname, $o);
Hook::callAll('jot_networks', $jotnets);
### src/Core/Authentication.php
Addon::callHooks('logged_in', $a->user);
Hook::callAll('logged_in', $a->user);
### src/Core/Hook.php
self::callSingle(self::getApp(), 'hook_fork', $fork_hook, $hookdata);
### src/Core/Worker.php
Addon::callHooks("proc_run", $arr);
Hook::callAll("proc_run", $arr);
### src/Util/Emailer.php
Addon::callHooks('emailer_send_prepare', $params);
Addon::callHooks("emailer_send", $hookdata);
Hook::callAll('emailer_send_prepare', $params);
Hook::callAll("emailer_send", $hookdata);
### src/Util/Map.php
Addon::callHooks('generate_map', $arr);
Addon::callHooks('generate_named_map', $arr);
Addon::callHooks('Map::getCoordinates', $arr);
Hook::callAll('generate_map', $arr);
Hook::callAll('generate_named_map', $arr);
Hook::callAll('Map::getCoordinates', $arr);
### src/Util/Network.php
Addon::callHooks('avatar_lookup', $avatar);
Hook::callAll('avatar_lookup', $avatar);
### src/Util/ParseUrl.php
Addon::callHooks("getsiteinfo", $siteinfo);
Hook::callAll("getsiteinfo", $siteinfo);
### src/Protocol/DFRN.php
Addon::callHooks('atom_feed_end', $atom);
Addon::callHooks('atom_feed_end', $atom);
Hook::callAll('atom_feed_end', $atom);
Hook::callAll('atom_feed_end', $atom);
### view/js/main.js

View file

@ -68,6 +68,10 @@ table.bbcodes > * > tr > th {
<td>[img]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]</td>
<td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" alt="Immagine/foto"></td>
</tr>
<tr>
<td>[img=https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg]The Friendica Logo[/img]</td>
<td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" alt="The Friendica Logo"></td>
</tr>
<tr>
<td>[img=64x32]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]<br>
<br>Note: provided height is simply discarded.</td>
@ -598,6 +602,9 @@ While taking pictures in the woods I had a really strange encounter...</td>
The [abstract] element is not working with connectors where we post HTML directly, like Tumblr, Wordpress or Pump.io.
For the native connections--that is to e.g. Friendica, Hubzilla, Diaspora or GNU Social--the full posting is used and the contacts instance will display the posting as desired.
For postings that are delivered via ActivityPub, the text from the abstract is placed in the summary field.
On Mastodon this field is used for the content warning.
## Special
<table class="bbcodes">

View file

@ -1,55 +1,63 @@
Config values that can only be set in config/local.ini.php
Config values that can only be set in config/local.config.php
==========================================================
* [Home](help)
Friendica's configuration is done in two places: in INI configuration files and in the `config` database table.
Friendica's configuration is done in two places: in PHP array configuration files and in the `config` database table.
Database config values overwrite the same file config values.
## File configuration
WARNING: some characters `?{}|&~![()^"` should not be used in the keys or values. If one of those character is required put the value between double quotes (eg. password = "let&me&in")
The configuration format for file configuration is an INI string returned from a PHP file.
This prevents your webserver from displaying your private configuration it interprets the configuration files and displays nothing.
The configuration format for file configuration is an array returned from a PHP file.
This prevents your webserver from displaying your private configuration. It interprets the configuration files and displays nothing.
A typical configuration file looks like this:
```php
<?php return <<<INI
<?php
; Comment line
/*
* Comment block
*/
[section1]
key = value
empty_key =
[section2]
array[] = value0
array[] = value1
array[] = value2
INI;
// Keep this line
return [
'section1' => [
// Comment line
'key' => 'value',
],
'section2' => [
'array' => ['value0', 'value1', 'value2'],
],
];
```
### Configuration location
The `config` directory holds key configuration files:
The `config` directory holds key configuration files and can have different config files.
All of them have to end with `.config.php` and must not include `-sample` in their name.
- `config.ini.php` holds the default values for all the configuration keys that can only be set in `local.ini.php`.
- `settings.ini.php` holds the default values for some configuration keys that are set through the admin settings page.
- `local.ini.php` holds the current node custom configuration.
- `addon.ini.php` is optional and holds the custom configuration for specific addons.
Some examples of common known configuration files:
- `local.config.php` holds the current node custom configuration.
- `addon.config.php` is optional and holds the custom configuration for specific addons.
Addons can define their own default configuration values in `addon/[addon]/config/[addon].ini.php` which is loaded when the addon is activated.
Addons can define their own default configuration values in `addon/[addon]/config/[addon].config.php` which is loaded when the addon is activated.
#### Migrating from .htconfig.php to config/local.ini.php
### Static Configuration location
The `static` directory holds the codebase default configurations files.
They must not be changed by users, because they can get changed from release to release.
Currently, the following configurations are included:
- `defaults.config.php` holds the default values for all the configuration keys that can only be set in `local.config.php`.
- `settings.config.php` holds the default values for some configuration keys that are set through the admin settings page.
#### Migrating from .htconfig.php to config/local.config.php
The legacy `.htconfig.php` configuration file is still supported, but is deprecated and will be removed in a subsequent Friendica release.
The migration is pretty straightforward:
If you had any addon-specific configuration in your `.htconfig.php`, just copy `config/addon-sample.ini.php` to `config/addon.ini.php` and move your configuration values.
Afterwards, copy `config/local-sample.ini.php` to `config/local.ini.php`, move the remaining configuration values to it according to the following conversion chart, then rename your `.htconfig.php` to check your node is working as expected before deleting it.
If you had any addon-specific configuration in your `.htconfig.php`, just copy `config/addon-sample.config.php` to `config/addon.config.php` and move your configuration values.
Afterwards, copy `config/local-sample.config.php` to `config/local.config.php`, move the remaining configuration values to it according to the following conversion chart, then rename your `.htconfig.php` to check your node is working as expected before deleting it.
<style>
table.config {
@ -81,7 +89,7 @@ table.config > * > tr > th {
<thead>
<tr>
<th>.htconfig.php</th>
<th>config/local.ini.php</th>
<th>config/local.config.php</th>
</tr>
</thead>
<tbody>
@ -94,25 +102,25 @@ $db_data = 'mysqldatabasename';
$a->config["system"]["db_charset"] = 'utf8mb4';
</pre></td>
<td><pre>
[database]
hostname = localhost
username = mysqlusername
password = mysqlpassword
database = mysqldatabasename
charset = utf8mb4
'database' => [
'hostname' => 'localhost',
'username' => 'mysqlusername',
'password' => 'mysqlpassword',
'database' => 'database',
'charset' => 'utf8mb4',
],
</pre></td>
</tr>
<tr>
<td><pre>
$a->config["section"]["key"] = "value";
</pre></td>
<td><pre>
[section]
key = value
'section' => [
'key' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
$a->config["section"]["key"] = array(
@ -122,74 +130,157 @@ $a->config["section"]["key"] = array(
);
</pre></td>
<td><pre>
[section]
key[] = value1
key[] = value2
key[] = value3
'section' => [
'key' => ['value1', 'value2', 'value3'],
],
</pre></td>
</tr>
<tr>
<td><pre>
$a->config["key"] = "value";
</pre></td>
<td><pre>
[config]
key = value
'config' => [
'key' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
$a->config['register_policy'] = REGISTER_CLOSED;
</pre></td>
<td><pre>
'config' => [
'register_policy' => \Friendica\Module\Register::CLOSED,
],
</pre></td>
</tr>
<tr>
<td><pre>
$a->path = "value";
</pre></td>
<td><pre>
[system]
urlpath = value
'system' => [
'urlpath' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
$default_timezone = "value";
</pre></td>
<td><pre>
[system]
default_timezone = value
'system' => [
'default_timezone' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
$pidfile = "value";
</pre></td>
<td><pre>
[system]
pidfile = value
'system' => [
'pidfile' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
$lang = "value";
</pre></td>
<td><pre>
[system]
language = value
'system' => [
'language' => 'value',
],
</pre></td>
</tr>
</tbody>
</table>
#### Migrating from config/local.ini.php to config/local.config.php
The legacy `config/local.ini.php` configuration file is still supported, but is deprecated and will be removed in a subsequent Friendica release.
The migration is pretty straightforward:
If you had any addon-specific configuration in your `config/addon.ini.php`, just copy `config/addon-sample.config.php` to `config/addon.config.php` and move your configuration values.
Afterwards, copy `config/local-sample.config.php` to `config/local.config.php`, move the remaining configuration values to it according to the following conversion chart, then rename your `config/local.ini.php` file to check your node is working as expected before deleting it.
<table class="config">
<thead>
<tr>
<th>config/local.ini.php</th>
<th>config/local.config.php</th>
</tr>
</thead>
<tbody>
<tr>
<td><pre>
[database]
hostname = localhost
username = mysqlusername
password = mysqlpassword
database = mysqldatabasename
charset = utf8mb4
</pre></td>
<td><pre>
'database' => [
'hostname' => 'localhost',
'username' => 'mysqlusername',
'password' => 'mysqlpassword',
'database' => 'database',
'charset' => 'utf8mb4',
],
</pre></td>
</tr>
<tr>
<td><pre>
[section]
key = value
</pre></td>
<td><pre>
'section' => [
'key' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
[config]
register_policty = REGISTER_CLOSED
</pre></td>
<td><pre>
'config' => [
'register_policy' => \Friendica\Module\Register::CLOSED,
],
</pre></td>
</tr>
<tr>
<td><pre>
[section]
key[] = value1
key[] = value2
key[] = value3
</pre></td>
<td><pre>
'section' => [
'key' => ['value1', 'value2', 'value3'],
],
</pre></td>
</tr>
</tbody>
</table>
### Database Settings
The configuration variables database.hostname, database.username, database.password, database.database and database.charset are holding your credentials for the database connection.
If you need to specify a port to access the database, you can do so by appending ":portnumber" to the database.hostname variable.
[database]
hostname = your.mysqlhost.com:123456
'database' => [
'hostname' => 'your.mysqlhost.com:123456',
]
If all of the following environment variables are set, Friendica will use them instead of the previously configured variables for the db:
@ -199,7 +290,7 @@ If all of the following environment variables are set, Friendica will use them i
MYSQL_PASSWORD
MYSQL_DATABASE
## Config values that can only be set in config/local.ini.php
## Config values that can only be set in config/local.config.php
There are some config values that haven't found their way into the administration page.
This has several reasons.
@ -210,22 +301,26 @@ Or it is for testing purposes only.
**Attention:** Please be warned that you shouldn't use one of these values without the knowledge what it could trigger.
Especially don't do that with undocumented values.
These configurations keys and their default value are listed in `config/config.ini.php` and should be ovewritten in `config/local.ini.php`.
These configurations keys and their default value are listed in `static/defaults.config.php` and should be overwritten in `config/local.config.php`.
## Administrator Options
Enabling the admin panel for an account, and thus making the account holder admin of the node, is done by setting the variable
[config]
admin_email = someone@example.com
'config' => [
'admin_email' => 'someone@example.com',
]
Where you have to match the email address used for the account with the one you enter to the config/local.ini.php file.
Where you have to match the email address used for the account with the one you enter to the `config/local.config.php` file.
If more then one account should be able to access the admin panel, separate the email addresses with a comma.
[config]
admin_email = someone@example.com,someoneelse@example.com
'config' => [
'admin_email' => 'someone@example.com,someoneelse@example.com',
]
If you want to have a more personalized closing line for the notification emails you can set a variable for the admin_name.
If you want to have a more personalized closing line for the notification emails you can set a variable for the `admin_name`.
[config]
admin_name = Marvin
'config' => [
'admin_name' => 'Marvin',
]

View file

@ -111,10 +111,10 @@ If the command-line tools `diff` and `patch` are unavailabe for you, `phpcbf` ca
### Code documentation
If you are interested in having the documentation of the Friendica code outside of the code files, you can use [Doxygen](http://doxygen.org) to generate it.
The configuration file for Doxygen is located in the `util` directory of the project sources.
The configuration file for Doxygen is located in the base directory of the project sources.
Run
$> doxygen util/Doxyfile
$> doxygen Doxyfile
to generate the files which will be located in the `doc/html` subdirectory in the Friendica directory.
You can browse these files with any browser.

View file

@ -8,6 +8,7 @@ User
* **[Why do I getting warnings about certificates?](help/FAQ#ssl)**
* **[How can I upload images, files, links, videos and sound files to posts?](help/FAQ#upload)**
* **[Is it possible to have different avatars per profile?](help/FAQ#avatars)**
* **[How can I view Friendica in a certain language?](help/FAQ#language)**
* **[What is the difference between blocked|ignored|archived|hidden contacts?](help/FAQ#contacts)**
* **[What happens when an account is removed? Is it truly deleted?](help/FAQ#removed)**
* **[Can I subscribe to a hashtag?](help/FAQ#hashtag)**
@ -64,7 +65,7 @@ However, instead of a direct upload you have to use one of the following methods
Friendica uses HTML5 for embedding content.
Therefore, the supported files are dependent on your browser and operating system.
Some supported filetypes are WebM, MP4, MP3 and OGG.
Some supported file types are WebM, MP4, MP3 and OGG.
See Wikipedia for more of them ([video](http://en.wikipedia.org/wiki/HTML5_video), [audio](http://en.wikipedia.org/wiki/HTML5_audio)).
<a name="avatars"></a>
@ -75,6 +76,33 @@ On your Edit/Manage Profiles page, you will find a "change profile photo" link.
Clicking this will take you to a page where you can upload a photograph and select which profile it will be associated with.
To avoid privacy leakage, we only display the photograph associated with your default profile as the avatar in your posts.
<a name="language"></a>
### How can I view Friendica in a certain language?
You can do this by adding the `lang` parameter to the url in your url bar.
The data in the parameter is a [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) code.
A question mark is required for the separation between url and parameters.
Example:
https://social.example.com/profile/example
in German:
https://social.example.com/profile/example?lang=de.
If the question mark is already in the url you need to do it using a ampersand.
Example:
https://social.example.com/profile/example?tab=profile
in German:
https://social.example.com/profile/example?tab=profile&lang=de.
When a certain language is forced, the language remains until session is closed.
<a name="contacts"></a>
### What is the difference between blocked|ignored|archived|hidden contacts?
@ -98,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?
@ -140,11 +167,13 @@ Example: Friendica Support
<a name="clients"></a>
### Are there any clients for friendica I can use?
Friendica is using a [Twitter/GNU Social compatible API](help/api), which means you can use any Twitter/GNU Social client for your plattform as long as you can change the API path in its settings.
Friendica is using a [Twitter/GNU Social compatible API](help/api), which means you can use any Twitter/GNU Social client for your platform as long as you can change the API path in its settings.
Here is a list of known working clients:
* Android
* [Friendiqa](https://github.com/lubuwest/friendiqa) (available in Google Playstore or from a binary repository you can add to [F-Droid](https://freunde.ma-nic.de/display/3e98eba8185a13c5bdbf3d1539646854))
* [Friendiqa](https://git.friendi.ca/lubuwest/Friendiqa) (available in Google Playstore or from a binary repository you can add to [F-Droid](https://freunde.ma-nic.de/display/3e98eba8185a13c5bdbf3d1539646854))
* [Fedilab](https://gitlab.com/tom79/mastalab) (available in F-Droid and Google stores)
* [DiCa](https://dica.mixi.cool/)
* AndStatus
* Twidere
* Mustard and Mustard-Mod
@ -187,7 +216,7 @@ No, this function is no longer supported as of Friendica 3.3 onwards.
<a name="sources"></a>
### Where can I find the source code of friendica, addons and themes?
You can find the main respository [here](https://github.com/friendica/friendica).
You can find the main repository [here](https://github.com/friendica/friendica).
There you will always find the current stable version of friendica.
Addons are listed at [this page](https://github.com/friendica/friendica-addons).
@ -197,14 +226,14 @@ If you are searching for new themes, you can find them at [Friendica-Themes.com]
<a name="adminaccount1"></a>
### I've changed my email address now the admin panel is gone?
Have a look into your <tt>config/local.ini.php</tt> and fix your email address there.
Have a look into your <tt>config/local.config.php</tt> and fix your email address there.
<a name="adminaccount2"></a>
### Can there be more then one admin for a node?
Yes.
You just have to list more then one email address in the
<tt>config/local.ini.php</tt> file.
<tt>config/local.config.php</tt> file.
The listed emails need to be separated by a comma.
<a name="dbupdate">

View file

@ -40,7 +40,7 @@ You are not required to do this, but the alternative is to log out and log back
This could get cumbersome if you manage several different forums/identities.
You may also appoint a delegate to manage your forum.
Do this by visiting the [Delegation Setup Page](delegate).
Do this by visiting the [Delegation Setup Page](settings/delegation).
This will provide you with a list of contacts on this system under "Potential Delegates".
Selecting one or more persons will give them access to manage your forum.
They will be able to edit contacts, profiles, and all content for this account/page.

View file

@ -32,7 +32,7 @@ Friendica Documentation and Resources
* [Installing Connectors (Twitter/GNU Social)](help/Installing-Connectors)
* [Install an ejabberd server (XMPP chat) with synchronized credentials](help/install-ejabberd)
* [Using SSL with Friendica](help/SSL)
* [Config values that can only be set in config/local.ini.php](help/Config)
* [Config values that can only be set in config/local.config.php](help/Config)
* [Improve Performance](help/Improve-Performance)
* [Administration Tools](help/tools)
@ -47,6 +47,7 @@ Friendica Documentation and Resources
* [Addon Development](help/Addons)
* [Theme Development](help/themes)
* [Smarty 3 Templates](help/smarty3-templates)
* [Storage backend addon](help/AddonStorageBackend)
* How To
* [Translate Friendica](help/translations)
* [Use Composer](help/Composer)
@ -56,7 +57,7 @@ Friendica Documentation and Resources
* [Twitter/GNU Social API Functions](help/api)
* [Code (Doxygen generated - sets cookies)](doc/html/)
* [Protocol Documentation](help/Protocol)
* [Database schema documantation](help/database)
* [Database schema documentation](help/database)
* [Class Autoloading](help/autoloader)
**External Resources**

View file

@ -1,44 +1,55 @@
Friendica Installation
===============
# Friendica Installation
We've tried very hard to ensure that Friendica will run on commodity hosting platforms - such as those used to host Wordpress blogs and Drupal websites.
We offer a manual and an automatic installation.
But be aware that Friendica is more than a simple web application.
It is a complex communications system which more closely resembles an email server than a web server.
For reliability and performance, messages are delivered in the background and are queued for later delivery when sites are down.
This kind of functionality requires a bit more of the host system than the typical blog.
Not every PHP/MySQL hosting provider will be able to support Friendica.
Many will.
But **please** review the requirements and confirm these with your hosting provider prior to installation.
Also if you encounter installation issues, please let us know via the [helper](http://forum.friendi.ca/profile/helpers) or the [developer](https://forum.friendi.ca/profile/developers) forum or [file an issue](https://github.com/friendica/friendica/issues).
But **please** review the [requirements](#1_2_1) and confirm these with your hosting provider prior to installation.
## Support
If you encounter installation issues, please let us know via the [helper](http://forum.friendi.ca/profile/helpers) or the [developer](https://forum.friendi.ca/profile/developers) forum or [file an issue](https://github.com/friendica/friendica/issues).
Please be as clear as you can about your operating environment and provide as much detail as possible about any error messages you may see, so that we can prevent it from happening in the future.
Due to the large variety of operating systems and PHP platforms in existence we may have only limited ability to debug your PHP installation or acquire any missing modules - but we will do our best to solve any general code issues.
If you do not have a Friendica account yet, you can register a temporary one at [tryfriendica.de](https://tryfriendica.de) and join the forums mentioned above from there.
The account will expire after 7 days, but you can ask the server admin to keep your account longer, should the problem not be resolved after that.
Before you begin: Choose a domain name or subdomain name for your server.
Put some thought into this. Changing it after installation is currently not supported.
Things will break, and some of your friends may have difficulty communicating with you.
We plan to address this limitation in a future release.
## Prerequisites
* Choose a domain name or subdomain name for your server. Put some thought into this. While changing it after installation is supported, things still might break.
* Setup HTTPS on your domain.
Requirements
---
### 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 equivalant 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.
* MySQL 5.6+ or an equivalent alternative for MySQL (MariaDB, Percona Server etc.)
* ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows)
* installation into a top-level domain or sub-domain (without a directory/path component in the URL) is RECOMMENDED. Directory paths will not be as convenient to use and have not been thoroughly tested. This is REQUIRED if you wish to communicate with the Diaspora network.
Installation procedure
---
**If your hosting provider doesn't allow Unix shell access, you might have trouble getting everything to work.**
For alternative server configurations (such as Nginx server and MariaDB database engine), refer to the [Friendica wiki](https://github.com/friendica/friendica/wiki).
### Optional
* PHP ImageMagick extension (php-imagick) for animated GIF support.
* [Composer](https://getcomposer.org/) for a git install
## Installation procedure
### Alternative Installation Methods
@ -46,20 +57,27 @@ This guide will walk you through the manual installation process of Friendica.
If this is nothing for you, you might be interested in
* the [Friendica Docker image](https://github.com/friendica/docker) or
* how [install Friendica with YunoHost](https://github.com/YunoHost-Apps/friendica_ynh).
* how to [install Friendica with YunoHost](https://github.com/YunoHost-Apps/friendica_ynh).
### Get Friendica
Unpack the Friendica files into the root of your web server document area.
If you are able to do so, we recommend using git to clone the source repository rather than to use a packaged tar or zip file.
If you copy the directory tree to your webserver, make sure that you also copy
`.htaccess-dist` - as "dot" files are often hidden and aren't normally copied.
**OR**
Clone the [friendica/friendica GitHub repository](https://github.com/friendica/friendica) and import dependencies.
This makes the software much easier to update.
The Linux commands to clone the repository into a directory "mywebsite" would be
git clone https://github.com/friendica/friendica.git -b master mywebsite
cd mywebsite
bin/composer.phar install
bin/composer.phar install --no-dev
Make sure the folder *view/smarty3* exists and is writable by the webserver user, in this case `www-data`
Make sure the folder *view/smarty3* exists and is writable by the webserver user, in this case *www-data*
mkdir view/smarty3
chown www-data:www-data view/smarty3
@ -73,16 +91,15 @@ Clone the addon repository (separately):
git clone https://github.com/friendica/friendica-addons.git -b master addon
If you copy the directory tree to your webserver, make sure that you also copy .htaccess - as "dot" files are often hidden and aren't normally copied.
If you want to use the development version of Friendica you can switch to the devel branch in the repository by running
If you want to use the development version of Friendica you can switch to the develop branch in the repository by running
git checkout develop
bin/composer.phar install
cd addon
git checkout develop
please be aware that the develop branch may break your Friendica node at any time.
**Be aware that the develop branch is unstable and may break your Friendica node at any time.**
You should have a recent backup before updating.
If you encounter a bug, please let us know.
### Create a database
@ -91,15 +108,9 @@ Create an empty database and note the access details (hostname, username, passwo
Friendica needs the permission to create and delete fields and tables in its own database.
With newer releases of MySQL (5.7.17 or newer), you might need to set the sql_mode to '' (blank).
Use this setting when the installer is unable to create all the needed tables due to a timestamp format problem.
In this case find the [mysqld] section in your my.cnf file and add the line :
Please check the [troubleshooting](#1_6) section if running on MySQL 5.7.17 or newer.
sql_mode = ''
Restart mysql and you should be fine.
### Option A: Run the manual installer
### Option A: Run the installer
Point your web browser to the new site and follow the instructions.
Please note any error messages and correct these before continuing.
@ -108,19 +119,19 @@ If you need to specify a port for the connection to the database, you can do so
*If* the manual installation fails for any reason, check the following:
* Does "config/local.ini.php" exist? If not, edit config/local-sample.ini.php and change the system settings.
* Rename to `config/local.ini.php`.
* Is the database is populated? If not, import the contents of `database.sql` with phpmyadmin or the mysql command line.
* Does `config/local.config.php` exist? If not, edit `config/local-sample.config.php` and change the system settings.
* Rename to `config/local.config.php`.
* Is the database populated? If not, import the contents of `database.sql` with phpmyadmin or the mysql command line.
At this point visit your website again, and register your personal account.
Registration errors should all be recoverable automatically.
If you get any *critical* failure at this point, it generally indicates the database was not installed correctly.
You might wish to move/rename `config/local.ini.php` to another name and empty (called 'dropping') the database tables, so that you can start fresh.
You might wish to move/rename `config/local.config.php` to another name and empty (called 'dropping') the database tables, so that you can start fresh.
### Option B: Run the automatic install script
You have the following options to automatically install Friendica:
- creating a prepared config file (f.e. `prepared.ini.php`)
- creating a prepared config file (f.e. `prepared.config.php`)
- using environment variables (f.e. `MYSQL_HOST`)
- using options (f.e. `--dbhost <host>`)
@ -136,17 +147,17 @@ If you wish to include all optional checks, use `-a` like this statement:
*If* the automatic installation fails for any reason, check the following:
* Does `config/local.ini.php` already exist? If yes, the automatic installation won't start
* Are the options in the `config/local.ini.php` correct? If not, edit them directly.
* Does `config/local.config.php` already exist? If yes, the automatic installation won't start
* Are the options in the `config/local.config.php` correct? If not, edit them directly.
* Is the empty MySQL-database created? If not, create it.
#### B.1: Config file
You can use a prepared config file like [local-sample.ini.php](config/local-sample.ini.php).
You can use a prepared config file like [local-sample.config.php](/config/local-sample.config.php).
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall -f <prepared.ini.php>
bin/console autoinstall -f <prepared.config.php>
#### B.2: Environment variables
@ -158,7 +169,7 @@ You can use the options during installation too and skip some of the environment
**Database credentials**
if you don't use the option `--savedb` during installation, the DB credentials will **not** be saved in the `config/local.ini.php`.
if you don't use the option `--savedb` during installation, the DB credentials will **not** be saved in the `config/local.config.php`.
- `MYSQL_HOST` The host of the mysql/mariadb database
- `MYSQL_PORT` The port of the mysql/mariadb database
@ -170,13 +181,13 @@ if you don't use the option `--savedb` during installation, the DB credentials w
**Friendica settings**
This variables wont be used at normal Friendica runtime.
Instead, they get saved into `config/local.ini.php`.
Instead, they get saved into `config/local.config.php`.
- `FRIENDICA_URL_PATH` The URL path of Friendica (f.e. '/friendica')
- `FRIENDICA_PHP_PATH` The path of the PHP binary
- `FRIENDICA_ADMIN_MAIL` The admin email address of Friendica (this email will be used for admin access)
- `FRIENDICA_TZ` The timezone of Friendica
- `FRIENDICA_LANG` The langauge of Friendica
- `FRIENDICA_LANG` The language of Friendica
Navigate to the main Friendica directory and execute the following command:
@ -184,7 +195,7 @@ Navigate to the main Friendica directory and execute the following command:
#### B.3: Execution options
All options will be saved in the `config/local.ini.php` and are overruling the associated environment variables.
All options will be saved in the `config/local.config.php` and are overruling the associated environment variables.
- `-H|--dbhost <host>` The host of the mysql/mariadb database (env `MYSQL_HOST`)
- `-p|--dbport <port>` The port of the mysql/mariadb database (env `MYSQL_PORT`)
@ -203,18 +214,18 @@ Navigate to the main Friendica directory and execute the following command:
### Prepare .htaccess file
Copy .htaccess-dist to .htaccess (be careful under Windows) to have working mod-rewrite again. If you have installed Friendica into a sub directory, like /friendica/ set this path in RewriteBase accordingly.
Copy `.htaccess-dist` to `.htaccess` (be careful under Windows) to have working mod-rewrite again. If you have installed Friendica into a sub directory, like */friendica/* set this path in `RewriteBase` accordingly.
Example:
cp .htacces-dist .htaccess
*Note*: Do **not** rename the .htaccess-dist file as it is tracked by GIT and renaming will cause a dirty working directory.
*Note*: Do **not** rename the `.htaccess-dist` file as it is tracked by GIT and renaming will cause a dirty working directory.
### Verify the "host-meta" page is working
Friendica should respond automatically to important addresses under the /.well-known/ rewrite path.
One critical URL would look like, for example, https://example.com/.well-known/host-meta
Friendica should respond automatically to important addresses under the */.well-known/* rewrite path.
One critical URL would look like, for example: https://example.com/.well-known/host-meta
It must be visible to the public and must respond with an XML file that is automatically customized to your site.
If that URL is not working, it is possible that some other software is using the /.well-known/ path.
@ -222,13 +233,23 @@ Other symptoms may include an error message in the Admin settings that says "hos
This is a severe configuration issue that prevents server to server communication."
Another common error related to host-meta is the "Invalid profile URL."
Check for a .well-known directory that did not come with Friendica.
Check for a `.well-known` directory that did not come with Friendica.
The preferred configuration is to remove the directory, however this is not always possible.
If there is any /.well-known/.htaccess file, it could interfere with this Friendica core requirement.
You should remove any RewriteRules from that file, or remove that whole file if appropriate.
It may be necessary to chmod the /.well-known/.htaccess file if you were not given write permissions by default.
### Set up the worker
## Register the admin account
At this point visit your website again, and register your personal account with the same email as in the `config.admin_email` config value.
Registration errors should all be recoverable automatically.
If you get any *critical* failure at this point, it generally indicates the database was not installed correctly.
You might wish to delete/rename `config/local.config.php` to another name and drop all the database tables so that you can start fresh.
## Post Install Configuration
### (REQUIRED) Background tasks
Set up a cron job or scheduled task to run the worker once every 5-10 minutes in order to perform background processing.
Example:
@ -237,6 +258,8 @@ Example:
Change "/base/directory", and "/path/to/php" as appropriate for your situation.
#### cron job for worker
If you are using a Linux server, run "crontab -e" and add a line like the
one shown, substituting for your unique paths and settings:
@ -248,13 +271,182 @@ Friendica will not work correctly if you cannot perform this step.
If it is not possible to set up a cron job then please activate the "frontend worker" in the administration interface.
Once you have installed Friendica and created an admin account as part of the process, you can access the admin panel of your installation and do most of the server wide configuration from there
Once you have installed Friendica and created an admin account as part of the process, you can access the admin panel of your installation and do most of the server wide configuration from there.
### Set up a backup plan
#### worker alternative: daemon
Otherwise, youll need to use the command line on your remote server and start the Friendica daemon (background task) using the following command:
cd /path/to/friendica; php bin/daemon.php start
Once started, you can check the daemon status using the following command:
cd /path/to/friendica; php bin/daemon.php status
After a server restart or any other failure, the daemon needs to be restarted.
This could be achieved by a cronjob.
### (RECOMMENDED) Logging & Log Rotation
At this point it is recommended that you set up logging and logrotation.
To do so please visit [Settings](help/Settings) and search the 'Logs' section for more information.
### (RECOMMENDED) Set up a backup plan
Bad things will happen.
Let there be a hardware failure, a corrupted database or whatever you can think of.
So once the installation of your Friendica node is done, you should make yourself a backup plan.
The most important file is the `config/local.ini.php` file.
The most important file is the `config/local.config.php` file.
As it stores all your data, you should also have a recent dump of your Friendica database at hand, should you have to recover your node.
### (OPTIONAL) Reverse-proxying and HTTPS
Friendica looks for some well-known HTTP headers indicating a reverse-proxy
terminating an HTTPS connection.
While the standard from RFC 7239 specifies the use of the `Forwarded` header.
Forwarded: for=192.0.2.1; proto=https; by=192.0.2.2
Friendica also supports a number on non-standard headers in common use.
X-Forwarded-Proto: https
Front-End-Https: on
X-Forwarded-Ssl: on
It is however preferable to use the standard approach if configuring a new server.
## Troubleshooting
### "System is currently unavailable. Please try again later"
Check your database settings.
It usually means your database could not be opened or accessed.
If the database resides on the same machine, check that the database server name is "localhost".
### 500 Internal Error
This could be the result of one of our Apache directives not being supported by your version of Apache. Examine your apache server logs.
You might remove the line "Options -Indexes" from the .htaccess file if you are using a Windows server as this has been known to cause problems.
Also check your file permissions. Your website and all contents must generally be world-readable.
It is likely that your web server reported the source of the problem in its error log files.
Please review these system error logs to determine what caused the problem.
Often this will need to be resolved with your hosting provider or (if self-hosted) your web server configuration.
### 400 and 4xx "File not found" errors
First check your file permissions.
Your website and all contents must generally be world-readable.
Ensure that mod-rewite is installed and working, and that your `.htaccess` file
is being used. To verify the latter, create a file `test.out` containing the
word "test" in the top directory of Friendica, make it world readable and point
your web browser to
http://yoursitenamehere.com/test.out
This file should be blocked. You should get a permission denied message.
If you see the word "test" your Apache configuration is not allowing your
`.htaccess` file to be used (there are rules in this file to block access to any
file with .out at the end, as these are typically used for system logs).
Make certain the `.htaccess` file exists and is readable by everybody, then look
for the existence of "AllowOverride None" in the Apache server configuration for your site.
This will need to be changed to "AllowOverride All".
If you do not see the word "test", your `.htaccess` is working, but it is likely
that mod-rewrite is not installed in your web server or is not working.
On most Linux flavors:
% a2enmod rewrite
% /etc/init.d/apache2 restart
Consult your hosting provider, experts on your particular Linux distribution or
(if Windows) the provider of your Apache server software if you need to change
either of these and can not figure out how. There is a lot of help available on
the web. Search "mod-rewrite" along with the name of your operating system
distribution or Apache package (if using Windows).
### Unable to write the file config/local.config.php due to permissions issues
Create an empty `config/local.config.php`file and apply world-write permission.
On Linux:
% touch config/local.config.php
% chmod 664 config/local.config.php
Retry the installation. As soon as the database has been created,
******* this is important *********
% chmod 644 config/local.config.php
### Suhosin issues
Some configurations with "suhosin" security are configured without an ability to
run external processes. Friendica requires this ability. Following are some notes
provided by one of our members.
> On my server I use the php protection system Suhosin [http://www.hardened-php.net/suhosin/].
> One of the things it does is to block certain functions like proc_open, as
> configured in `/etc/php5/conf.d/suhosin.ini`:
>
> suhosin.executor.func.blacklist = proc_open, ...
>
> For those sites like Friendica that really need these functions they can be
> enabled, e.g. in `/etc/apache2/sites-available/friendica`:
>
> <Directory /var/www/friendica/>
> php_admin_value suhosin.executor.func.blacklist none
> php_admin_value suhosin.executor.eval.blacklist none
> </Directory>
>
> This enables every function for Friendica if accessed via browser, but not for
> the cronjob that is called via php command line. I attempted to enable it for
> cron by using something like:
>
> */10 * * * * cd /var/www/friendica/friendica/ && sudo -u www-data /usr/bin/php \
> -d suhosin.executor.func.blacklist=none \
> -d suhosin.executor.eval.blacklist=none -f bin/worker.php
>
> This worked well for simple test cases, but the friendica-cron still failed
> with a fatal error:
>
> suhosin[22962]: ALERT - function within blacklist called: proc_open()
> (attacker 'REMOTE_ADDR not set', file '/var/www/friendica/friendica/boot.php',
> line 1341)
>
> After a while I noticed, that `bin/worker.php` calls further PHP script via `proc_open`.
> These scripts themselves also use `proc_open` and fail, because they are NOT
> called with `-d suhosin.executor.func.blacklist=none`.
>
> So the simple solution is to put the correct parameters into `config/local.config.php`:
>
> 'config' => [
> //Location of PHP command line processor
> 'php_path' => '/usr/bin/php -d suhosin.executor.func.blacklist=none \
> -d suhosin.executor.eval.blacklist=none',
> ],
>
> This is obvious as soon as you notice that the friendica-cron uses `proc_open`
> to execute PHP scripts that also use `proc_open`, but it took me quite some time to find that out.
> I hope this saves some time for other people using suhosin with function blacklists.
### Unable to create all mysql tables on MySQL 5.7.17 or newer
If the setup fails to create all the database tables and/or manual creation from
the command line fails, with this error:
ERROR 1067 (42000) at line XX: Invalid default value for 'created'
You need to adjust your my.cnf and add the following setting under the [mysqld]
section:
sql_mode = '';
After that, restart mysql and try again.

View file

@ -19,7 +19,7 @@ Addons must be installed by the site administrator before they can be used.
This is accomplished through the site administration panel.
Each of the connectors also requires an "API key" from the service you wish to connect with.
Some addons allow you to enter this information in the site administration pages, while others may require you to edit your configuration file (config/local.ini.php).
Some addons allow you to enter this information in the site administration pages, while others may require you to edit your configuration file (config/local.config.php).
The ways to obtain these keys vary between the services, but they all require an existing account on the target service.
Once installed, these API keys can usually be shared by all site members.
@ -39,7 +39,7 @@ You can get it from [Twitter](https://twitter.com/apps).
Register your Friendica site as "Client" application with "Read & Write" access.
We do not need "Twitter as login".
When you've registered the app you get a key pair with an OAuth Consumer key and a secret key for your application/site.
Add this key pair to your config/local.ini.php:
Add this key pair to your config/local.config.php:
[twitter]
consumerkey = your consumer_key here

View file

@ -15,6 +15,6 @@ Remember the link at the top of this page will bring you back here.
Once you've added some groups, <a href="help/Quick-Start-andfinally">move on to the next section</a>.
<iframe src="http://dir.friendica.social/directory" width="950" height="600"></iframe>
<iframe src="https://dir.friendica.social/forum" width="950" height="600"></iframe>

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

@ -11,13 +11,13 @@ with your web browser.
You will need to be logged in at the time.
You will be asked for your password to confirm the request.
If this matches your stored password, your account will immediately be blocked to all probing.
Unlike some social networks we do **not** hold onto it for a grace period in case you change your mind.
All your content and user data, etc is instantly removed.
For all intents and purposes, the account is gone in moments.
If this matches your stored password, your account will immediately be marked as deleted.
There is no grace period, this action cannot be reverted.
Most of your content and user data will be deleted shortly in the background.
We then send out an "unfriend" signal to all of your contacts.
This signal deletes all content on those networks.
Unfortunately, due to limitations of the other networks, this only works well with Friendica contacts.
We allow four days for this, in case some servers were down and the unfriend signal was queued.
After this, we finish off deleting the account.
We then send out a notification about the account removal to all of your contacts so that they can do the same with their copy of your data.
For technical reasons some of your user data is still needed to transmit this removal message.
This remaining data will be deleted after a period of around seven days.
To disallow impersonation we have to save your used nickname, so that it can't be used again to register on this node.

View file

@ -73,7 +73,7 @@ With Apache, enable the modules rewrite and ssl (with a shared hosting provider,
sudo a2enmod rewrite ssl
Add the following lines to the .htaccess file in the root folder of your Friendica instance (thanks to [url=https://github.com/AlfredSK]AlfredSK[/url]):
Add the following lines to the .htaccess file in the root folder of your Friendica instance (thanks to [AlfredSK](https://github.com/AlfredSK)):
RewriteEngine On
RewriteCond %{SERVER_PORT} 80

View file

@ -2,23 +2,28 @@
* [Home](help)
If you are the admin of a Friendica node, you have access to the so called **Admin Panel** where you can configure your Friendica node.
If you are the admin of a Friendica node, you have access to the **Admin Panel** where you can configure your Friendica node.
On the front page of the admin panel you will see a summary of information about your node.
These information include the amount of messages currently being processed in the queues.
The first number is the number of messages which could not been delivered for various reasons.
They will be resend later.
You can have a quick glance into that second queus in the "Inspect Queue" section of the admin panel.
The second number represents the current number of jobs for the background workers.
These worker tasks are prioritised and are done accordingly.
## Overview
In the main page of the admin panel you will see an information summary about your node.
### Queues
The three numbers shown are respectively:
- The retry queue: These outgoing messages couldn't be received by the remote host, and will be resent at longer intervals before being dropped entirely after 30 days.
- The deferred queue: These internal tasks failed and will be retried at most 14 times.
- The task queue: These internal tasks are queued for execution during the next background worker run.
### Additional information
Then you get an overview of the accounts on your node, which can be moderated in the "Users" section of the panel.
As well as an overview of the currently active addons
As well as an overview of the currently active addons.
The list is linked, so you can have quick access to the Addon settings.
And finally you are informed about the version of Friendica you have installed.
If you contact the devs with a bug or problem, please also mention the version of your node.
If you contact the developers with a bug or problem, please also mention the version of your node.
The admin panel is seperated into subsections accessible from the side bar of the panel.
The admin panel is separated into subsections accessible from the side bar of the panel.
## Site
@ -42,17 +47,17 @@ This option will set the default language for the node.
It is used as fall back setting should Friendica fail to recognize the visitors preferences and can be overwritten by user settings.
The Friendica community offers some translations.
Some more compleate then others.
Some more complete then others.
See [this help page](/help/translations) for more information about the translation process.
#### System Theme
Choose a theme to be the default system theme.
This can be over-ridden by user profiles.
Default theme is "duepunto zero" at the moment.
Default theme is `vier` at the moment.
You may also want to set a special theme for mobile interfaces.
Which may or may not be neccessary depending of the mobile friendlyness of the desktop theme you have chosen.
Which may or may not be necessary depending of the mobile friendliness of the desktop theme you have chosen.
The `vier` theme for instance is mobile friendly.
### Registration
@ -68,8 +73,8 @@ You can chose between the following modes:
##### Invitation based registry
Additionally to the setting in the admin panel, you can devide if registrations are only possible using an invitation code or not.
To enable invitation based registration, you have to set the `invitation_only` setting in the [config/local.ini.php](/help/Config) file.
Additionally to the setting in the admin panel, you can decide if registrations are only possible using an invitation code or not.
To enable invitation based registration, you have to set the `invitation_only` setting in the [config/local.config.php](/help/Config) file.
If you want to use this method, the registration policy has to be set to either *open* or *requires approval*.
#### Check Full Names
@ -91,11 +96,37 @@ The ability to create "Pages" requires a person to register more than once.
Your site configuration can block registration (or require approval to register).
By default, logged in users can register additional accounts for use as pages.
These will still require approval if the registration policy is set to *require approval*
You may prohibit logged in users from creating additional accounts by setting *block multible registrations* to true.
You may prohibit logged in users from creating additional accounts by setting *block multiple registrations* to true.
Default is false.
### File upload
#### File storage backend
Set the backend used by Friendica to store uploaded file data.
Two storage backends are avaiable with Friendica:
- **Database** : Data is stored in a dedicated table in database (`storage`)
- **Filesystem** : Data is stored as file on the filesystem.
More storage backends can be avaiable from third-party addons.
If you use those, please refer to the documentation of those addons for further information.
Default value is 'Database (legacy)': it's the legacy way used to store data directly in database.
Existing data can be moved to the current active backend using the ['storage move' console command](help/tools)
If selected backend has configurable options, new fields are shown here.
##### Filesystem: Storage base path
The base path where Filesystem storage backend saves data.
For maximum security, this path should be outside the folder tree served by the web server: this way files can't be downloaded bypassing the privacy checks.
Default value is `storage`, that is the `storage` folder in Friendica code root folder.
#### Maximum Image Size
Maximum size in bytes of uploaded images.
@ -138,17 +169,15 @@ 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, cooperations and similar communities that don't want to commuicate with the rest of the network.
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.
#### Allowed Email Domains
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
@ -184,7 +213,7 @@ Value is in seconds.
Default is 60 seconds.
Set to 0 for unlimited (not recommended).
#### Verify SSL Certitificates
#### Verify SSL Certificates
By default Friendica allows SSL communication between websites that have "self-signed" SSL certificates.
For the widest compatibility with browsers and other networks we do not recommend using self-signed certificates, but we will not prevent you from using them.
@ -217,7 +246,7 @@ The tasks for the background process have priorities.
To guarantee that important tasks are executed even though the system has a lot of work to do, it is useful to enable the *fastlane*.
Should you not be able to run a cron job on your server, you can also activate the *frontend* worker.
If you have done so, you can call `example.com/worker` (replace example.com with your actual domain name) on a regular basis from an external servie.
If you have done so, you can call `example.com/worker` (replace example.com with your actual domain name) on a regular basis from an external service.
This will then trigger the execution of the background process.
### Relocate
@ -234,13 +263,13 @@ You can sort the user list by name, email, registration date, date of last login
Here the admin can also block/unblock users from accessing the node or delete the accounts entirely.
In the last section of the page admins can create new accounts on the node.
The password for the new account will be send by email to the choosen email address.
The password for the new account will be send by email to the chosen email address.
## Addons
This page is for selecting and configuration of extensions for Friendica which have to be placed into the `/addon` subdirectory of your Friendica installation.
You are presented with a long list of available addons.
The name of each addon is linked to a separate page for that addon which offers more informations and configuration possibilities.
The name of each addon is linked to a separate page for that addon which offers more information and configuration possibilities.
Also shown is the version of the addon and an indicator if the addon is currently active or not.
When you update your node and the addons they may have to be reloaded.
@ -263,16 +292,16 @@ In this section of the admin panel you can select a default setting for your nod
## DB Updates
Should the database structure of Friendica change, it will apply the changes automatically.
In case you are suspecious that the update might not have worked, you can use this section of the admin panel to check the situation.
In case you are suspecting the update might not have worked, you can use this section of the admin panel to check the situation.
## Inspect Queue
In the admin panel summary there are two numbers for the message queues.
The second number represents messages which could not be delivered and are queued for later retry.
If this number goes sky-rocking you might ask yourself which receopiant is not receiving.
If this number goes sky-rocking you might ask yourself which recipient is not receiving.
Behind the inspect queue section of the admin panel you will find a list of the messages that could not be delivered.
The listing is sorted by the receipiant name so identifying potential broken communication lines should be simple.
The listing is sorted by the recipient name so identifying potential broken communication lines should be simple.
These lines might be broken for various reasons.
The receiving end might be off-line, there might be a high system load and so on.
@ -288,7 +317,7 @@ Matching is exact, blocking a domain doesn't block subdomains.
## Federation Statistics
The federation statistics page gives you a short summery of the nodes/servers/pods of the decentralized social network federation your node knows.
These numbers are not compleate and only contain nodes from networks Friendica federates directly with.
These numbers are not complete and only contain nodes from networks Friendica federates directly with.
## Delete Item
@ -304,16 +333,16 @@ All those addons will be listed in this area of the admin panels side bar with t
## Logs
The log section of the admin panel is seperated into two pages.
The log section of the admin panel is separated into two pages.
On the first, following the "log" link, you can configure how much Friendica shall log.
And on the second you can read the log.
You should not place your logs into any directory that is accessible from the web.
If you have to, and you are using the default configuration from Apache, you should choose a name for the logfile ending in ``.log`` or ``.out``.
Should you use another web server, please make sure that you have the correct accessrules in place so that your log files are not accessible.
Should you use another web server, please make sure that you have the correct access rules in place so that your log files are not accessible.
There are five different log levels: Normal, Trace, Debug, Data and All.
Specifying different verbosities of information and data written out to the log file.
Specifying different verbosity of information and data written out to the log file.
Normally you should not need to log at all.
The *DEBUG* level will show a good deal of information about system activity but will not include detailed data.
In the *ALL* level Friendica will log everything to the file.
@ -324,8 +353,8 @@ You should set up some kind of [log rotation](https://en.wikipedia.org/wiki/Log_
**Known Issues**: The filename ``friendica.log`` can cause problems depending on your server configuration (see [issue 2209](https://github.com/friendica/friendica/issues/2209)).
By default PHP warnings and error messages are supressed.
If you want to enable those, you have to activate them in the ``config/local.ini.php`` file.
By default PHP warnings and error messages are suppressed.
If you want to enable those, you have to activate them in the ``config/local.config.php`` file.
Use the following settings to redirect PHP errors to a file.
Config:
@ -345,7 +374,7 @@ If you encounter a blank (white) page when using the application, view the PHP l
## Diagnostics
In this section of the admin panel you find two tools to investigate what Friendica sees for certain ressources.
In this section of the admin panel you find two tools to investigate what Friendica sees for certain resources.
These tools can help to clarify communication problems.
For the *probe address* Friendica will display information for the address provided.
@ -359,12 +388,15 @@ These are the data base settings, the admin account settings, the path of PHP an
## DB Settings
With the following settings, you specify the data base server, the username and passwort for Friendica and the database to use.
With the following settings, you specify the data base server, the username and password for Friendica and the database to use.
$db_host = 'your.db.host';
$db_user = 'db_username';
$db_pass = 'db_password';
$db_data = 'database_name';
'database' => [
'hostname' => 'localhost',
'username' => 'mysqlusername',
'password' => 'mysqlpassword',
'database' => 'mysqldatabasename',
'charset' => 'utf8mb4',
],
## Admin users
@ -373,27 +405,30 @@ By default this will be the one account you create during the installation proce
But you can expand the list of email addresses by any used email address you want.
Registration of new accounts with a listed email address is not possible.
[config]
admin_email = you@example.com, buddy@example.com
'config' => [
'admin_email' => 'you@example.com, buddy@example.com',
],
## PHP Path
Some of Friendicas processes are running in the background.
Some of Friendica's processes are running in the background.
For this you need to specify the path to the PHP binary to be used.
[config]
php_path = {{$phpath}}
'config' => [
'php_path' => '/usr/bin/php',
],
## Subdirectory configuration
It is possible to install Friendica into a subdirectory of your webserver.
We strongly discourage you from doing so, as this will break federation to other networks (e.g. Diaspora, GNU Socia, Hubzilla)
It is possible to install Friendica into a subdirectory of your web server.
We strongly discourage you from doing so, as this will break federation to other networks (e.g. Diaspora, GNU Social, Hubzilla)
Say you have a subdirectory for tests and put Friendica into a further subdirectory, the config would be:
[system]
urlpath = tests/friendica
'system' => [
'urlpath' => 'tests/friendica',
],
## Other exceptions
Furthermore there are some experimental settings, you can read-up in the [Config values that can only be set in config/local.ini.php](help/Config) section of the documentation.
Furthermore there are some experimental settings, you can read-up in the [Config values that can only be set in config/local.config.php](help/Config) section of the documentation.

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,74 @@
# 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.
## Third-party applications and API
Third-party applications using the Friendica API can't accept two-factor time-based authentication codes.
Instead, if you enabled two-factor authentication, you have to generate app-specific randomly generated long passwords to use in your apps instead of your regular account password.
**Note**: Your regular password won't work at all when prompted in third-party apps if you enabled two-factor authentication.
You can generate as many app-specific passwords as you want, they will be shown once to you just after you generated it.
Just copy and paste it in your third-party app in the Friendica account password input field at this point.
We recommend generating a single app-specific password for each separate third-party app you are using, using a meaningul description of the target app (like "Frienqa on my Fairphone 2").
You can also revoke any and all app-specific password you generated this way.
This may log you out of the third-party application(s) you used the revoked app-specific password to log in with.

View file

@ -6,8 +6,9 @@ Updating Friendica
## Using a Friendica archive
If you installed Friendica in the ``path/to/friendica`` folder:
1. Unpack the new Friendica archive in ``path/to/friendica_new``.
2. Copy ``config/local.ini.php``, ``photo/`` and ``proxy/`` from ``path/to/friendica`` to ``path/to/friendica_new``.
2. Copy ``config/local.config.php``, ``photo/`` and ``proxy/`` from ``path/to/friendica`` to ``path/to/friendica_new``.
3. Rename the ``path/to/friendica`` folder to ``path/to/friendica_old``.
4. Rename the ``path/to/friendica_new`` folder to ``path/to/friendica``.
5. Check your site. Note: it may go into maintenance mode to update the database schema.
@ -21,7 +22,7 @@ You can get the latest changes at any time with
cd path/to/friendica
git pull
bin/composer.phar install
bin/composer.phar install --no-dev
The addon tree has to be updated separately like so:
@ -69,4 +70,4 @@ DROP TABLE <table_name>;
RENAME TABLE <table_name>_new TO <table_name>;
```
This method is slower overall, but it is better suited for large numbers of duplicates.
This method is slower overall, but it is better suited for large numbers of duplicates.

View file

@ -42,7 +42,7 @@ This will not delete the virtual machine.
9. To ultimately delete the virtual machine run
$> vagrant destroy
$> rm /vagrant/config/local.ini.php
$> rm /vagrant/config/local.config.php
to make sure that you can start from scratch with another "vagrant up".
@ -53,6 +53,6 @@ You will then have the following accounts to login:
* friendica1, password friendica1
* friendica2, password friendica2 and so on until friendica5
* friendica1 is connected to all others. friendica1 has two groups: group1 with friendica2 and friendica4, group2 with friendica3 and friendica5.
* friendica2 and friendica3 are conntected. friendica4 and friendica5 are connected.
* friendica2 and friendica3 are connected. friendica4 and friendica5 are connected.
For further documentation of vagrant, please see [the vagrant*docs*](https://docs.vagrantup.com/v2/).

View file

@ -379,6 +379,39 @@ Friendica doesn't allow showing the friends of other users.
* media: image data
#### Return values
Object of:
* media_id: a media identifier (integer)
* media_id_string: a media identifier (string)
* size: size in byte
* image.w: image width
* image.h: image height
* image.image_type: image mime type
* image.friendica_preview_url: image preview url
---
### media/metadata/create (POST,PUT; AUTH)
#### Parameters
Parameters are sent as JSON object:
```
{
"media_id":"1234",
"alt_text": {
"text":"Here comes the description"
}
}
```
#### Return values
None
---
### oauth/request_token (*)
@ -642,9 +675,11 @@ Returned status object is conform to GNU Social/Twitter api.
Friendica adds some addictional fields:
- author: a user object, it's the author of the item. In case of a reshare for legacy reasons the "user" field doesn't show the real author. This field always contains the real author of a post.
- owner: a user object, it's the owner of the item.
- private: boolean, true if the item is marked as private
- activities: map with activities related to the item. Every activity is a list of user objects.
- comments: comment numbers
This properties are prefixed with "friendica_" in JSON responses and namespaced under "http://friendi.ca/schema/api/1/" in XML responses
@ -654,6 +689,9 @@ JSON:
[
{
// ...
'friendica_author' : {
// user object
},
'friendica_owner' : {
// user object
},
@ -669,7 +707,8 @@ JSON:
'attendyes': [],
'attendno': [],
'attendmaybe': []
}
},
'friendica_comments': 12
},
// ...
]
@ -695,6 +734,7 @@ XML:
<friendica:attendno/>
<friendica:attendmaybe/>
</friendica:activities>
<friendica:comments>21</friendica:comments>
</status>
<!-- ... -->
</statuses>
@ -744,6 +784,7 @@ Friendica doesn't allow showing followers of other users.
* count: alias for the rpp parameter
* since_id: returns statuses with ids greater than the given id
* max_id: returns statuses with ids lower or equal to the given id
* exclude_replies: don't show replies (default: false)
#### Unsupported parameters

View file

@ -4,71 +4,73 @@ Account - Basics
* [Zur Startseite der Hilfe](help)
**Registrierung**
## Registrierung
Nicht alle Friendica-Knoten bieten die Möglichkeit zur Registrierung.
Wenn die Registrierung möglich ist, wird ein "Registrieren"-Link unter dem Login-Feld auf der Startseite angezeigt, der zur Registrierungsseite führt.
Die Stärke unseres Netzwerks ist, dass die verschiedenen Knoten komplett kompatibel zueinander sind.
Wenn der Knoten, den Du besuchst, keine Registrierung anbietet, oder wenn Du glaubst, dass Dir eine andere Seite möglicherweise besser gefällt, dann kannst Du hier eine <a href="https://dir.friendica.social/servers">Liste von öffentlichen Servern (Knoten)</a> finden und den Knoten heraus suchen, der am Besten zu Deinen Anforderungen passt.
Viele, aber nicht alle Friendica-Knoten (Server) bieten die Möglichkeit zur Registrierung an.
Falls der Friendica-Knoten, den Du besuchst, keine Registrierung anbietet, oder Du glaubst, dass Dir ein anderer Knoten möglicherweise besser gefällt, dann findest Du hier eine [Liste von öffentlichen Friendica-Knoten](https://dir.friendica.social/servers), aus der Du Dir eine netten Knoten heraussuchen kannst.
Wenn Du Deinen eigenen Server aufsetzen willst, kannst Du das ebenfalls machen.
Besuche <a href="http://friendi.ca">die Friendica-Webseite</a>, um den Code mit den Installationsanleitungen herunterzuladen.
Es ist ein einfacher Installationsprozess, den jeder mit ein wenig Erfahrungen im Webseiten-Hosting oder mit grundlegenden Linux-Erfahrungen einfach handhaben kann.
Auf der Startseite des Knotens wird unter dem Login-Feld ein "Registrieren"-Link angezeigt.
Dieser Link führt dann direkt auf das Registrierungsformular.
### OpenID
*OpenID*
Falls du keine [OpenID-Adresse](https://de.wikipedia.org/wiki/OpenID">OpenID-Adresse) hast, kannst du diesen Punkt ignorieren.
Das erste Feld auf der Registrierungsseite ist für eine OpenID-Adresse.
Wenn Du keine OpenID-Adresse hast oder nicht wünschst, diese zu nutzen, dann lasse das Feld frei.
Wenn Du einen OpenID-Account hast und diesen nutzen willst, gib die Adresse in das Feld ein und klicke auf "Registrieren".
Solltest du eine OpenID Adresse haben, kannst Du sie im ersten Feld eintragen und "Registrieren" klicken.
Friendica wird versuchen, so viele Informationen wie möglich von Deinem OpenID-Provider zu übernehmen, um diese in Dein Profil auf dieser Seite einzutragen.
*Dein vollständiger Name*
### Dein vollständiger Name
Bitte trage Deinen vollständigen Namen **so ein, wie Du ihn im System anzeigen lassen willst**.
Viele Leute nutzen ihren richtigen Namen hierfür, allerdings besteht für dich keine Pflicht, das auch so zu machen.
Bitte trage bei "vollständiger Name" Deinen **gewünschten Namen** ein, wie er über deinen Beiträgen angezeigt werden soll.
Du kannst deinen echten Namen eintragen, kannst Dir aber auch einen Namen ausdenken. Einen Zwang zu dem sogenannten Klarnamen gibt es nicht.
*Email-Adresse*
### Email-Adresse
Bitte trage eine richtige Email-Adresse ein.
Deine Email-Adresse wird **niemals** veröffentlicht.
Wir benötigen diese, um Dir Account-Informationen und die Login-Daten zu schicken.
Du erhältst zudem von Zeit zu Zeit Benachrichtigungen über eingegangene Nachrichten oder Punkte, die Deine Aufmerksamkeit benötigen.
Du hast aber auch die Möglichkeit, diese Nachrichten in Deinen Account-Einstellungen komplett abzuschalten.
Du musst nicht Deine Haupt-Email-Adresse sein, jedoch wird eine funktionierende Adresse benötigt.
Ohne dieses kannst Du weder Dein Initialpasswort erhalten, noch Dein Passwort zurücksetzen.
Dies ist die einzige persönliche Information, die korrekt sein muss.
Deine Email-Adresse wird **niemals** veröffentlicht.
*Spitzname/Nickname*
Wir benötigen diese, um Dir Account-Informationen, das Initialpasswort und die Login-Daten zu schicken. Oder z.B. Dein Passwort zurückzusetzen.
Der Spitzname wird benötigt, um eine Webadresse für viele Deiner persönlichen Seiten zu erstellen.
Du erhältst zudem von Zeit zu Zeit Benachrichtigungen über eingegangene Nachrichten oder Punkte, die Deine Aufmerksamkeit benötigen.
Diese Nachrichten sind in den Einstellungen jederzeit an- oder abschaltbar.
### Spitzname/Nickname
Der Spitzname wird benötigt, um eine Webadresse (Profiladresse) für viele Deiner persönlichen Seiten zu erstellen.
Auch wird dieser wie eine Email-Adresse genutzt, wenn eine Verbindung zu anderen Personen hergestellt werden soll.
Durch die Art, wie der Spitzname genutzt wird, gibt es bestimmte Einschränkungen. Er darf nur US-ASCII-Textzeichen und Nummern enthalten und er muss zudem mit einem Buchstaben beginnen.
Er muss außerdem einzigartig im System sein.
Dieser Spitzname wird an vielen Stellen genutzt, um Deinen Account zu identifizieren, und kann daher später nicht mehr geändert werden.
Durch die Art, wie der Spitzname genutzt wird, gibt es bestimmte Einschränkungen:
* **er muss mit einem Buchstaben beginnen**
* **er darf nur US-ASCII-Textzeichen und Nummern enthalten**
* **er muss einzigartig auf diesem Friendica-Knoten sein**
* **er kann später nicht mehr geändert werden**
Dieser Spitzname wird an vielen Stellen genutzt, um Deinen Account zu identifizieren, daher ist es nicht möglich ihn später zu ändern.
*Verzeichnis-Eintrag*
### Verzeichnis-Eintrag
Das Registrierungsformular erlaubt es dir, direkt auszuwählen, ob Du im [Onlineverzeichnis](https://dir.friendica.social/) (Friendica Directory) aufgelistet wirst oder nicht.
Das ist wie ein Telefonbuch und Du entscheidest, ob du darin eingetragen werden möchtest, oder nicht.
* Wir bitten dich, "Ja" zu wählen, damit Andere Dich finden können, so wie Du sie finden kannst
* Wählst Du "Nein", bist Du für Andere *nicht einfach auffindbar*
Das Registrierungsformular erlaubt es dir, direkt auszuwählen, ob Du im Onlineverzeichnis aufgelistet wirst oder nicht.
Das ist wie ein Telefonbuch und Du kannst entscheiden, nicht aufgeführt zu werden.
Wir bitten dich, "Ja" zu wählen, so dass dich andere Leute (Freunde, Familie etc.) finden können.
Wenn Du "Nein" wählst, wirst Du hauptsächlich unsichtbar sein und nur wenige Möglichkeiten zur Interaktion haben.
Was auch immer Du wählst, kann jederzeit nach dem Login in Deinen Account-Einstellungen geändert werden.
*Registrierung*
### Registrierung
Sobald Du die nötigen Informationen eingegeben hast, klicke auf "Registrieren".
Eine Email mit den Registrierungsdetails und Deinem Initialpasswort wird an die hinterlegte Email-Adresse geschickt.
Bitte prüfe den Posteingang (inkl. dem Spam-Ordner).
**Login-Seite**
## Login-Seite
Gib auf der "Login"-Seite die Informationen ein, die Du mit der oben genannten Email erhalten hast.
Du kannst entweder Deinen Spitznamen oder die Email-Adresse als Login-Namen nutzen.
@ -83,25 +85,29 @@ Das Passwort muss genau so geschrieben werden, wie es in der Email steht; Groß-
Falls Du Schwierigkeiten beim Login hast, prüfe bitte, ob z. B. Deine Feststelltaste aktiv ist.
**Passwort ändern**
### Passwort ändern
Besuche nach Deinem ersten Login bitte die Einstellungsseite und wechsle das Passwort in eines, dass Du Dir merken kannst.
**Der Anfang**
## Die ersten Schritte
### Persönliche Daten exportieren
Du solltest dir als erstes Deinen neu erstellen [Account exportieren](uexport) unter Einstellungen/Persönliche Daten exportieren und an einem sicheren Ort verwahren.
In diesem Export (JSON-Datei) sind enthalten
* Deine Identität, die mit kryptographischen Schlüsseln ausgestattet ist
* Deine Kontakte
Dies ist z.B. dann nützlich wenn du mit deinem Account auf einen anderen Friendica Knoten umziehen willst, oder musst.
### Hilfe für Neulinge
Ein ['Tipp für neue Mitglieder'](newmember)-Link zeigt sich in den ersten beiden Wochen auf Deiner Startseite, um Dir erste Informationen zum Start zu bieten.
**Persönliche Daten exportieren**
Du kannst eine Kopie Deiner persönlichen Daten in einer JSON-Datei exportieren.
Gehe hierzu in Deinen Einstellungen auf "Persönliche Daten exportieren".
Dies ist z.B. dann nützlich wenn du mit deinem Account auf einen anderen Friendica Knoten umziehen möchstest.
Ein Grund hierfür könnte sein, dass der Server auf dem dieser Friendica Knoten läuft dauerhaft wegen eines Hardware Problems ausfällt.
**Schau Dir ebenfalls folgende Seiten an**
## Schau Dir ebenfalls folgende Seiten an
* [Profile](help/Profiles)
@ -109,3 +115,10 @@ Ein Grund hierfür könnte sein, dass der Server auf dem dieser Friendica Knoten
* [Account löschen](help/Remove-Account)
### Der eigene Friendica-Knoten
Wenn Du Deinen eigenen Friendica-Knoten auf einem Server aufsetzen willst, kannst Du das ebenfalls machen.
Besuche die [Friendica-Webseite](https://friendi.ca), um den Code mit den Installationsanleitungen herunterzuladen.
Es ist ein einfacher Installationsprozess, den jeder mit ein wenig technischen Erfahrungen im Webseiten-Hosting oder mit grundlegenden Linux-Erfahrungen handhaben kann.

View file

@ -26,7 +26,7 @@ Addons sollten einen Kommentarblock mit den folgenden vier Parametern enthalten:
Registriere deine Addon-Hooks während der Installation.
Addon::registerHook($hookname, $file, $function);
\Friendica\Core\Hook::register($hookname, $file, $function);
$hookname ist ein String und entspricht einem bekannten Friendica-Hook.
@ -193,299 +193,294 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap
### index.php
Addon::callHooks('init_1');
Addon::callHooks('app_menu', $arr);
Addon::callHooks('page_content_top', $a->page['content']);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_init', $placeholder);
Addon::callHooks($a->module.'_mod_post', $_POST);
Addon::callHooks($a->module.'_mod_afterpost', $placeholder);
Addon::callHooks($a->module.'_mod_content', $arr);
Addon::callHooks($a->module.'_mod_aftercontent', $arr);
Addon::callHooks('page_end', $a->page['content']);
Hook::callAll('init_1');
Hook::callAll('app_menu', $arr);
Hook::callAll('page_content_top', $a->page['content']);
Hook::callAll($a->module.'_mod_init', $placeholder);
Hook::callAll($a->module.'_mod_init', $placeholder);
Hook::callAll($a->module.'_mod_post', $_POST);
Hook::callAll($a->module.'_mod_afterpost', $placeholder);
Hook::callAll($a->module.'_mod_content', $arr);
Hook::callAll($a->module.'_mod_aftercontent', $arr);
Hook::callAll('page_end', $a->page['content']);
### include/api.php
Addon::callHooks('logged_in', $a->user);
Addon::callHooks('authenticate', $addon_auth);
Addon::callHooks('logged_in', $a->user);
Hook::callAll('logged_in', $a->user);
Hook::callAll('authenticate', $addon_auth);
Hook::callAll('logged_in', $a->user);
### include/enotify.php
Addon::callHooks('enotify', $h);
Addon::callHooks('enotify_store', $datarray);
Addon::callHooks('enotify_mail', $datarray);
Addon::callHooks('check_item_notification', $notification_data);
Hook::callAll('enotify', $h);
Hook::callAll('enotify_store', $datarray);
Hook::callAll('enotify_mail', $datarray);
Hook::callAll('check_item_notification', $notification_data);
### include/conversation.php
Addon::callHooks('conversation_start', $cb);
Addon::callHooks('render_location', $locate);
Addon::callHooks('display_item', $arr);
Addon::callHooks('display_item', $arr);
Addon::callHooks('item_photo_menu', $args);
Addon::callHooks('jot_tool', $jotplugins);
Hook::callAll('conversation_start', $cb);
Hook::callAll('render_location', $locate);
Hook::callAll('display_item', $arr);
Hook::callAll('display_item', $arr);
Hook::callAll('item_photo_menu', $args);
Hook::callAll('jot_tool', $jotplugins);
### include/text.php
Addon::callHooks('contact_block_end', $arr);
Addon::callHooks('poke_verbs', $arr);
Addon::callHooks('put_item_in_cache', $hook_data);
Addon::callHooks('prepare_body_init', $item);
Addon::callHooks('prepare_body_content_filter', $hook_data);
Addon::callHooks('prepare_body', $hook_data);
Addon::callHooks('prepare_body_final', $hook_data);
Hook::callAll('contact_block_end', $arr);
Hook::callAll('poke_verbs', $arr);
Hook::callAll('put_item_in_cache', $hook_data);
Hook::callAll('prepare_body_init', $item);
Hook::callAll('prepare_body_content_filter', $hook_data);
Hook::callAll('prepare_body', $hook_data);
Hook::callAll('prepare_body_final', $hook_data);
### include/items.php
Addon::callHooks('page_info_data', $data);
Hook::callAll('page_info_data', $data);
### mod/directory.php
Addon::callHooks('directory_item', $arr);
Hook::callAll('directory_item', $arr);
### mod/xrd.php
Addon::callHooks('personal_xrd', $arr);
Hook::callAll('personal_xrd', $arr);
### mod/ping.php
Addon::callHooks('network_ping', $arr);
Hook::callAll('network_ping', $arr);
### mod/parse_url.php
Addon::callHooks("parse_link", $arr);
Hook::callAll("parse_link", $arr);
### mod/manage.php
### src/Module/Delegation.php
Addon::callHooks('home_init', $ret);
Hook::callAll('home_init', $ret);
### mod/acl.php
Addon::callHooks('acl_lookup_end', $results);
Hook::callAll('acl_lookup_end', $results);
### mod/network.php
Addon::callHooks('network_content_init', $arr);
Addon::callHooks('network_tabs', $arr);
Hook::callAll('network_content_init', $arr);
Hook::callAll('network_tabs', $arr);
### mod/friendica.php
Addon::callHooks('about_hook', $o);
Hook::callAll('about_hook', $o);
### mod/subthread.php
Addon::callHooks('post_local_end', $arr);
Hook::callAll('post_local_end', $arr);
### mod/profiles.php
Addon::callHooks('profile_post', $_POST);
Addon::callHooks('profile_edit', $arr);
Hook::callAll('profile_post', $_POST);
Hook::callAll('profile_edit', $arr);
### mod/settings.php
Addon::callHooks('addon_settings_post', $_POST);
Addon::callHooks('connector_settings_post', $_POST);
Addon::callHooks('display_settings_post', $_POST);
Addon::callHooks('settings_post', $_POST);
Addon::callHooks('addon_settings', $settings_addons);
Addon::callHooks('connector_settings', $settings_connectors);
Addon::callHooks('display_settings', $o);
Addon::callHooks('settings_form', $o);
Hook::callAll('addon_settings_post', $_POST);
Hook::callAll('connector_settings_post', $_POST);
Hook::callAll('display_settings_post', $_POST);
Hook::callAll('settings_post', $_POST);
Hook::callAll('addon_settings', $settings_addons);
Hook::callAll('connector_settings', $settings_connectors);
Hook::callAll('display_settings', $o);
Hook::callAll('settings_form', $o);
### mod/photos.php
Addon::callHooks('photo_post_init', $_POST);
Addon::callHooks('photo_post_file', $ret);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', $foo);
Addon::callHooks('photo_post_end', intval($item_id));
Addon::callHooks('photo_upload_form', $ret);
Hook::callAll('photo_post_init', $_POST);
Hook::callAll('photo_post_file', $ret);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', $foo);
Hook::callAll('photo_post_end', intval($item_id));
Hook::callAll('photo_upload_form', $ret);
### mod/profile.php
Addon::callHooks('profile_advanced', $o);
Hook::callAll('profile_advanced', $o);
### mod/home.php
Addon::callHooks('home_init', $ret);
Addon::callHooks("home_content", $content);
Hook::callAll('home_init', $ret);
Hook::callAll("home_content", $content);
### mod/poke.php
Addon::callHooks('post_local_end', $arr);
Hook::callAll('post_local_end', $arr);
### mod/contacts.php
Addon::callHooks('contact_edit_post', $_POST);
Addon::callHooks('contact_edit', $arr);
Hook::callAll('contact_edit_post', $_POST);
Hook::callAll('contact_edit', $arr);
### mod/tagger.php
Addon::callHooks('post_local_end', $arr);
Hook::callAll('post_local_end', $arr);
### mod/lockview.php
Addon::callHooks('lockview_content', $item);
Hook::callAll('lockview_content', $item);
### mod/uexport.php
Addon::callHooks('uexport_options', $options);
Hook::callAll('uexport_options', $options);
### mod/register.php
Addon::callHooks('register_post', $arr);
Addon::callHooks('register_form', $arr);
Hook::callAll('register_post', $arr);
Hook::callAll('register_form', $arr);
### mod/item.php
Addon::callHooks('post_local_start', $_REQUEST);
Addon::callHooks('post_local', $datarray);
Addon::callHooks('post_local_end', $datarray);
Hook::callAll('post_local_start', $_REQUEST);
Hook::callAll('post_local', $datarray);
Hook::callAll('post_local_end', $datarray);
### mod/editpost.php
Addon::callHooks('jot_tool', $jotplugins);
Hook::callAll('jot_tool', $jotplugins);
### src/Network/FKOAuth1.php
Addon::callHooks('logged_in', $a->user);
Hook::callAll('logged_in', $a->user);
### src/Render/FriendicaSmartyEngine.php
Addon::callHooks("template_vars", $arr);
Hook::callAll("template_vars", $arr);
### src/Model/Item.php
Addon::callHooks('post_local', $item);
Addon::callHooks('post_remote', $item);
Addon::callHooks('post_local_end', $posted_item);
Addon::callHooks('post_remote_end', $posted_item);
Addon::callHooks('tagged', $arr);
Addon::callHooks('post_local_end', $new_item);
Hook::callAll('post_local', $item);
Hook::callAll('post_remote', $item);
Hook::callAll('post_local_end', $posted_item);
Hook::callAll('post_remote_end', $posted_item);
Hook::callAll('tagged', $arr);
Hook::callAll('post_local_end', $new_item);
### src/Model/Contact.php
Addon::callHooks('contact_photo_menu', $args);
Addon::callHooks('follow', $arr);
Hook::callAll('contact_photo_menu', $args);
Hook::callAll('follow', $arr);
### src/Model/Profile.php
Addon::callHooks('profile_sidebar_enter', $profile);
Addon::callHooks('profile_sidebar', $arr);
Addon::callHooks('profile_tabs', $arr);
Addon::callHooks('zrl_init', $arr);
Hook::callAll('profile_sidebar_enter', $profile);
Hook::callAll('profile_sidebar', $arr);
Hook::callAll('profile_tabs', $arr);
Hook::callAll('zrl_init', $arr);
### src/Model/Event.php
Addon::callHooks('event_updated', $event['id']);
Addon::callHooks("event_created", $event['id']);
Hook::callAll('event_updated', $event['id']);
Hook::callAll("event_created", $event['id']);
### src/Model/User.php
Addon::callHooks('register_account', $uid);
Addon::callHooks('remove_user', $user);
Hook::callAll('register_account', $uid);
Hook::callAll('remove_user', $user);
### src/Content/Text/BBCode.php
Addon::callHooks('bbcode', $text);
Addon::callHooks('bb2diaspora', $text);
Hook::callAll('bbcode', $text);
Hook::callAll('bb2diaspora', $text);
### src/Content/Text/HTML.php
Addon::callHooks('html2bbcode', $message);
Hook::callAll('html2bbcode', $message);
### src/Content/Smilies.php
Addon::callHooks('smilie', $params);
Hook::callAll('smilie', $params);
### src/Content/Feature.php
Addon::callHooks('isEnabled', $arr);
Addon::callHooks('get', $arr);
Hook::callAll('isEnabled', $arr);
Hook::callAll('get', $arr);
### src/Content/ContactSelector.php
Addon::callHooks('network_to_name', $nets);
Addon::callHooks('gender_selector', $select);
Addon::callHooks('sexpref_selector', $select);
Addon::callHooks('marital_selector', $select);
Hook::callAll('network_to_name', $nets);
Hook::callAll('gender_selector', $select);
Hook::callAll('sexpref_selector', $select);
Hook::callAll('marital_selector', $select);
### src/Content/OEmbed.php
Addon::callHooks('oembed_fetch_url', $embedurl, $j);
Hook::callAll('oembed_fetch_url', $embedurl, $j);
### src/Content/Nav.php
Addon::callHooks('page_header', $a->page['nav']);
Addon::callHooks('nav_info', $nav);
Hook::callAll('page_header', $a->page['nav']);
Hook::callAll('nav_info', $nav);
### src/Core/Authentication.php
Addon::callHooks('logged_in', $a->user);
Hook::callAll('logged_in', $a->user);
### src/Worker/Directory.php
Addon::callHooks('globaldir_update', $arr);
Hook::callAll('globaldir_update', $arr);
### src/Worker/Notifier.php
Addon::callHooks('notifier_end', $target_item);
### src/Worker/Queue.php
Addon::callHooks('queue_predeliver', $r);
Addon::callHooks('queue_deliver', $params);
Hook::callAll('notifier_end', $target_item);
### src/Module/Login.php
Addon::callHooks('authenticate', $addon_auth);
Addon::callHooks('login_hook', $o);
Hook::callAll('authenticate', $addon_auth);
Hook::callAll('login_hook', $o);
### src/Module/Logout.php
Addon::callHooks("logging_out");
Hook::callAll("logging_out");
### src/Object/Post.php
Addon::callHooks('render_location', $locate);
Addon::callHooks('display_item', $arr);
Hook::callAll('render_location', $locate);
Hook::callAll('display_item', $arr);
### src/Core/ACL.php
Addon::callHooks('contact_select_options', $x);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks($a->module.'_pre_'.$selname, $arr);
Addon::callHooks($a->module.'_post_'.$selname, $o);
Addon::callHooks('jot_networks', $jotnets);
Hook::callAll('contact_select_options', $x);
Hook::callAll($a->module.'_pre_'.$selname, $arr);
Hook::callAll($a->module.'_post_'.$selname, $o);
Hook::callAll($a->module.'_pre_'.$selname, $arr);
Hook::callAll($a->module.'_post_'.$selname, $o);
Hook::callAll('jot_networks', $jotnets);
### src/Core/Worker.php
Addon::callHooks("proc_run", $arr);
Hook::callAll("proc_run", $arr);
### src/Util/Emailer.php
Addon::callHooks('emailer_send_prepare', $params);
Addon::callHooks("emailer_send", $hookdata);
Hook::callAll('emailer_send_prepare', $params);
Hook::callAll("emailer_send", $hookdata);
### src/Util/Map.php
Addon::callHooks('generate_map', $arr);
Addon::callHooks('generate_named_map', $arr);
Addon::callHooks('Map::getCoordinates', $arr);
Hook::callAll('generate_map', $arr);
Hook::callAll('generate_named_map', $arr);
Hook::callAll('Map::getCoordinates', $arr);
### src/Util/Network.php
Addon::callHooks('avatar_lookup', $avatar);
Hook::callAll('avatar_lookup', $avatar);
### src/Util/ParseUrl.php
Addon::callHooks("getsiteinfo", $siteinfo);
Hook::callAll("getsiteinfo", $siteinfo);
### src/Protocol/DFRN.php
Addon::callHooks('atom_feed_end', $atom);
Addon::callHooks('atom_feed_end', $atom);
Hook::callAll('atom_feed_end', $atom);
Hook::callAll('atom_feed_end', $atom);

View file

@ -68,6 +68,10 @@ table.bbcodes > * > tr > th {
<td>[img]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]</td>
<td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" alt="Immagine/foto"></td>
</tr>
<tr>
<td>[img=https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg]Das Friendica Logo[/img]</td>
<td><img src="https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg" alt="Das Friendica Logo"></td>
</tr>
<tr>
<td>[img=64x32]https://raw.githubusercontent.com/friendica/friendica/master/images/friendica-32.jpg[/img]<br>
<br>Note: provided height is simply discarded.</td>
@ -576,6 +580,9 @@ F&uuml;r Verbindungen zu Netzwerken, zu denen Friendica den HTML Code postet, wi
Bei nativen Verbindungen; das hei&szlig;t zu z.B. Friendica, Hubzilla, Diaspora oder GNU Social Kontakten; wird der ungek&uuml;rzte Beitrag &uuml;bertragen.
Die Instanz des Kontakts k&uuml;mmert sich um die Darstellung.
Wird ein Beitrag über das ActivityPub Protokoll &uuml;bermittelt, wird der Text des Abstracts f&uuml;r das "summary" (Zusammenfassung) Feld verwendet.
Dieses Feld wird von Mastodon f&uuml;r die Inhaltswarnung (content warning) verwendet.
## Special
<table class="bbcodes">

View file

@ -8,6 +8,7 @@ Nutzer
* **[Warum erhalte ich Warnungen über fehlende Zertifikate?](help/FAQ#ssl)**
* **[Wie kann ich Bilder, Dateien, Links, Video und Audio in Beiträge einfügen?](help/FAQ#upload)**
* **[Ist es möglich, bei mehreren Profilen verschiedene Avatare (Nutzerbilder) zu haben?](help/FAQ#avatars)**
* **[Wie kann ich Friendica in einer bestimmten Sprache ansehen?](help/FAQ#language)**
* **[Was ist der Unterschied zwischen blockierten|ignorierten|archivierten|versteckten Kontakten?](help/FAQ#contacts)**
* **[Was passiert, wenn ein Account gelöscht ist? Ist dieser richtig gelöscht?](help/FAQ#removed)**
* **[Kann ich einem Hashtag folgen?](help/FAQ#hashtag)**
@ -90,6 +91,31 @@ Anschließend siehst Du eine Seite mit allen Infos zu diesem Profil.
Klicke nun oben auf den Link "Profilbild ändern" und lade im nächsten Fenster ein Bild von Deinem PC hoch.
Um Deine privaten Daten zu schützen, wird in Beiträgen nur das Bild aus Deinem öffentlichen Profil angezeigt.
<a name="language"></a>
### Wie kann ich Friendica in einer bestimmten Sprache ansehen?
Die Sprache des Friendica Interfaces kann durch den `lang` Parameter un der URL beeinflusst werden.
Das Argument des Parameters ist ein [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) Code.
Zwischen der URL und dem Parameter muss ein Fragezeichen als Trennzeichen verwendet werden.
Ein Beispiel:
https://social.example.com/profile/example
auf Deutsch:
https://social.example.com/profile/example?lang=de.
Wenn das Fragezeichen bereits in der URL verwendet wird, werden die einzelnen URL Parameter mit einem kaufmännischen Und getrennt werden.
Ein Beispiel:
https://social.example.com/profile/example?tab=profile
auf Deutsch:
https://social.example.com/profile/example?tab=profile&lang=de.
<a name="contacts"></a>
### Was ist der Unterschied zwischen blockierten|ignorierten|archivierten|versteckten Kontakten?
@ -162,7 +188,9 @@ Das bedeutet, dass du jeden Twitter/GNU Social Client verwenden kannst in dem du
Hier ist eine Liste von Clients bei denen dies möglich ist, bzw. die speziell für Friendica entwickelt werden:
* Android
* [Friendiqa](https://github.com/lubuwest/friendiqa) (Gibt es im Google Playstore oder als [binary Repository](https://freunde.ma-nic.de/display/3e98eba8185a13c5bdbf3d1539646854) für F-Droid)
* [Friendiqa](https://git.friendi.ca/lubuwest/Friendiqa) (Gibt es im Google Playstore oder als [binary Repository](https://freunde.ma-nic.de/display/3e98eba8185a13c5bdbf3d1539646854) für F-Droid)
* [Fedilab](https://gitlab.com/tom79/mastalab) (Gibt es im F-Droid und dem Google Play Store)
* [DiCa](https://dica.mixi.cool/) (Gibt es bei Google Play)
* AndStatus
* Twidere
* Mustard and Mustard-Mod
@ -199,7 +227,7 @@ Admin
Ja, das ist möglich.
Es ist allerdings nicht möglich, eine Datenbank durch zwei Domains zu nutzen.
Solange Du Deine config/local.ini.php allerdings so einrichtest, dass das System nicht versucht, eine Installation durchzuführen, kannst Du die richtige Config-Datei in include/$hostname/config/local.ini.php hinterlegen.
Solange Du Deine config/local.config.php allerdings so einrichtest, dass das System nicht versucht, eine Installation durchzuführen, kannst Du die richtige Config-Datei in include/$hostname/config/local.config.php hinterlegen.
Alle Cache-Aspekte und der Zugriffsschutz können pro Instanz konfiguriert werden.
<a name="sources"></a>
@ -216,13 +244,13 @@ Wenn Du neue Themen suchst, findest Du sie auf [Friendica-Themes.com](http://fri
<a name="adminaccount1"></a>
### Ich habe meine E-Mail Adresse geändern und jetzt ist das Admin Panel verschwunden?
Bitte aktualisiere deine E-Mail Adresse in der <tt>config/local.ini.php</tt> Datei.
Bitte aktualisiere deine E-Mail Adresse in der <tt>config/local.config.php</tt> Datei.
<a name="adminaccount2"></a>
### Kann es mehr als einen Admin auf einer Friendica Instanz geben?
Ja.
Du kannst in der <tt>config/local.ini.php</tt> Datei mehrere E-Mail Adressen auflisten.
Du kannst in der <tt>config/local.config.php</tt> Datei mehrere E-Mail Adressen auflisten.
Die aufgelisteten Adressen werden mit Kommata von einander getrennt.
<a name="dbupdate">

View file

@ -38,7 +38,7 @@ Du musst das nicht machen, die Alternative ist allerdings, Dich immer wieder aus
Und das kann umständlich sein, wenn Du mehrere verschiedene Foren/Identitäten verwaltest.
Du kannst ebenso jemanden wählen, der Dein Forum verwaltet.
Mach das, indem Du die [Delegations-Setup-Seite](/delegate) besuchst.
Mach das, indem Du die [Delegations-Setup-Seite](/settings/delegation) besuchst.
Dort wird Dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt.
Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, Dein Forum zu verwalten.
Sie können Kontakte, Profile und alle Inhalte Deines Accounts/deiner Seite bearbeiten.

View file

@ -34,7 +34,7 @@ Friendica - Dokumentation und Ressourcen
* [Konnektoren (Connectors) installieren (Twitter/GNU Social)](help/Installing-Connectors)
* [Installation eines ejabberd Servers (XMPP-Chat) mit synchronisierten Anmeldedaten](help/install-ejabberd) (EN)
* [Betreibe deine Seite mit einem SSL-Zertifikat](help/SSL)
* [Konfigurationswerte, die nur in der config/local.ini.php gesetzt werden können](help/Config) (EN)
* [Konfigurationswerte, die nur in der config/local.config.php gesetzt werden können](help/Config) (EN)
* [Performance verbessern](help/Improve-Performance)
* [Administration Werkzeuge](help/tools) (EN)

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.
@ -112,18 +112,18 @@ Bitte beachte jeden Fehler und korrigiere diese, bevor du fortfährst.
Falls du einen Port für die Datenbankverbindung angeben musst, kannst du diesen in der Host-Eingabe Zeile angeben.
*Wenn* die manuelle Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende:
* "config/local.ini.php" existiert ... wenn nicht, bearbeite die „config/local-sample.ini.php“ und ändere die Systemeinstellungen. Benenne sie um in „config/local.ini.php".
* "config/local.config.php" existiert ... wenn nicht, bearbeite die „config/local-sample.config.php“ und ändere die Systemeinstellungen. Benenne sie um in „config/local.config.php".
* die Datenbank beinhaltet Daten. ... wenn nicht, importiere den Inhalt der Datei "database.sql" mit phpmyadmin oder per mysql-Kommandozeile.
Besuche deine Seite an diesem Punkt wieder und registriere deinen persönlichen Account.
Alle Registrierungsprobleme sollten automatisch behebbar sein.
Wenn du irgendwelche **kritischen** Fehler zu diesen Zeitpunkt erhalten solltest, deutet das darauf hin, dass die Datenbank nicht korrekt installiert wurde.
Du kannst bei Bedarf die Datei config/local.ini.php verschieben/umbenennen und die Datenbank leeren (als „Dropping“ bezeichnet), so dass du mit einem sauberen System neu starten kannst.
Du kannst bei Bedarf die Datei config/local.config.php verschieben/umbenennen und die Datenbank leeren (als „Dropping“ bezeichnet), so dass du mit einem sauberen System neu starten kannst.
### Option B: Starte das automatische Installationsscript
Es existieren folgende Varianten zur automatischen Installation von Friendica:
- Eine vorgefertigte Konfigurationsdatei erstellen (z.B. `prepared.ini.php`)
- Eine vorgefertigte Konfigurationsdatei erstellen (z.B. `prepared.config.php`)
- Verwendung von Umgebungsvariablen (z.B. `MYSQL_HOST`)
- Verwendung von Optionen (z.B. `--dbhost <host>`)
@ -139,17 +139,17 @@ Falls du alle optionalen Checks ausfürehn lassen möchtest, benutze diese Optio
bin/console autoinstall -a
*Wenn* die automatisierte Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende:
* Existiert die `config/local.ini.php`? Falls ja, wird die automatisierte Installation nicht gestartet.
* Sind Einstellungen in der `config/local.ini.php` korrekt? Falls nicht, bitte bearbeite diese Datei erneut.
* Existiert die `config/local.config.php`? Falls ja, wird die automatisierte Installation nicht gestartet.
* Sind Einstellungen in der `config/local.config.php` korrekt? Falls nicht, bitte bearbeite diese Datei erneut.
* Ist die leere MySQL-Datenbank erstellt? Falls nicht, erstelle diese.
#### B.1: Konfigurationsdatei
Für diese Variante muss ein Konfigurationsdatei bereits vor der Installation fertig definiert sein (z.B. [local-sample.ini.php](config/local-sample.ini.php).
Für diese Variante muss ein Konfigurationsdatei bereits vor der Installation fertig definiert sein (z.B. [local-sample.config.php](config/local-sample.config.php).
Gehe im Anschluss in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus:
bin/console autoinstall -f <prepared.ini.php>
bin/console autoinstall -f <prepared.config.php>
#### B.2: Umgebungsvariablen
@ -161,7 +161,7 @@ Umgebungsvariablen können auch durch adäquate Optionen (z.B. `--dbhost <hostna
**Datenbank Einstellungen**
Nur wenn die Option `--savedb` gesetzt ist, werden diese Umgebungsvariablen auch in `config/local.ini.php` gespeichert!
Nur wenn die Option `--savedb` gesetzt ist, werden diese Umgebungsvariablen auch in `config/local.config.php` gespeichert!
- `MYSQL_HOST` Der Host der MySQL/MariaDB Datenbank
- `MYSQL_PORT` Der Port der MySQL/MariaDB Datenbank
@ -173,7 +173,7 @@ Nur wenn die Option `--savedb` gesetzt ist, werden diese Umgebungsvariablen auch
**Friendica Einstellungen**
Diese Umgebungsvariablen können nicht während des normalen Friendica Betriebs verwendet werden.
Sie werden stattdessen direkt in `config/local.ini.php` gespeichert.
Sie werden stattdessen direkt in `config/local.config.php` gespeichert.
- `FRIENDICA_PHP_PATH` Der Pfad zur PHP-Datei
- `FRIENDICA_ADMIN_MAIL` Die Admin E-Mail Adresse dieses Friendica Knotens (wird auch für den Admin-Zugang benötigt)
@ -186,7 +186,7 @@ Gehe im Anschluss in den Friendica-Hauptordner und führe den Kommandozeilen Bef
#### B.3: Optionen
Alle Optionen werden in `config/local.ini.php` gespeichert und überschreiben etwaige, zugehörige Umgebungsvariablen.
Alle Optionen werden in `config/local.config.php` gespeichert und überschreiben etwaige, zugehörige Umgebungsvariablen.
- `-H|--dbhost <host>` Der Host der MySQL/MariaDB Datenbank (env `MYSQL_HOST`)
- `-p|--dbport <port>` Der Port der MySQL/MariaDB Datenbank (env `MYSQL_PORT`)
@ -227,5 +227,5 @@ Es werden schlimme Dinge geschehen.
Sei es nun ein Hardwareversagen oder eine kaputte Datenbank.
Deshalb solltest du dir, nachdem die Installation deines Friendica Knotens abgeschlossen ist, einen Backup Plan erstellen.
Die wichtigste Datei ist die `config/local.ini.php` im Stammverzeichnis deiner Friendica Installation.
Die wichtigste Datei ist die `config/local.config.php` im Stammverzeichnis deiner Friendica Installation.
Und da alle Daten in der Datenbank gespeichert werden, solltest du einen nicht all zu alten Dump der Friendica Datenbank zur Hand haben, solltest du deinen Knoten wieder herstellen müssen.

View file

@ -18,7 +18,7 @@ Erweiterung müssen vom Administrator installiert werden, bevor sie genutzt werd
Dieses kann über das Administrationsmenü erstellt werden.
Jeder der Konnektoren benötigt zudem einen API-Schlüssel vom Service, der verbunden werden soll.
Einige Erweiterung erlaube es, diese Informationen auf den Administrationsseiten einzustellen, wohingegen andere eine direkte Bearbeitung der Konfigurationsdatei "config/local.ini.php" erfordern.
Einige Erweiterung erlaube es, diese Informationen auf den Administrationsseiten einzustellen, wohingegen andere eine direkte Bearbeitung der Konfigurationsdatei "config/local.config.php" erfordern.
Der Weg, um diese Schlüssel zu erhalten, variiert stark, jedoch brauchen fast alle einen bestehenden Account im gewünschten Service.
Einmal installiert, können diese Schlüssel von allen Seitennutzern genutzt werden.
@ -37,7 +37,7 @@ Um dieses Erweiterung zu nutzen, benötigst du einen OAuth Consumer-Schlüsselpa
Registriere deine Friendica-Seite als "Client"-Anwendung mit "Read&Write"-Zugriff. Wir benötigen "Twitter als Login" nicht. Sobald du deine Anwendung installiert hast, erhältst du das Schlüsselpaar für deine Seite.
Trage dieses Schlüsselpaar in deine globale "config/local.ini.php"-Datei ein.
Trage dieses Schlüsselpaar in deine globale "config/local.config.php"-Datei ein.
```
[twitter]

View file

@ -21,6 +21,6 @@ Solltest Du beim Stöbern durch die vielen Gruppen nicht wieder hierher zurück
Wenn Du einige Gruppen hinzugefügt hast, gehe <a href="help/Quick-Start-andfinally">weiter zum nächsten Schritt</a>.
<iframe src="https://dir.friendica.social/home" width="950" height="600"></iframe>
<iframe src="https://dir.friendica.social/forum" width="950" height="600"></iframe>

View file

@ -10,24 +10,14 @@ Wir freuen uns nicht, wenn Leute Friendica verlassen, aber wenn du deinen Accoun
in deinem Webbrowser. Du musst dabei eingeloggt sein.
Du wirst nach deinem Passwort gefragt, um die Anfrage zu bestätigen.
Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account sofort gelöscht.
Anders als andere Netzwerke, behalten wir die Daten **nicht** für eine gewisse Zeit, falls du deine Meinung noch änderst.
Deine Nutzerdetails, deine Unterhaltungen, deine Photos, deine Freunde - alles; wird sofort gelöscht und du wirst ausgeloggt.
Wenn dieses mit deinem gespeichertem Passwort übereinstimmt, dann wird dein Account als "gelöscht" markiert.
Dies passiert sofort und kann nicht rückgängig gemacht werden.
Die meisten Deiner Inhalte und Benutzerdaten werden kurzfristig danach durch Hintergrundprozesse gelöscht.
Wenn Beiträge ablaufen, schicken wir Mitteilungen an Friendica, um diese zu löschen.
Diaspora hat keine automatische Löschfunktion, so dass diese Funktion in dem Netzwerk deaktiviert ist.
Und hoffentlich ist klar, dass das Löschen auch in anderen Netzwerken nicht funktioniert.
Wenn du manuell einen Beitrag bzw. eine Reihe von Beiträgen löschst, dann senden wir individuelle Mitteilungen zu Friendica und Diaspora für jeden gelöschten Post.
Parallel dazu senden wir eine Mitteilung an die Server deiner Kontakte, damit sie deine dort vorliegenden Daten ebenfalls löschen.
Wir haben keinen Einfluss darauf, wie sorgfältig und ob überhaupt diese Systeme der Löschaufforderung nachgehen.
Diaspora versäumt dieses oft.
Aus technischen Gründen benötigen wir für die Übetragung dieser Mitteilung ein paar Benutzerdaten.
Diese Daten werden dann nach einer Frist von etwa sieben Tagen ebenfalls gelöscht.
Wenn du einen Beitrag löscht, aber jemand diesem Beitrag folgt, wird es trotzdem gelöscht.
Dein Wunsch hat Priorität.
Wenn du deinen Account löscht, dann löschen wir alle Beiträge, dein Profil, die Nutzerdaten etc. sofort.
Um einen Gesamtlöschauftrag zu versenden, bräuchten wir zunächst noch deinen Account; auch, um deinen Freunden zu zeigen, wer diese Anfrage stellt.
Das können wir nicht tun, wenn du keinen Account mehr hast.
Deine Freunde können möglicherweise noch deine Beiträge sehen, wenn dein Account gelöscht wurde, aber es gibt keinen öffentlichen Ort in Friendica mehr, wo diese angeschaut werden können.
Wenn du Freunde bei Diaspora hast, kann es sein, dass deine Beiträge weiterhin vorhanden und für andere aus diesem Netzwerk sichtbar sind.
Wir speichern deinen Benutzernamen dauerhaft, damit sich niemand einen Account unter deinem Spitznamen anlegen kann.

View file

@ -12,7 +12,7 @@ Die zweite Zahl steht für die Anzahl der Aufgaben, die die Worker noch vor sich
Die Worker arbeiten Hintergrundprozesse ab.
Die Aufgaben der Worker sind priorisiert und werden anhand dieser Prioritäten abgearbeitet.
Desweiteren findest du eine Übersicht über die Accounts auf dem Friendica Knoten, die unter dem Punkt "Nutzer" moderiert werden können.
Des weiteren findest du eine Übersicht über die Accounts auf dem Friendica Knoten, die unter dem Punkt "Nutzer" moderiert werden können.
Sowie eine Liste der derzeit aktivierten Addons.
Diese Liste ist verlinkt, so dass du schnellen Zugriff auf die Informationsseiten der einzelnen Addons hast.
Abschließend findest du auf der Startseite des Admin Panels die installierte Version von Friendica.
@ -47,7 +47,7 @@ Mehr Informationen zum Übersetzungsprozess von Friendica findest du [auf dieser
Hier kann das Theme bestimmt werden, welches standardmäßig zum Anzeigen der Seite verwendet werden soll.
Nutzer können in ihren Einstellungen andere Themes wählen.
Derzeit ist das "duepunto zero" Theme das vorausgewählte Theme.
Derzeit ist das "vier" Theme das vorausgewählte Theme.
Für mobile Geräte kannst du ein spezielles Theme wählen, wenn das Standardtheme ungeeignet für mobile Geräte sein sollte.
Das `vier` Theme z.B. unterstützt kleine Anzeigen und benötigt kein zusätzliches mobiles Theme.
@ -66,7 +66,7 @@ Dabei kannst du zwischen den folgenden Optionen wählen:
##### Einladungen
Zusätzlich zu den oben genannten Möglichkeiten, kann die Registrierung eines neuen Nutzerkontos an eine Einladung durch einen bestehenden Nutzer gekoppelt werden.
Hierzu muss in der [config/local.ini.php](/help/Config) Datei die Option `invitation_only` aktiviert und als Registrierungsmethode entweder *Offen* oder *Bedarf der Zustimmung* gewählt werden.
Hierzu muss in der [config/local.config.php](/help/Config) Datei die Option `invitation_only` aktiviert und als Registrierungsmethode entweder *Offen* oder *Bedarf der Zustimmung* gewählt werden.
#### Namen auf Vollständigkeit überprüfen
@ -92,6 +92,32 @@ Standardmäßig ist hier "false" gesetzt.
### Datei hochladen
#### Datenspeicher Backend
Legt das Datenspeicher Backend fest, mit dem Friendica hoch geladene Daten speichert.
Zwei Speicher Backends sind standardmäßig bei Friendica verfügbar:
- **Database** : Die Daten werden in einer speziellen Tabelle in der Datenbank (`storage`) gespeichert.
- **Filesystem** : Die Daten werden als Dateien im Dateisystem gespeichert.
Weitere Speicher Backends können als Addons von Drittanbietern verfügbar sein.
Falls ein solches verwendet wird, sei an dieser Stelle nur auf deren Dokumentation für weitere Informationen verwiesen.
Die Grundeinstellung ist 'Datenbank (legacy)': Dies ist die alte Methode von Friendica Daten direkt in der Datenbank abzulegen.
Bestehende Daten können zum aktuell ausgewählten Backend verschoben werden.
Hierfür kann der ['storage move'](help/tools) Befehl der Friendica Konsole verwendet werden.
Sollte das ausgewählte Speicher Backand zusätzliche Konfigurationsparameter besitzen, werden nach der Auswahl des Backends hier weitere Felder angezeigt.
##### Dateipfad zum Speicher
Der Basispfad unter dem das Filesystem Datenspeicher Backend die Daten speichern soll.
Um zu verhindern, dass Daten unter Umgehung der Privatsphären-Einstellungen herunter geladen werden, sollte dieser Pfad außerhalb der Verzeichnisstruktur des Webservers liegen.
Die Grundeinstellung ist `storage`, das ist das `storage` Unterverzeichnis innerhalb des Friendica Verzeichnisses.
#### Maximale Bildgröße
Maximale Bild-Dateigröße in Byte. Standardmäßig ist 0 gesetzt, was bedeutet, dass kein Limit gesetzt ist.
@ -134,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.
@ -142,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
@ -313,7 +339,7 @@ Du solltest deshalb einen Dienst zur [log rotation](https://en.wikipedia.org/wik
**Bekannte Probleme**: Der Dateiname `friendica.log` kann bei speziellen Server Konfigurationen zu Problemen führen (siehe [issue 2209](https://github.com/friendica/friendica/issues/2209)).
Normalerweise werden Fehler- und Warnmeldungen von PHP unterdrückt.
Wenn du sie aktivieren willst, musst du folgendes in der `config/local.ini.php` Datei eintragen um die Meldungen in die Datei `php.out` zu speichern
Wenn du sie aktivieren willst, musst du folgendes in der `config/local.config.php` Datei eintragen um die Meldungen in die Datei `php.out` zu speichern
error_reporting(E_ERROR | E_WARNING | E_PARSE );
ini_set('error_log','php.out');
@ -347,18 +373,21 @@ Dies sind die Datenbank Einstellungen, die Administrator Accounts, der PHP Pfad
Mit den folgenden Einstellungen kannst du die Zugriffsdaten für den Datenbank Server festlegen.
$db_host = 'your.db.host';
$db_user = 'db_username';
$db_pass = 'db_password';
$db_data = 'database_name';
'database' => [
'hostname' => 'localhost',
'username' => 'mysqlusername',
'password' => 'mysqlpassword',
'database' => 'mysqldatabasename',
'charset' => 'utf8mb4',
],
Sollten alle der folgenden Environment-Variablen gesetzt sein, wird Friendica diese anstatt der vorher konfigurierten Werte nutzen.
MYSQL_HOST
MYSQL_PORT
MYSQL_USERNAME
MYSQL_PASSWORD
MYSQL_DATABASE
MYSQL_HOST
MYSQL_PORT
MYSQL_USERNAME
MYSQL_PASSWORD
MYSQL_DATABASE
## Administratoren
@ -367,16 +396,18 @@ Normalerweise trifft dies auf den ersten Account zu, der nach der Installation a
Die Liste der E-Mail Adressen kann aber einfach erweitert werden.
Mit keiner der angegebenen E-Mail Adressen können weitere Accounts registriert werden.
[config]
admin_email = you@example.com, buddy@example.com
'config' => [
'admin_email' => 'you@example.com, buddy@example.com',
],
## PHP Pfad
Einige Prozesse von Friendica laufen im Hintergrund.
Für diese Prozesse muss der Pfad zu der PHP Version gesetzt sein, die verwendet werden soll.
[config]
php_path = {{$phpath}}
'config' => [
'php_path' => '/usr/bin/php',
],
## Unterverzeichnis Konfiguration
@ -384,10 +415,11 @@ Man kann Friendica in ein Unterverzeichnis des Webservers installieren.
Wir raten allerdings dringen davon ab, da es die Interoperabilität mit anderen Netzwerken (z.B. Diaspora, GNU Social, Hubzilla) verhindert.
Mal angenommen, du hast ein Unterverzeichnis tests und willst Friendica in ein weiteres Unterverzeichnis installieren, dann lautet die Konfiguration hierfür:
[system]
urlpath = tests/friendica
'system' => [
'urlpath' => 'tests/friendica',
],
## Weitere Ausnahmen
Es gibt noch einige experimentelle Einstellungen, die nur in der ``config/local.ini.php`` Datei konfiguriert werden können.
Im [Konfigurationswerte, die nur in der config/local.ini.php gesetzt werden können (EN)](help/Config) Artikel kannst du mehr darüber erfahren.
Es gibt noch einige experimentelle Einstellungen, die nur in der ``config/local.config.php`` Datei konfiguriert werden können.
Im [Konfigurationswerte, die nur in der config/local.config.php gesetzt werden können (EN)](help/Config) Artikel kannst du mehr darüber erfahren.

View file

@ -8,7 +8,7 @@
To get the Doxygen API Documentation you must render it with the program <a href="http://www.doxygen.org">Doxygen</a> (included in most distributions).
<pre>
$ doxygen util/Doxyfile
$ doxygen Doxyfile
</pre>
<br>
<a href="javascript:history.back()">back</a>

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

View file

@ -20,10 +20,10 @@ Templates that are only used by addons shall be placed in the
directory.
To render a template use the function *get_markup_template* to load the template and *replace_macros* to replace the macros/variables in the just loaded template file.
To render a template use the function *getMarkupTemplate* to load the template and *replaceMacros* to replace the macros/variables in the just loaded template file.
$tpl = get_markup_template('install_settings.tpl');
$o .= replace_macros($tpl, array( ... ));
$tpl = Renderer::getMarkupTemplate('install_settings.tpl');
$o .= Renderer::replaceMacros($tpl, array( ... ));
the array consists of an association of an identifier and the value for that identifier, i.e.
@ -177,6 +177,7 @@ Field parameter:
1. Label for the input box,
2. Current text for the box,
3. Help text for the input box.
4. if set to "required" modern browser will check that this input box is filled when submitting the form,
### field_yesno.tpl

View file

@ -181,13 +181,13 @@ Next take the default.php file found in the /view direcotry and exchange the asi
So the central part of the file now looks like this:
<body>
<?php if(x($page,'nav')) echo $page['nav']; ?>
<aside><?php if(x($page,'right_aside')) echo $page['right_aside']; ?></aside>
<section><?php if(x($page,'content')) echo $page['content']; ?>
<?php if(!empty($page['nav'])) echo $page['nav']; ?>
<aside><?php if(!empty($page['right_aside'])) echo $page['right_aside']; ?></aside>
<section><?php if(!empty($page['content'])) echo $page['content']; ?>
<div id="page-footer"></div>
</section>
<right_aside><?php if(x($page,'aside')) echo $page['aside']; ?></right_aside>
<footer><?php if(x($page,'footer')) echo $page['footer']; ?></footer>
<right_aside><?php if(!empty($page['aside'])) echo $page['aside']; ?></right_aside>
<footer><?php if(!empty($page['footer'])) echo $page['footer']; ?></footer>
</body>
Finally we need a style.css file, inheriting the definitions from the parent theme and containing out changes for the new theme.

View file

@ -9,6 +9,7 @@ Friendica Tools
Friendica has a build in command console you can find in the *bin* directory.
The console provides the following commands:
* cache: Manage node cache
* config: Edit site config
* createdoxygen: Generate Doxygen headers
* dbstructure: Do database updates
@ -24,6 +25,8 @@ The console provides the following commands:
* php2po: Generate a messages.po file from a strings.php file
* po2php: Generate a strings.php file from a messages.po file
* typo: Checks for parse errors in Friendica files
* postupdate: Execute pending post update scripts (can last days)
* storage: Manage storage backend
Please consult *bin/console help* on the command line interface of your server for details about the commands.
@ -53,7 +56,7 @@ In */etc/fail2ban/jail.local* create a section for Friendica:
And create a filter definition in */etc/fail2ban/filter.d/friendica.conf*:
[Definition]
failregex = ^.*Login\.php.*failed login attempt.*from IP <HOST>.*$
failregex = ^.*authenticate\: failed login attempt.*\"ip\"\:\"<HOST>\".*$
ignoreregex =
Additionally you have to define the number of failed logins before the ban should be activated.

View file

@ -3,78 +3,52 @@ Friendica translations
* [Home](help)
Translation Process
-------------------
## Overview
The strings used in the UI of Friendica are translated at [Transifex] [1] and then included in the git repository at github.
If you want to help with translation for any language, be it correcting terms or translating friendica to a currently not supported language, please register an account at transifex.com and contact the friendica translation team there.
The Friendica translation process is based on `gettext` PO files.
Translating friendica is simple.
Just use the online tool at transifex.
If you don't want to deal with git & co. that is fine, we check the status of the translations regularly and import them into the source tree at github so that others can use them.
Basic worflow:
1. `xgettext` is used to collect translation strings across the project in the master PO file located in `view/lang/C/messages.po`.
2. This file makes translations strings available at [the Transifex Friendica page](https://www.transifex.com/Friendica/friendica/dashboard/).
3. The translation itself is done at Transifex by volunteers.
4. The resulting PO files by languages are manually updated in `view/lang/<language>/messages.po`.
5. PO files are converted to PHP arrays in `view/lang/<language>/strings.php` that are ultimately used by Friendica to display the translations.
We do not include every translation from transifex in the source tree to avoid a scattered and disturbed overall experience.
As an uneducated guess we have a lower limit of 50% translated strings before we include the language (for the core messages.po file, addont translation will be included once all strings of an addon are translated.
This limit is judging only by the amount of translated strings under the assumption that the most prominent strings for the UI will be translated first by a translation team.
If you feel your translation useable before this limit, please contact us and we will probably include your teams work in the source tree.
## Translate Friendica in your favorite language
If you want to help translating, please concentrate on the core messages.po file first.
We will only include translations with a sufficient translated messages.po file.
Translations of addons will only be included, when the core file is included as well.
Thank you for your interest in improving Friendica's translation!
Please register a free Transifex account and ask over at [the Transifex Friendica page](https://www.transifex.com/Friendica/friendica/dashboard/) to join the translation team for your favorite language.
If you want to get your work into the source tree yourself, feel free to do so and contact us with and questions that arise.
The process is simple and friendica ships with all the tools necessary.
As a rule of thumb, we add support for a language in Friendica when at least 50% of the strings have been translated to avoid a scattered experience.
For addons, we add support for a language when if we already support the language in Friendica.
The location of the translated files in the source tree is
/view/lang/LNG-CODE/
where LNG-CODE is the language code used, e.g. de for German or fr for French.
The translated strings come as a "message.po" file from transifex which needs to be translated into the PHP file friendica uses.
To do so, place the file in the directory mentioned above and use the "po2php" command from the Friendica Console.
## Add new translation strings
Assuming you want to convert the German localization which is placed in view/lang/de/message.po you would do the following.
### Core
1. Navigate at the command prompt to the base directory of your
friendica installation
Once you have added new translation strings in your code changes, please run `bin/run_xgettext.sh` from the base Friendica directory and commit the updated `view/lang/C/messages.po` to your branch.
2. Execute the po2php command, which will place the translation
in the strings.php file that is used by friendica.
### Addon
$> php bin/console.php po2php view/lang/de/messages.po
If you have the `friendica-addons` repository in the `addon` directory of your Friendica cloned repository, just run `bin/run_xgettext.sh -a <addon_name>` from the base Friendica directory.
The output of the script will be placed at view/lang/de/strings.php where
friendica is expecting it, so you can test your translation immediately.
*Please note that the console tool has to be called from the base directory of your Friendica installation.*
Otherwise:
3. Visit your friendica page to check if it still works in the language you
just translated. If not try to find the error, most likely PHP will give
you a hint in the log/warnings.about the error.
cd /path/to/friendica-addons/<addon_name>
/path/to/friendica/bin/run_xgettext.sh -s
For debugging you can also try to "run" the file with PHP. This should
not give any output if the file is ok but might give a hint for
searching the bug in the file.
In either case, you need to commit the updated `<addon_name>/lang/C/messages.po` to your working branch.
$> php view/lang/de/strings.php
## Update translations from Transifex
4. commit the two files with a meaningful commit message to your git
repository, push it to your fork of the friendica repository at github and
issue a pull request for that commit.
Please download the Transifex file "for use" in `view/lang/<language>/messages.po`.
You should translate the PO files at Transifex.
Otherwise your work might get lost, when the translation from Transifex is included to the Friendica repository after it was updated there.
Then run `bin/console po2php view/lang/<language>/messages.po` to update the related `strings.php` file and commit both files to your working branch.
Utilities
---------
### Using the Transifex client
Additional to the po2php command there are some more utilities for translation in the console.
If you only want to translate friendica into another language you wont need any of these tools most likely but it gives you an idea how the translation process of friendica works.
For further information see the utils/README file.
Transifex-Client
----------------
Transifex has a client program which let you interact with the translation files in a similar way to git.
Help for the client can be found at the [Transifex Help Center] [2].
Transifex has a client program which allows you to sync files between your cloned Friendica repository and Transifex.
Help for the client can be found at the [Transifex Help Center](https://docs.transifex.com/client/introduction).
Here we will only cover basic usage.
After installation of the client, you should have a `tx` command available on your system.
@ -88,17 +62,25 @@ The content of the file should be something like the following:
password = p@ssw0rd
hostname = https://www.transifex.com
Since Friendica version 3.5.1 we ship configuration files for the Transifex client in the core repository and the addon repository.
To update the translation files after you have translated strings of e.g. Esperanto in the web-UI of transifex you can use `tx` to download the file.
Since Friendica version 3.5.1 we ship configuration files for the Transifex client in the core repository and the addon repository in `.tx/config`.
To update the PO files after you have translated strings of e.g. Esperanto on the Transifex website you can use `tx` to download the updated PO file in the right location.
$> tx pull -l eo
And then use the `po2php` command described above to convert the `messages.po` file to the `strings.php` file Friendica is loading.
Then run `bin/console po2php view/lang/<language>/messages.po` to update the related `strings.php` file and commit both files to your working branch.
$> php bin/console.php po2php view/lang/eo/messages.po
## Translation functions usage
Afterwards, just commit the two changed files to a feature branch of your Friendica repository, push the changes to github and open a pull request for your changes.
### Basic usage
[1]: https://www.transifex.com/projects/p/friendica/
[2]: https://docs.transifex.com/client/introduction
- `Friendica\Core\L10n::t('Label')` => `Label`
- `Friendica\Core\L10n::t('Label %s', 'test')` => `Label test`
### Plural
- `Friendica\Core\L10n::tt('Label', 'Labels', 1)` => `Label`
- `Friendica\Core\L10n::tt('Label', 'Labels', 3)` => `Labels`
- `Friendica\Core\L10n::tt('%d Label', '%d Labels', 1)` => `1 Label`
- `Friendica\Core\L10n::tt('%d Label', '%d Labels', 3)` => `3 Labels`
- `Friendica\Core\L10n::tt('%d Label', 'Labels %2%s %3%s', 1, 'test', 'test2')` => `Label test test2`
- `Friendica\Core\L10n::tt('%d Label', 'Labels %2%s %3%s', 3, 'test', 'test2')` => `Labels test test2`

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

File diff suppressed because it is too large Load diff

View file

@ -8,11 +8,14 @@ use Friendica\Content\ContactSelector;
use Friendica\Content\Feature;
use Friendica\Content\Pager;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Addon;
use Friendica\Core\Config;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
@ -24,7 +27,9 @@ use Friendica\Object\Thread;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Temporal;
use Friendica\Util\Strings;
use Friendica\Util\XML;
use Friendica\Util\Crypto;
function item_extract_images($body) {
@ -113,6 +118,10 @@ function item_redir_and_replace_images($body, $images, $cid) {
/**
* Render actions localized
*
* @param $item
* @throws ImagickException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function localize_item(&$item)
{
@ -168,6 +177,7 @@ function localize_item(&$item)
$plink = '[url=' . $obj['plink'] . ']' . $post_type . '[/url]';
$bodyverb = '';
if (activity_match($item['verb'], ACTIVITY_LIKE)) {
$bodyverb = L10n::t('%1$s likes %2$s\'s %3$s');
} elseif (activity_match($item['verb'], ACTIVITY_DISLIKE)) {
@ -193,7 +203,7 @@ function localize_item(&$item)
$xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">";
$obj = XML::parseString($xmlhead.$item['object']);
$links = XML::parseString($xmlhead."<links>".unxmlify($obj->link)."</links>");
$links = XML::parseString($xmlhead."<links>".XML::unescape($obj->link)."</links>");
$Bname = $obj->title;
$Blink = "";
@ -201,8 +211,8 @@ function localize_item(&$item)
foreach ($links->link as $l) {
$atts = $l->attributes();
switch ($atts['rel']) {
case "alternate": $Blink = $atts['href'];
case "photo": $Bphoto = $atts['href'];
case "alternate": $Blink = $atts['href']; break;
case "photo": $Bphoto = $atts['href']; break;
}
}
@ -355,14 +365,16 @@ function localize_item(&$item)
'network' => $item['author-network'], 'url' => $item['author-link']];
// Only create a redirection to a magic link when logged in
if (!empty($item['plink']) && (local_user() || remote_user())) {
$item['plink'] = Contact::magicLinkbyContact($author, $item['plink']);
if (!empty($item['plink']) && Session::isAuthenticated()) {
$item['plink'] = Contact::magicLinkByContact($author, $item['plink']);
}
}
/**
* Count the total of comments on this item and its desendants
* @TODO proper type-hint + doc-tag
* @param $item
* @return int
*/
function count_descendants($item) {
$total = count($item['children']);
@ -385,7 +397,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];
$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;
@ -432,7 +444,17 @@ function conv_get_blocklist()
* The $mode parameter decides between the various renderings and also
* figures out how to determine page owner and other contextual items
* that are based on unique features of the calling module.
*
* @param App $a
* @param array $items
* @param Pager $pager
* @param $mode
* @param $update
* @param bool $preview
* @param string $order
* @param int $uid
* @return string
* @throws ImagickException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function conversation(App $a, array $items, Pager $pager, $mode, $update, $preview = false, $order = 'commented', $uid = 0)
{
@ -458,17 +480,17 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
. "<script> var profile_uid = " . $_SESSION['uid']
. "; var netargs = '" . substr($a->cmd, 8)
. '?f='
. ((x($_GET, 'cid')) ? '&cid=' . $_GET['cid'] : '')
. ((x($_GET, 'search')) ? '&search=' . $_GET['search'] : '')
. ((x($_GET, 'star')) ? '&star=' . $_GET['star'] : '')
. ((x($_GET, 'order')) ? '&order=' . $_GET['order'] : '')
. ((x($_GET, 'bmark')) ? '&bmark=' . $_GET['bmark'] : '')
. ((x($_GET, 'liked')) ? '&liked=' . $_GET['liked'] : '')
. ((x($_GET, 'conv')) ? '&conv=' . $_GET['conv'] : '')
. ((x($_GET, 'nets')) ? '&nets=' . $_GET['nets'] : '')
. ((x($_GET, 'cmin')) ? '&cmin=' . $_GET['cmin'] : '')
. ((x($_GET, 'cmax')) ? '&cmax=' . $_GET['cmax'] : '')
. ((x($_GET, 'file')) ? '&file=' . $_GET['file'] : '')
. (!empty($_GET['cid']) ? '&cid=' . rawurlencode($_GET['cid']) : '')
. (!empty($_GET['search']) ? '&search=' . rawurlencode($_GET['search']) : '')
. (!empty($_GET['star']) ? '&star=' . rawurlencode($_GET['star']) : '')
. (!empty($_GET['order']) ? '&order=' . rawurlencode($_GET['order']) : '')
. (!empty($_GET['bmark']) ? '&bmark=' . rawurlencode($_GET['bmark']) : '')
. (!empty($_GET['liked']) ? '&liked=' . rawurlencode($_GET['liked']) : '')
. (!empty($_GET['conv']) ? '&conv=' . rawurlencode($_GET['conv']) : '')
. (!empty($_GET['nets']) ? '&nets=' . rawurlencode($_GET['nets']) : '')
. (!empty($_GET['cmin']) ? '&cmin=' . rawurlencode($_GET['cmin']) : '')
. (!empty($_GET['cmax']) ? '&cmax=' . rawurlencode($_GET['cmax']) : '')
. (!empty($_GET['file']) ? '&file=' . rawurlencode($_GET['file']) : '')
. "'; var profile_page = " . $pager->getPage() . "; </script>\r\n";
}
@ -478,8 +500,8 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
if (!$update) {
$tab = 'posts';
if (x($_GET, 'tab')) {
$tab = notags(trim($_GET['tab']));
if (!empty($_GET['tab'])) {
$tab = Strings::escapeTags(trim($_GET['tab']));
}
if ($tab === 'posts') {
/*
@ -493,7 +515,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
}
}
} elseif ($mode === 'notes') {
$items = conversation_add_children($items, false, $order, $uid);
$items = conversation_add_children($items, false, $order, local_user());
$profile_owner = local_user();
if (!$update) {
@ -507,7 +529,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
if (!$update) {
$live_update_div = '<div id="live-display"></div>' . "\r\n"
. "<script> var profile_uid = " . defaults($_SESSION, 'uid', 0) . ";"
. "<script> var profile_uid = " . Session::get('uid', 0) . ";"
. " var profile_page = 1; </script>";
}
} elseif ($mode === 'community') {
@ -520,7 +542,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
."/?f='; var profile_page = " . $pager->getPage() . "; </script>\r\n";
}
} elseif ($mode === 'contacts') {
$items = conversation_add_children($items, true, $order, $uid);
$items = conversation_add_children($items, false, $order, $uid);
$profile_owner = 0;
if (!$update) {
@ -539,26 +561,30 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
}
$cb = ['items' => $items, 'mode' => $mode, 'update' => $update, 'preview' => $preview];
Addon::callHooks('conversation_start',$cb);
Hook::callAll('conversation_start',$cb);
$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)
$threads = [];
$threadsid = -1;
$page_template = get_markup_template("conversation.tpl");
$page_template = Renderer::getMarkupTemplate("conversation.tpl");
if (!empty($items)) {
if (in_array($mode, ['community', 'contacts'])) {
$writable = true;
} else {
$writable = ($items[0]['uid'] == 0) && in_array($items[0]['network'], [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN]);
$writable = ($items[0]['uid'] == 0) && in_array($items[0]['network'], Protocol::FEDERATED);
}
if (!local_user()) {
@ -604,14 +630,14 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
$author = ['uid' => 0, 'id' => $item['author-id'],
'network' => $item['author-network'], 'url' => $item['author-link']];
$profile_link = Contact::magicLinkbyContact($author);
$profile_link = Contact::magicLinkByContact($author);
if (strpos($profile_link, 'redir/') === 0) {
$sparkle = ' sparkle';
}
$locate = ['location' => $item['location'], 'coord' => $item['coord'], 'html' => ''];
Addon::callHooks('render_location',$locate);
Hook::callAll('render_location',$locate);
$location = ((strlen($locate['html'])) ? $locate['html'] : render_location_dummy($locate));
@ -635,58 +661,51 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
$lock = false;
$likebuttons = false;
$body = prepare_body($item, true, $preview);
$body = Item::prepareBody($item, true, $preview);
list($categories, $folders) = get_cats_and_terms($item);
$profile_name_e = $profile_name;
if (!empty($item['content-warning']) && PConfig::get(local_user(), 'system', 'disable_cw', false)) {
$title_e = ucfirst($item['content-warning']);
$title = ucfirst($item['content-warning']);
} else {
$title_e = $item['title'];
$title = $item['title'];
}
$body_e = $body;
$tags_e = $tags['tags'];
$hashtags_e = $tags['hashtags'];
$mentions_e = $tags['mentions'];
$location_e = $location;
$owner_name_e = $owner_name;
$tmp_item = [
'template' => $tpl,
'id' => ($preview ? 'P0' : $item['id']),
'guid' => ($preview ? 'Q0' : $item['guid']),
'network' => $item['network'],
'network_name' => ContactSelector::networkToName($item['network'], $item['author-link']),
'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link']),
'linktitle' => L10n::t('View %s\'s profile @ %s', $profile_name, $item['author-link']),
'profile_url' => $profile_link,
'item_photo_menu' => item_photo_menu($item),
'name' => $profile_name_e,
'name' => $profile_name,
'sparkle' => $sparkle,
'lock' => $lock,
'thumb' => System::removedBaseUrl(ProxyUtils::proxifyUrl($item['author-avatar'], false, ProxyUtils::SIZE_THUMB)),
'title' => $title_e,
'body' => $body_e,
'tags' => $tags_e,
'hashtags' => $hashtags_e,
'mentions' => $mentions_e,
'title' => $title,
'body' => $body,
'tags' => $tags['tags'],
'hashtags' => $tags['hashtags'],
'mentions' => $tags['mentions'],
'implicit_mentions' => $tags['implicit_mentions'],
'txt_cats' => L10n::t('Categories:'),
'txt_folders' => L10n::t('Filed under:'),
'has_cats' => ((count($categories)) ? 'true' : ''),
'has_folders' => ((count($folders)) ? 'true' : ''),
'categories' => $categories,
'folders' => $folders,
'text' => strip_tags($body_e),
'text' => strip_tags($body),
'localtime' => DateTimeFormat::local($item['created'], 'r'),
'ago' => (($item['app']) ? L10n::t('%s from %s', Temporal::getRelativeDate($item['created']),$item['app']) : Temporal::getRelativeDate($item['created'])),
'location' => $location_e,
'location' => $location,
'indent' => '',
'owner_name' => $owner_name_e,
'owner_name' => $owner_name,
'owner_url' => $owner_url,
'owner_photo' => System::removedBaseUrl(ProxyUtils::proxifyUrl($item['owner-avatar'], false, ProxyUtils::SIZE_THUMB)),
'plink' => get_plink($item),
'plink' => Item::getPlink($item),
'edpost' => false,
'isstarred' => $isstarred,
'star' => $star,
@ -702,7 +721,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
];
$arr = ['item' => $item, 'output' => $tmp_item];
Addon::callHooks('display_item', $arr);
Hook::callAll('display_item', $arr);
$threads[$threadsid]['id'] = $item['id'];
$threads[$threadsid]['network'] = $item['network'];
@ -711,7 +730,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
}
} else {
// Normal View
$page_template = get_markup_template("threaded_conversation.tpl");
$page_template = Renderer::getMarkupTemplate("threaded_conversation.tpl");
$conv = new Thread($mode, $preview, $writable);
@ -739,7 +758,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
/// @todo Check if this call is needed or not
$arr = ['item' => $item];
Addon::callHooks('display_item', $arr);
Hook::callAll('display_item', $arr);
$item['pagedrop'] = $page_dropping;
@ -751,13 +770,13 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
$threads = $conv->getTemplateData($conv_responses);
if (!$threads) {
logger('[ERROR] conversation : Failed to get template data.', LOGGER_DEBUG);
Logger::log('[ERROR] conversation : Failed to get template data.', Logger::DEBUG);
$threads = [];
}
}
}
$o = replace_macros($page_template, [
$o = Renderer::replaceMacros($page_template, [
'$baseurl' => System::baseUrl($ssl_state),
'$return_path' => $a->query_string,
'$live_update' => $live_update_div,
@ -765,12 +784,52 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
'$mode' => $mode,
'$user' => $a->user,
'$threads' => $threads,
'$dropping' => ($page_dropping && Feature::isEnabled(local_user(), 'multi_delete') ? L10n::t('Delete Selected Items') : False),
'$dropping' => ($page_dropping ? L10n::t('Delete Selected Items') : False),
]);
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 = [];
$received = '';
while ($row = Item::fetch($thread_items)) {
if (($row['verb'] == ACTIVITY2_ANNOUNCE) && !empty($row['contact-uid']) && ($row['received'] > $received) && ($row['thr-parent'] == $row['parent-uri'])) {
$actor = ['link' => $row['author-link'], 'avatar' => $row['author-avatar'], 'name' => $row['author-name']];
$received = $row['received'];
}
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
*
@ -779,7 +838,11 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ
*
* @param array $parents Parent items
*
* @param $block_authors
* @param $order
* @param $uid
* @return array items with parents and comments
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function conversation_add_children(array $parents, $block_authors, $order, $uid) {
$max_comments = Config::get('system', 'max_comments', 100);
@ -794,13 +857,14 @@ function conversation_add_children(array $parents, $block_authors, $order, $uid)
foreach ($parents AS $parent) {
$condition = ["`item`.`parent-uri` = ? AND `item`.`uid` IN (0, ?) ",
$parent['uri'], local_user()];
$parent['uri'], $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);
@ -809,7 +873,7 @@ function conversation_add_children(array $parents, $block_authors, $order, $uid)
foreach ($items as $index => $item) {
if ($item['uid'] == 0) {
$items[$index]['writable'] = in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN]);
$items[$index]['writable'] = in_array($item['network'], Protocol::FEDERATED);
}
}
@ -826,6 +890,8 @@ function item_photo_menu($item) {
$status_link = '';
$photos_link = '';
$posts_link = '';
$block_link = '';
$ignore_link = '';
if (local_user() && local_user() == $item['uid'] && $item['parent'] == $item['id'] && !$item['self']) {
$sub_link = 'javascript:dosubthread(' . $item['id'] . '); return false;';
@ -833,13 +899,14 @@ function item_photo_menu($item) {
$author = ['uid' => 0, 'id' => $item['author-id'],
'network' => $item['author-network'], 'url' => $item['author-link']];
$profile_link = Contact::magicLinkbyContact($author);
$profile_link = Contact::magicLinkByContact($author, $item['author-link']);
$sparkle = (strpos($profile_link, 'redir/') === 0);
$cid = 0;
$pcid = Contact::getIdForURL($item['author-link'], 0, true);
$network = '';
$rel = 0;
$condition = ['uid' => local_user(), 'nurl' => normalise_link($item['author-link'])];
$condition = ['uid' => local_user(), 'nurl' => Strings::normaliseLink($item['author-link'])];
$contact = DBA::selectFirst('contact', ['id', 'network', 'rel'], $condition);
if (DBA::isResult($contact)) {
$cid = $contact['id'];
@ -848,9 +915,16 @@ function item_photo_menu($item) {
}
if ($sparkle) {
$status_link = $profile_link . '?url=status';
$photos_link = $profile_link . '?url=photos';
$profile_link = $profile_link . '?url=profile';
$status_link = $profile_link . '?tab=status';
$photos_link = str_replace('/profile/', '/photos/', $profile_link);
$profile_link = $profile_link . '?=profile';
}
if (!empty($pcid)) {
$contact_url = 'contact/' . $pcid;
$posts_link = 'contact/' . $pcid . '/posts';
$block_link = 'contact/' . $pcid . '/block';
$ignore_link = 'contact/' . $pcid . '/ignore';
}
if ($cid && !$item['self']) {
@ -858,7 +932,7 @@ function item_photo_menu($item) {
$contact_url = 'contact/' . $cid;
$posts_link = 'contact/' . $cid . '/posts';
if (in_array($network, [Protocol::DFRN, Protocol::DIASPORA])) {
if (in_array($network, [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA])) {
$pm_url = 'message/new/' . $cid;
}
}
@ -871,7 +945,9 @@ function item_photo_menu($item) {
L10n::t('View Photos') => $photos_link,
L10n::t('Network Posts') => $posts_link,
L10n::t('View Contact') => $contact_url,
L10n::t('Send PM') => $pm_url
L10n::t('Send PM') => $pm_url,
L10n::t('Block') => $block_link,
L10n::t('Ignore') => $ignore_link
];
if ($network == Protocol::DFRN) {
@ -879,7 +955,7 @@ function item_photo_menu($item) {
}
if ((($cid == 0) || ($rel == Contact::FOLLOWER)) &&
in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::DIASPORA])) {
in_array($item['network'], Protocol::FEDERATED)) {
$menu[L10n::t('Connect/Follow')] = 'follow?url=' . urlencode($item['author-link']);
}
} else {
@ -888,7 +964,7 @@ function item_photo_menu($item) {
$args = ['item' => $item, 'menu' => $menu];
Addon::callHooks('item_photo_menu', $args);
Hook::callAll('item_photo_menu', $args);
$menu = $args['menu'];
@ -908,13 +984,14 @@ function item_photo_menu($item) {
* @brief Checks item to see if it is one of the builtin activities (like/dislike, event attendance, consensus items, etc.)
* Increments the count of each matching activity and adds a link to the author as needed.
*
* @param array $item
* @param array $item
* @param array &$conv_responses (already created with builtin activity structure)
* @return void
* @throws ImagickException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function builtin_activity_puller($item, &$conv_responses) {
foreach ($conv_responses as $mode => $v) {
$url = '';
$sparkle = '';
switch ($mode) {
@ -933,6 +1010,9 @@ function builtin_activity_puller($item, &$conv_responses) {
case 'attendmaybe':
$verb = ACTIVITY_ATTENDMAYBE;
break;
case 'announce':
$verb = ACTIVITY2_ANNOUNCE;
break;
default:
return;
}
@ -940,14 +1020,14 @@ function builtin_activity_puller($item, &$conv_responses) {
if (activity_match($item['verb'], $verb) && ($item['id'] != $item['parent'])) {
$author = ['uid' => 0, 'id' => $item['author-id'],
'network' => $item['author-network'], 'url' => $item['author-link']];
$url = Contact::magicLinkbyContact($author);
$url = Contact::magicLinkByContact($author);
if (strpos($url, 'redir/') === 0) {
$sparkle = ' class="sparkle" ';
}
$url = '<a href="'. $url . '"'. $sparkle .'>' . htmlentities($item['author-name']) . '</a>';
if (!x($item, 'thr-parent')) {
if (empty($item['thr-parent'])) {
$item['thr-parent'] = $item['parent-uri'];
}
@ -981,15 +1061,18 @@ function builtin_activity_puller($item, &$conv_responses) {
/**
* Format the vote text for a profile item
* @param int $cnt = number of people who vote the item
* @param array $arr = array of pre-linked names of likers/dislikers
*
* @param int $cnt = number of people who vote the item
* @param array $arr = array of pre-linked names of likers/dislikers
* @param string $type = one of 'like, 'dislike', 'attendyes', 'attendno', 'attendmaybe'
* @param int $id = item id
* @param int $id = item id
* @return string formatted text
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function format_like($cnt, array $arr, $type, $id) {
$o = '';
$expanded = '';
$phrase = '';
if ($cnt == 1) {
$likers = $arr[0];
@ -1012,28 +1095,27 @@ 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;
}
}
if ($cnt > 1) {
$total = count($arr);
if ($total >= MAX_LIKERS) {
$arr = array_slice($arr, 0, MAX_LIKERS - 1);
}
if ($total < MAX_LIKERS) {
$last = L10n::t('and') . ' ' . $arr[count($arr)-1];
$arr2 = array_slice($arr, 0, -1);
$str = implode(', ', $arr2) . ' ' . $last;
$likers = implode(', ', $arr2) . ' ' . $last;
} else {
$arr = array_slice($arr, 0, MAX_LIKERS - 1);
$likers = implode(', ', $arr);
$likers .= L10n::t('and %d other people', $total - MAX_LIKERS);
}
if ($total >= MAX_LIKERS) {
$str = implode(', ', $arr);
$str .= L10n::t('and %d other people', $total - MAX_LIKERS);
}
$likers = $str;
$spanatts = "class=\"fakelink\" onclick=\"openClose('{$type}list-$id');\"";
$explikers = '';
switch ($type) {
case 'like':
$phrase = L10n::t('<span %1$s>%2$d people</span> like this', $spanatts, $cnt);
@ -1055,13 +1137,16 @@ 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" . '<div class="wall-item-' . $type . '-expanded" id="' . $type . 'list-' . $id . '" style="display: none;" >' . $explikers . EOL . '</div>';
$expanded .= "\t" . '<p class="wall-item-' . $type . '-expanded" id="' . $type . 'list-' . $id . '" style="display: none;" >' . $explikers . EOL . '</p>';
}
$phrase .= EOL ;
$o .= replace_macros(get_markup_template('voting_fakelink.tpl'), [
$o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('voting_fakelink.tpl'), [
'$phrase' => $phrase,
'$type' => $type,
'$id' => $id
@ -1075,10 +1160,10 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
{
$o = '';
$geotag = x($x, 'allow_location') ? replace_macros(get_markup_template('jot_geotag.tpl'), []) : '';
$geotag = !empty($x['allow_location']) ? Renderer::replaceMacros(Renderer::getMarkupTemplate('jot_geotag.tpl'), []) : '';
$tpl = get_markup_template('jot-header.tpl');
$a->page['htmlhead'] .= replace_macros($tpl, [
$tpl = Renderer::getMarkupTemplate('jot-header.tpl');
$a->page['htmlhead'] .= Renderer::replaceMacros($tpl, [
'$newpost' => 'true',
'$baseurl' => System::baseUrl(true),
'$geotag' => $geotag,
@ -1092,11 +1177,11 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
]);
$jotplugins = '';
Addon::callHooks('jot_tool', $jotplugins);
Hook::callAll('jot_tool', $jotplugins);
// Private/public post links for the non-JS ACL form
$private_post = 1;
if (x($_REQUEST, 'public')) {
if (!empty($_REQUEST['public'])) {
$private_post = 0;
}
@ -1116,10 +1201,10 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
$public_post_link = '&public=1';
}
// $tpl = replace_macros($tpl,array('$jotplugins' => $jotplugins));
$tpl = get_markup_template("jot.tpl");
// $tpl = Renderer::replaceMacros($tpl,array('$jotplugins' => $jotplugins));
$tpl = Renderer::getMarkupTemplate("jot.tpl");
$o .= replace_macros($tpl,[
$o .= Renderer::replaceMacros($tpl,[
'$new_post' => L10n::t('New Post'),
'$return_path' => $query_str,
'$action' => 'item',
@ -1159,12 +1244,12 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
'$lockstate' => $x['lockstate'],
'$bang' => $x['bang'],
'$profile_uid' => $x['profile_uid'],
'$preview' => Feature::isEnabled($x['profile_uid'], 'preview') ? L10n::t('Preview') : '',
'$preview' => L10n::t('Preview'),
'$jotplugins' => $jotplugins,
'$notes_cid' => $notes_cid,
'$sourceapp' => L10n::t($a->sourcename),
'$cancel' => L10n::t('Cancel'),
'$rand_num' => random_digits(12),
'$rand_num' => Crypto::randomDigits(12),
// ACL permissions box
'$acl' => $x['acl'],
@ -1194,8 +1279,8 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false)
*
* @param array $item_list
* @param array $parent
* @param bool $recursive
* @return type
* @param bool $recursive
* @return array
*/
function get_item_children(array &$item_list, array $parent, $recursive = true)
{
@ -1232,7 +1317,7 @@ function get_item_children(array &$item_list, array $parent, $recursive = true)
function sort_item_children(array $items)
{
$result = $items;
usort($result, 'sort_thr_created_rev');
usort($result, 'sort_thr_received_rev');
foreach ($result as $k => $i) {
if (isset($result[$k]['children'])) {
$result[$k]['children'] = sort_item_children($result[$k]['children']);
@ -1317,14 +1402,15 @@ function smart_flatten_conversation(array $parent)
/**
* Expands a flat list of items into corresponding tree-like conversation structures,
* sort the top-level posts either on "created" or "commented", and finally
* sort the top-level posts either on "received" or "commented", and finally
* append all the items at the top level (???)
*
* @brief Expands a flat item list into a conversation array for display
*
* @param array $item_list A list of items belonging to one or more conversations
* @param string $order Either on "created" or "commented"
* @param string $order Either on "received" or "commented"
* @return array
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function conv_sort(array $item_list, $order)
{
@ -1354,8 +1440,8 @@ function conv_sort(array $item_list, $order)
}
}
if (stristr($order, 'created')) {
usort($parents, 'sort_thr_created');
if (stristr($order, 'received')) {
usort($parents, 'sort_thr_received');
} elseif (stristr($order, 'commented')) {
usort($parents, 'sort_thr_commented');
}
@ -1392,27 +1478,27 @@ function conv_sort(array $item_list, $order)
}
/**
* @brief usort() callback to sort item arrays by the created key
* @brief usort() callback to sort item arrays by the received key
*
* @param array $a
* @param array $b
* @return int
*/
function sort_thr_created(array $a, array $b)
function sort_thr_received(array $a, array $b)
{
return strcmp($b['created'], $a['created']);
return strcmp($b['received'], $a['received']);
}
/**
* @brief usort() callback to reverse sort item arrays by the created key
* @brief usort() callback to reverse sort item arrays by the received key
*
* @param array $a
* @param array $b
* @return int
*/
function sort_thr_created_rev(array $a, array $b)
function sort_thr_received_rev(array $a, array $b)
{
return strcmp($a['created'], $b['created']);
return strcmp($a['received'], $b['received']);
}
/**
@ -1420,7 +1506,7 @@ function sort_thr_created_rev(array $a, array $b)
*
* @param array $a
* @param array $b
* @return type
* @return int
*/
function sort_thr_commented(array $a, array $b)
{
@ -1428,16 +1514,16 @@ function sort_thr_commented(array $a, array $b)
}
function render_location_dummy(array $item) {
if (x($item, 'location') && !empty($item['location'])) {
if (!empty($item['location']) && !empty($item['location'])) {
return $item['location'];
}
if (x($item, 'coord') && !empty($item['coord'])) {
if (!empty($item['coord']) && !empty($item['coord'])) {
return $item['coord'];
}
}
function get_responses(array $conv_responses, array $response_verbs, $ob, array $item) {
function get_responses(array $conv_responses, array $response_verbs, array $item, Post $ob = null) {
$ret = [];
foreach ($response_verbs as $v) {
$ret[$v] = [];
@ -1468,6 +1554,7 @@ function get_responses(array $conv_responses, array $response_verbs, $ob, array
function get_response_button_text($v, $count)
{
$return = '';
switch ($v) {
case 'like':
$return = L10n::tt('Like', 'Likes', $count);

View file

@ -9,15 +9,16 @@ use Friendica\Database\DBA;
* DBA::select, DBA::exists, DBA::insert
* DBA::delete, DBA::update, DBA::p, DBA::e
*
* @param $args Query parameters (1 to N parameters of different types)
* @param $sql
* @return array|bool Query array
* @throws Exception
* @deprecated
*/
function q($sql) {
$args = func_get_args();
unset($args[0]);
if (!DBA::$connected) {
if (!DBA::connected()) {
return false;
}

View file

@ -4,32 +4,37 @@
*/
use Friendica\Content\Text\BBCode;
use Friendica\Core\Addon;
use Friendica\Core\Config;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Item;
use Friendica\Model\User;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Emailer;
use Friendica\Util\Strings;
/**
* @brief Creates a notification entry and possibly sends a mail
*
* @param array $params Array with the elements:
* uid, item, parent, type, otype, verb, event,
* link, subject, body, to_name, to_email, source_name,
* source_link, activity, preamble, notify_flags,
* language, show_in_notification_page
* uid, item, parent, type, otype, verb, event,
* link, subject, body, to_name, to_email, source_name,
* source_link, activity, preamble, notify_flags,
* language, show_in_notification_page
* @return bool
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function notification($params)
{
$a = get_app();
$a = \get_app();
// Temporary logging for finding the origin
if (!isset($params['language']) || !isset($params['uid'])) {
logger('Missing parameters.' . System::callstack());
if (!isset($params['uid'])) {
Logger::notice('Missing parameters "uid".', ['params' => $params, 'callstack' => System::callstack()]);
}
// Ensure that the important fields are set at any time
@ -37,8 +42,8 @@ function notification($params)
$user = DBA::selectFirst('user', $fields, ['uid' => $params['uid']]);
if (!DBA::isResult($user)) {
logger('Unknown user ' . $params['uid']);
return;
Logger::error('Unknown user', ['uid' => $params['uid']]);
return false;
}
$params['notify_flags'] = defaults($params, 'notify_flags', $user['notify-flags']);
@ -73,8 +78,8 @@ function notification($params)
['uid' => $params['uid']]);
// There is no need to create notifications for forum accounts
if (!DBA::isResult($user) || in_array($user["page-flags"], [Contact::PAGE_COMMUNITY, Contact::PAGE_PRVGROUP])) {
return;
if (!DBA::isResult($user) || in_array($user["page-flags"], [User::PAGE_FLAGS_COMMUNITY, User::PAGE_FLAGS_PRVGROUP])) {
return false;
}
$nickname = $user["nickname"];
} else {
@ -115,6 +120,12 @@ function notification($params)
}
$epreamble = '';
$preamble = '';
$subject = '';
$sitelink = '';
$tsitelink = '';
$hsitelink = '';
$itemlink = '';
if ($params['type'] == NOTIFY_MAIL) {
$itemlink = $siteurl.'/message/'.$params['item']['id'];
@ -123,19 +134,19 @@ function notification($params)
$subject = L10n::t('[Friendica:Notify] New mail received at %s', $sitename);
$preamble = L10n::t('%1$s sent you a new private message at %2$s.', $params['source_name'], $sitename);
$epreamble = L10n::t('%1$s sent you %2$s.', '[url='.$params['source_link'].']'.$params['source_name'].'[/url]', '[url=$itemlink]'.L10n::t('a private message').'[/url]');
$epreamble = L10n::t('%1$s sent you %2$s.', '[url='.$params['source_link'].']'.$params['source_name'].'[/url]', '[url=' . $itemlink . ']'.L10n::t('a private message').'[/url]');
$sitelink = L10n::t('Please visit %s to view and/or reply to your private messages.');
$tsitelink = sprintf($sitelink, $siteurl.'/message/'.$params['item']['id']);
$hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'/message/'.$params['item']['id'].'">'.$sitename.'</a>');
}
if ($params['type'] == NOTIFY_COMMENT) {
$thread = Item::selectFirstThreadForUser($params['uid'] ,['ignored'], ['iid' => $parent_id]);
if (DBA::isResult($thread) && $thread["ignored"]) {
logger("Thread ".$parent_id." will be ignored", LOGGER_DEBUG);
if ($params['type'] == NOTIFY_COMMENT || $params['type'] == NOTIFY_TAGSELF) {
$thread = Item::selectFirstThreadForUser($params['uid'], ['ignored'], ['iid' => $parent_id, 'deleted' => false]);
if (DBA::isResult($thread) && $thread['ignored']) {
Logger::log('Thread ' . $parent_id . ' will be ignored', Logger::DEBUG);
L10n::popLang();
return;
return false;
}
// Check to see if there was already a tag notify or comment notify for this post.
@ -144,59 +155,105 @@ function notification($params)
'link' => $params['link'], 'uid' => $params['uid']];
if (DBA::exists('notify', $condition)) {
L10n::popLang();
return;
return false;
}
// if it's a post figure out who's post it is.
$item = null;
if ($params['otype'] === 'item' && $parent_id) {
$item = Item::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id]);
$item = Item::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id, 'deleted' => false]);
}
$item_post_type = item_post_type($item);
$item_post_type = Item::postType($item);
$itemlink = $item['plink'];
// "a post"
$dest_str = L10n::t('%1$s commented on [url=%2$s]a %3$s[/url]',
'[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
$itemlink,
$item_post_type
);
// "George Bull's post"
if ($item) {
$dest_str = L10n::t('%1$s commented on [url=%2$s]%3$s\'s %4$s[/url]',
'[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
if ($params['type'] == NOTIFY_TAGSELF) {
$dest_str = L10n::t('%1$s tagged you on [url=%2$s]a %3$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item['author-name'],
$item_post_type
);
} else {
$dest_str = L10n::t('%1$s commented on [url=%2$s]a %3$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item_post_type
);
}
// "George Bull's post"
if (DBA::isResult($item)) {
if ($params['type'] == NOTIFY_TAGSELF) {
$dest_str = L10n::t('%1$s tagged you on [url=%2$s]%3$s\'s %4$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item['author-name'],
$item_post_type
);
} else {
$dest_str = L10n::t('%1$s commented on [url=%2$s]%3$s\'s %4$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item['author-name'],
$item_post_type
);
}
}
// "your post"
if (DBA::isResult($item) && $item['owner-id'] == $item['author-id'] && $item['wall']) {
$dest_str = L10n::t('%1$s commented on [url=%2$s]your %3$s[/url]',
'[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
$itemlink,
$item_post_type
);
if ($params['type'] == NOTIFY_TAGSELF) {
$dest_str = L10n::t('%1$s tagged you on [url=%2$s]your %3$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item_post_type
);
} else {
$dest_str = L10n::t('%1$s commented on [url=%2$s]your %3$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item_post_type
);
}
}
// Some mail softwares relies on subject field for threading.
// "their post"
if (DBA::isResult($item) && $item['author-link'] == $params['source_link']) {
if ($params['type'] == NOTIFY_TAGSELF) {
$dest_str = L10n::t('%1$s tagged you on [url=%2$s]their %3$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item_post_type
);
} else {
$dest_str = L10n::t('%1$s commented on [url=%2$s]their %3$s[/url]',
'[url=' . $params['source_link'] . ']' . $params['source_name'] . '[/url]',
$itemlink,
$item_post_type
);
}
}
// Some mail software relies on subject field for threading.
// So, we cannot have different subjects for notifications of the same thread.
// Before this we have the name of the replier on the subject rendering
// differents subjects for messages on the same thread.
// different subjects for messages on the same thread.
if ($params['type'] == NOTIFY_TAGSELF) {
$subject = L10n::t('[Friendica:Notify] %s tagged you', $params['source_name']);
$subject = L10n::t('[Friendica:Notify] Comment to conversation #%1$d by %2$s', $parent_id, $params['source_name']);
$preamble = L10n::t('%1$s tagged you at %2$s', $params['source_name'], $sitename);
} else {
$subject = L10n::t('[Friendica:Notify] Comment to conversation #%1$d by %2$s', $parent_id, $params['source_name']);
$preamble = L10n::t('%s commented on an item/conversation you have been following.', $params['source_name']);
}
$preamble = L10n::t('%s commented on an item/conversation you have been following.', $params['source_name']);
$epreamble = $dest_str;
$sitelink = L10n::t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf($sitelink, $siteurl);
$hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
$hsitelink = sprintf($sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
$itemlink = $params['link'];
}
@ -215,21 +272,6 @@ function notification($params)
$itemlink = $params['link'];
}
if ($params['type'] == NOTIFY_TAGSELF) {
$subject = L10n::t('[Friendica:Notify] %s tagged you', $params['source_name']);
$preamble = L10n::t('%1$s tagged you at %2$s', $params['source_name'], $sitename);
$epreamble = L10n::t('%1$s [url=%2$s]tagged you[/url].',
'[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
$params['link']
);
$sitelink = L10n::t('Please visit %s to view and/or reply to the conversation.');
$tsitelink = sprintf($sitelink, $siteurl);
$hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
$itemlink = $params['link'];
}
if ($params['type'] == NOTIFY_SHARE) {
$subject = L10n::t('[Friendica:Notify] %s shared a new post', $params['source_name']);
@ -411,16 +453,21 @@ function notification($params)
// It will be used by the system to send emails to users (like
// password reset, invitations and so) using one look (but without
// add a notification to the user, with could be inexistent)
$subject = $params['subject'];
if (!isset($params['subject'])) {
Logger::warning('subject isn\'t set.', ['type' => $params['type']]);
}
$subject = defaults($params, 'subject', '');
$preamble = $params['preamble'];
if (!isset($params['preamble'])) {
Logger::warning('preamble isn\'t set.', ['type' => $params['type'], 'subject' => $subject]);
}
$preamble = defaults($params, 'preamble', '');
$body = $params['body'];
if (!isset($params['body'])) {
Logger::warning('body isn\'t set.', ['type' => $params['type'], 'subject' => $subject, 'preamble' => $preamble]);
}
$body = defaults($params, 'body', '');
$sitelink = "";
$tsitelink = "";
$hsitelink = "";
$itemlink = "";
$show_in_notification_page = false;
}
@ -438,7 +485,7 @@ function notification($params)
'itemlink' => $itemlink
];
Addon::callHooks('enotify', $h);
Hook::callAll('enotify', $h);
$subject = $h['subject'];
@ -451,11 +498,13 @@ function notification($params)
$hsitelink = $h['hsitelink'];
$itemlink = $h['itemlink'];
$notify_id = 0;
if ($show_in_notification_page) {
logger("adding notification entry", LOGGER_DEBUG);
Logger::log("adding notification entry", Logger::DEBUG);
do {
$dups = false;
$hash = random_string();
$hash = Strings::getRandomHex();
if (DBA::exists('notify', ['hash' => $hash])) {
$dups = true;
}
@ -478,11 +527,11 @@ function notification($params)
$datarray['otype'] = $params['otype'];
$datarray['abort'] = false;
Addon::callHooks('enotify_store', $datarray);
Hook::callAll('enotify_store', $datarray);
if ($datarray['abort']) {
L10n::popLang();
return False;
return false;
}
// create notification entry in DB
@ -516,7 +565,7 @@ function notification($params)
}
$itemlink = System::baseUrl().'/notify/view/'.$notify_id;
$msg = replace_macros($epreamble, ['$itemlink' => $itemlink]);
$msg = Renderer::replaceMacros($epreamble, ['$itemlink' => $itemlink]);
$msg_cache = format_notification_message($datarray['name_cache'], strip_tags(BBCode::convert($msg)));
$fields = ['msg' => $msg, 'msg_cache' => $msg_cache];
@ -529,14 +578,14 @@ function notification($params)
|| $params['type'] == NOTIFY_SYSTEM
|| $params['type'] == SYSTEM_EMAIL) {
logger('sending notification email');
Logger::log('sending notification email');
if (isset($params['parent']) && (intval($params['parent']) != 0)) {
$id_for_parent = $params['parent']."@".$hostname;
// Is this the first email notification for this parent item and user?
if (!DBA::exists('notify-threads', ['master-parent-item' => $params['parent'], 'receiver-uid' => $params['uid']])) {
logger("notify_id:".intval($notify_id).", parent: ".intval($params['parent'])."uid: ".intval($params['uid']), LOGGER_DEBUG);
Logger::log("notify_id:".intval($notify_id).", parent: ".intval($params['parent'])."uid: ".intval($params['uid']), Logger::DEBUG);
$fields = ['notify-id' => $notify_id, 'master-parent-item' => $params['parent'],
'receiver-uid' => $params['uid'], 'parent-item' => 0];
@ -545,11 +594,11 @@ function notification($params)
$additional_mail_header .= "Message-ID: <${id_for_parent}>\n";
$log_msg = "include/enotify: No previous notification found for this parent:\n".
" parent: ${params['parent']}\n"." uid : ${params['uid']}\n";
logger($log_msg, LOGGER_DEBUG);
Logger::log($log_msg, Logger::DEBUG);
} else {
// If not, just "follow" the thread.
$additional_mail_header .= "References: <${id_for_parent}>\nIn-Reply-To: <${id_for_parent}>\n";
logger("There's already a notification for this parent.", LOGGER_DEBUG);
Logger::log("There's already a notification for this parent.", Logger::DEBUG);
}
}
@ -581,15 +630,15 @@ function notification($params)
$datarray['subject'] = $subject;
$datarray['headers'] = $additional_mail_header;
Addon::callHooks('enotify_mail', $datarray);
Hook::callAll('enotify_mail', $datarray);
// check whether sending post content in email notifications is allowed
// always true for SYSTEM_EMAIL
$content_allowed = ((!Config::get('system', 'enotify_no_content')) || ($params['type'] == SYSTEM_EMAIL));
// load the template for private message notifications
$tpl = get_markup_template('email_notify_html.tpl');
$email_html_body = replace_macros($tpl, [
$tpl = Renderer::getMarkupTemplate('email_notify_html.tpl');
$email_html_body = Renderer::replaceMacros($tpl, [
'$banner' => $datarray['banner'],
'$product' => $datarray['product'],
'$preamble' => str_replace("\n", "<br>\n", $datarray['preamble']),
@ -609,8 +658,8 @@ function notification($params)
]);
// load the template for private message notifications
$tpl = get_markup_template('email_notify_text.tpl');
$email_text_body = replace_macros($tpl, [
$tpl = Renderer::getMarkupTemplate('email_notify_text.tpl');
$email_text_body = Renderer::replaceMacros($tpl, [
'$banner' => $datarray['banner'],
'$product' => $datarray['product'],
'$preamble' => $datarray['preamble'],
@ -631,8 +680,7 @@ function notification($params)
L10n::popLang();
// use the Emailer class to send the message
return Emailer::send(
[
return Emailer::send([
'uid' => $params['uid'],
'fromName' => $sender_name,
'fromEmail' => $sender_email,
@ -641,8 +689,8 @@ function notification($params)
'messageSubject' => $datarray['subject'],
'htmlVersion' => $email_html_body,
'textVersion' => $email_text_body,
'additionalMailHeader' => $datarray['headers']]
);
'additionalMailHeader' => $datarray['headers']
]);
}
L10n::popLang();
@ -653,6 +701,7 @@ function notification($params)
* @brief Checks for users who should be notified
*
* @param int $itemid ID of the item for which the check should be done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function check_user_notification($itemid) {
// fetch all users in the thread
@ -668,13 +717,15 @@ function check_user_notification($itemid) {
/**
* @brief Checks for item related notifications and sends them
*
* @param int $itemid ID of the item for which the check should be done
* @param int $uid User ID
* @param int $itemid ID of the item for which the check should be done
* @param int $uid User ID
* @param string $defaulttype (Optional) Forces a notification with this type.
* @return bool
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function check_item_notification($itemid, $uid, $defaulttype = "") {
$notification_data = ["uid" => $uid, "profiles" => []];
Addon::callHooks('check_item_notification', $notification_data);
Hook::callAll('check_item_notification', $notification_data);
$profiles = $notification_data["profiles"];
@ -701,11 +752,11 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
// Check for invalid profile urls. 13 should be the shortest possible profile length:
// http://a.bc/d
// Additionally check for invalid urls that would return the normalised value "http:"
if ((strlen($profile) >= 13) && (normalise_link($profile) != "http:")) {
if ((strlen($profile) >= 13) && (Strings::normaliseLink($profile) != "http:")) {
if (!in_array($profile, $profiles2))
$profiles2[] = $profile;
$profile = normalise_link($profile);
$profile = Strings::normaliseLink($profile);
if (!in_array($profile, $profiles2))
$profiles2[] = $profile;
@ -732,10 +783,10 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
$fields = ['id', 'mention', 'tag', 'parent', 'title', 'body',
'author-link', 'author-name', 'author-avatar', 'author-id',
'guid', 'parent-uri', 'uri', 'contact-id', 'network'];
$condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]];
$item = Item::selectFirst($fields, $condition);
$condition = ['id' => $itemid, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], 'deleted' => false];
$item = Item::selectFirstForUser($uid, $fields, $condition);
if (!DBA::isResult($item) || in_array($item['author-id'], $contacts)) {
return;
return false;
}
// Generate the notification array
@ -759,7 +810,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
if (DBA::isResult($tags)) {
foreach ($tags AS $tag) {
$condition = ['nurl' => normalise_link($tag["url"]), 'uid' => $uid, 'notify_new_posts' => true];
$condition = ['nurl' => Strings::normaliseLink($tag["url"]), 'uid' => $uid, 'notify_new_posts' => true];
$r = DBA::exists('contact', $condition);
if ($r) {
$send_notification = true;
@ -789,7 +840,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
// Is it a post that the user had started?
$fields = ['ignored', 'mention'];
$thread = Item::selectFirstThreadForUser($params['uid'], $fields, ['iid' => $item["parent"]]);
$thread = Item::selectFirstThreadForUser($params['uid'], $fields, ['iid' => $item["parent"], 'deleted' => false]);
if ($thread['mention'] && !$thread['ignored'] && !isset($params["type"])) {
$params["type"] = NOTIFY_COMMENT;
@ -797,7 +848,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
}
// And now we check for participation of one of our contacts in the thread
$condition = ['parent' => $item["parent"], 'author-id' => $contacts];
$condition = ['parent' => $item["parent"], 'author-id' => $contacts, 'deleted' => false];
if (!$thread['ignored'] && !isset($params["type"]) && Item::exists($condition)) {
$params["type"] = NOTIFY_COMMENT;

View file

@ -5,12 +5,15 @@
use Friendica\BaseObject;
use Friendica\Content\Feature;
use Friendica\Core\Addon;
use Friendica\Core\Config;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
use Friendica\Model\Item;
use Friendica\Protocol\DFRN;
@ -19,15 +22,14 @@ use Friendica\Protocol\OStatus;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network;
use Friendica\Util\ParseUrl;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
require_once 'include/text.php';
require_once 'mod/share.php';
require_once 'include/enotify.php';
require_once __DIR__ . '/../mod/share.php';
function add_page_info_data(array $data, $no_photos = false)
{
Addon::callHooks('page_info_data', $data);
Hook::callAll('page_info_data', $data);
if (empty($data['type'])) {
return '';
@ -94,7 +96,7 @@ function add_page_info_data(array $data, $no_photos = false)
/// @TODO make a positive list of allowed characters
$hashtag = str_replace([" ", "+", "/", ".", "#", "'", "", "`", "(", ")", "", ""],
["", "", "", "", "", "", "", "", "", "", "", ""], $keyword);
$hashtags .= "#[url=" . System::baseUrl() . "/search?tag=" . rawurlencode($hashtag) . "]" . $hashtag . "[/url] ";
$hashtags .= "#[url=" . System::baseUrl() . "/search?tag=" . $hashtag . "]" . $hashtag . "[/url] ";
}
}
@ -109,7 +111,7 @@ function query_page_info($url, $photo = "", $keywords = false, $keyword_blacklis
$data["images"][0]["src"] = $photo;
}
logger('fetch page info for ' . $url . ' ' . print_r($data, true), LOGGER_DEBUG);
Logger::log('fetch page info for ' . $url . ' ' . print_r($data, true), Logger::DEBUG);
if (!$keywords && isset($data["keywords"])) {
unset($data["keywords"]);
@ -145,7 +147,7 @@ function add_page_keywords($url, $photo = "", $keywords = false, $keyword_blackl
$tags .= ", ";
}
$tags .= "#[url=" . System::baseUrl() . "/search?tag=" . rawurlencode($hashtag) . "]" . $hashtag . "[/url]";
$tags .= "#[url=" . System::baseUrl() . "/search?tag=" . $hashtag . "]" . $hashtag . "[/url]";
}
}
@ -167,7 +169,7 @@ function add_page_info($url, $no_photos = false, $photo = "", $keywords = false,
function add_page_info_to_body($body, $texturl = false, $no_photos = false)
{
logger('add_page_info_to_body: fetch page info for body ' . $body, LOGGER_DEBUG);
Logger::log('add_page_info_to_body: fetch page info for body ' . $body, Logger::DEBUG);
$URLSearchString = "^\[\]";
@ -203,8 +205,7 @@ function add_page_info_to_body($body, $texturl = false, $no_photos = false)
$body = $removedlink;
}
$url = str_replace(['/', '.'], ['\/', '\.'], $matches[1]);
$removedlink = preg_replace("/\[url\=" . $url . "\](.*?)\[\/url\]/ism", '', $body);
$removedlink = preg_replace("/\[url\=" . preg_quote($matches[1], '/') . "\](.*?)\[\/url\]/ism", '', $body);
if (($removedlink == "") || strstr($body, $removedlink)) {
$body = $removedlink;
}
@ -243,35 +244,35 @@ function add_page_info_to_body($body, $texturl = false, $no_photos = false)
* model where comments can have sub-threads. That would require some massive sorting
* to get all the feed items into a mostly linear ordering, and might still require
* recursion.
*
* @param $xml
* @param array $importer
* @param array $contact
* @param $hub
* @throws ImagickException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
function consume_feed($xml, array $importer, array $contact, &$hub, $datedir = 0, $pass = 0)
function consume_feed($xml, array $importer, array $contact, &$hub)
{
if ($contact['network'] === Protocol::OSTATUS) {
if ($pass < 2) {
// Test - remove before flight
//$tempfile = tempnam(get_temppath(), "ostatus2");
//file_put_contents($tempfile, $xml);
logger("Consume OStatus messages ", LOGGER_DEBUG);
OStatus::import($xml, $importer, $contact, $hub);
}
Logger::log("Consume OStatus messages ", Logger::DEBUG);
OStatus::import($xml, $importer, $contact, $hub);
return;
}
if ($contact['network'] === Protocol::FEED) {
if ($pass < 2) {
logger("Consume feeds", LOGGER_DEBUG);
Feed::import($xml, $importer, $contact, $hub);
}
Logger::log("Consume feeds", Logger::DEBUG);
Feed::import($xml, $importer, $contact, $hub);
return;
}
if ($contact['network'] === Protocol::DFRN) {
logger("Consume DFRN messages", LOGGER_DEBUG);
Logger::log("Consume DFRN messages", Logger::DEBUG);
$dfrn_importer = DFRN::getImporter($contact["id"], $importer["uid"]);
if (!empty($dfrn_importer)) {
logger("Now import the DFRN feed");
Logger::log("Now import the DFRN feed");
DFRN::import($xml, $dfrn_importer, true);
return;
}
@ -294,8 +295,6 @@ function subscribe_to_hub($url, array $importer, array $contact, $hubmode = 'sub
return;
}
$a = BaseObject::getApp();
$user = DBA::selectFirst('user', ['nickname'], ['uid' => $importer['uid']]);
// No user, no nickname, we quit
@ -306,11 +305,11 @@ function subscribe_to_hub($url, array $importer, array $contact, $hubmode = 'sub
$push_url = System::baseUrl() . '/pubsub/' . $user['nickname'] . '/' . $contact['id'];
// Use a single verify token, even if multiple hubs
$verify_token = ((strlen($contact['hub-verify'])) ? $contact['hub-verify'] : random_string());
$verify_token = ((strlen($contact['hub-verify'])) ? $contact['hub-verify'] : Strings::getRandomHex());
$params= 'hub.mode=' . $hubmode . '&hub.callback=' . urlencode($push_url) . '&hub.topic=' . urlencode($contact['poll']) . '&hub.verify=async&hub.verify_token=' . $verify_token;
logger('subscribe_to_hub: ' . $hubmode . ' ' . $contact['name'] . ' to hub ' . $url . ' endpoint: ' . $push_url . ' with verifier ' . $verify_token);
Logger::log('subscribe_to_hub: ' . $hubmode . ' ' . $contact['name'] . ' to hub ' . $url . ' endpoint: ' . $push_url . ' with verifier ' . $verify_token);
if (!strlen($contact['hub-verify']) || ($contact['hub-verify'] != $verify_token)) {
DBA::update('contact', ['hub-verify' => $verify_token], ['id' => $contact['id']]);
@ -318,7 +317,7 @@ function subscribe_to_hub($url, array $importer, array $contact, $hubmode = 'sub
$postResult = Network::post($url, $params);
logger('subscribe_to_hub: returns: ' . $postResult->getReturnCode(), LOGGER_DEBUG);
Logger::log('subscribe_to_hub: returns: ' . $postResult->getReturnCode(), Logger::DEBUG);
return;
@ -328,7 +327,7 @@ function drop_items(array $items)
{
$uid = 0;
if (!local_user() && !remote_user()) {
if (!Session::isAuthenticated()) {
return;
}
@ -343,13 +342,13 @@ function drop_items(array $items)
}
}
function drop_item($id)
function drop_item($id, $return = '')
{
$a = BaseObject::getApp();
// locate item to be deleted
$fields = ['id', 'uid', 'guid', 'contact-id', 'deleted'];
$fields = ['id', 'uid', 'guid', 'contact-id', 'deleted', 'gravity', 'parent'];
$item = Item::selectFirstForUser(local_user(), $fields, ['id' => $id]);
if (!DBA::isResult($item)) {
@ -364,14 +363,8 @@ function drop_item($id)
$contact_id = 0;
// check if logged in user is either the author or owner of this item
if (!empty($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $visitor) {
if ($visitor['uid'] == $item['uid'] && $visitor['cid'] == $item['contact-id']) {
$contact_id = $visitor['cid'];
break;
}
}
if (Session::getRemoteContactID($item['uid']) == $item['contact-id']) {
$contact_id = $item['contact-id'];
}
if ((local_user() == $item['uid']) || $contact_id) {
@ -389,7 +382,7 @@ function drop_item($id)
}
}
return replace_macros(get_markup_template('confirm.tpl'), [
return Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [
'$method' => 'get',
'$message' => L10n::t('Do you really want to delete this item?'),
'$extra_inputs' => $inputs,
@ -404,91 +397,47 @@ function drop_item($id)
$a->internalRedirect('display/' . $item['guid']);
}
$is_comment = ($item['gravity'] == GRAVITY_COMMENT) ? true : false;
$parentitem = null;
if (!empty($item['parent'])){
$fields = ['guid'];
$parentitem = Item::selectFirstForUser(local_user(), $fields, ['id' => $item['parent']]);
}
// delete the item
Item::deleteForUser(['id' => $item['id']], local_user());
$a->internalRedirect('network');
//NOTREACHED
$return_url = hex2bin($return);
// removes update_* from return_url to ignore Ajax refresh
$return_url = str_replace("update_", "", $return_url);
// Check if delete a comment
if ($is_comment) {
// Return to parent guid
if (!empty($parentitem)) {
$a->internalRedirect('display/' . $parentitem['guid']);
//NOTREACHED
}
// In case something goes wrong
else {
$a->internalRedirect('network');
//NOTREACHED
}
}
else {
// if unknown location or deleting top level post called from display
if (empty($return_url) || strpos($return_url, 'display') !== false) {
$a->internalRedirect('network');
//NOTREACHED
} else {
$a->internalRedirect($return_url);
//NOTREACHED
}
}
} else {
notice(L10n::t('Permission denied.') . EOL);
$a->internalRedirect('display/' . $item['guid']);
//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 = day_translate(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 = replace_macros(get_markup_template('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;
}

File diff suppressed because it is too large Load diff

View file

@ -4,12 +4,23 @@
* Friendica
*/
use Friendica\App;
use Dice\Dice;
require_once 'boot.php';
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
die('Vendor path not found. Please execute "bin/composer.phar --no-dev install" on the command line in the web root.');
}
// We assume that the index.php is called by a frontend process
// The value is set to "true" by default in App
$a = new App(__DIR__, false);
require __DIR__ . '/vendor/autoload.php';
$a->runFrontend();
$dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php');
$dice = $dice->addRule(Friendica\App\Mode::class, ['call' => [['determineRunMode', [false, $_SERVER], Dice::CHAIN_CALL]]]);
\Friendica\BaseObject::setDependencyInjection($dice);
$a = \Friendica\BaseObject::getApp();
$a->runFrontend(
$dice->create(\Friendica\App\Module::class),
$dice->create(\Friendica\App\Router::class),
$dice->create(\Friendica\Core\Config\PConfiguration::class)
);

View file

@ -3,26 +3,31 @@
/* Generic exception class
*/
class OAuthException extends Exception {
// pass
if (!class_exists('OAuthException', false)) {
class OAuthException extends Exception
{ }
}
class OAuthConsumer {
class OAuthConsumer
{
public $key;
public $secret;
function __construct($key, $secret, $callback_url=NULL) {
function __construct($key, $secret, $callback_url = NULL)
{
$this->key = $key;
$this->secret = $secret;
$this->callback_url = $callback_url;
}
function __toString() {
function __toString()
{
return "OAuthConsumer[key=$this->key,secret=$this->secret]";
}
}
class OAuthToken {
class OAuthToken
{
// access tokens and request tokens
public $key;
public $secret;
@ -35,7 +40,8 @@ class OAuthToken {
* key = the token
* secret = the token secret
*/
function __construct($key, $secret) {
function __construct($key, $secret)
{
$this->key = $key;
$this->secret = $secret;
}
@ -44,14 +50,16 @@ class OAuthToken {
* generates the basic string serialization of a token that a server
* would respond to request_token and access_token calls with
*/
function to_string() {
function to_string()
{
return "oauth_token=" .
OAuthUtil::urlencode_rfc3986($this->key) .
"&oauth_token_secret=" .
OAuthUtil::urlencode_rfc3986($this->secret);
OAuthUtil::urlencode_rfc3986($this->key) .
"&oauth_token_secret=" .
OAuthUtil::urlencode_rfc3986($this->secret);
}
function __toString() {
function __toString()
{
return $this->to_string();
}
}
@ -60,7 +68,8 @@ class OAuthToken {
* A class for implementing a Signature Method
* See section 9 ("Signing Requests") in the spec
*/
abstract class OAuthSignatureMethod {
abstract class OAuthSignatureMethod
{
/**
* Needs to return the name of the Signature Method (ie HMAC-SHA1)
* @return string
@ -87,26 +96,29 @@ abstract class OAuthSignatureMethod {
* @param string $signature
* @return bool
*/
public function check_signature($request, $consumer, $token, $signature) {
public function check_signature($request, $consumer, $token, $signature)
{
$built = $this->build_signature($request, $consumer, $token);
//echo "<pre>"; var_dump($signature, $built, ($built == $signature)); killme();
return ($built == $signature);
}
}
/**
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
* where the Signature Base String is the text and the key is the concatenated values (each first
* encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
* where the Signature Base String is the text and the key is the concatenated values (each first
* encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
* character (ASCII code 38) even if empty.
* - Chapter 9.2 ("HMAC-SHA1")
*/
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
function get_name() {
class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod
{
function get_name()
{
return "HMAC-SHA1";
}
public function build_signature($request, $consumer, $token) {
public function build_signature($request, $consumer, $token)
{
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
@ -125,25 +137,28 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
}
/**
* The PLAINTEXT method does not provide any security protection and SHOULD only be used
* The PLAINTEXT method does not provide any security protection and SHOULD only be used
* over a secure channel such as HTTPS. It does not use the Signature Base String.
* - Chapter 9.4 ("PLAINTEXT")
*/
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
public function get_name() {
class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod
{
public function get_name()
{
return "PLAINTEXT";
}
/**
* oauth_signature is set to the concatenated encoded values of the Consumer Secret and
* Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
* oauth_signature is set to the concatenated encoded values of the Consumer Secret and
* Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
* empty. The result MUST be encoded again.
* - Chapter 9.4.1 ("Generating Signatures")
*
* Please note that the second encoding MUST NOT happen in the SignatureMethod, as
* OAuthRequest handles this!
*/
public function build_signature($request, $consumer, $token) {
public function build_signature($request, $consumer, $token)
{
$key_parts = array(
$consumer->secret,
($token) ? $token->secret : ""
@ -158,15 +173,17 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
}
/**
* The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
* [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
* EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
* verified way to the Service Provider, in a manner which is beyond the scope of this
* The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
* [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
* EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
* verified way to the Service Provider, in a manner which is beyond the scope of this
* specification.
* - Chapter 9.3 ("RSA-SHA1")
*/
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
public function get_name() {
abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod
{
public function get_name()
{
return "RSA-SHA1";
}
@ -184,7 +201,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
// Either way should return a string representation of the certificate
protected abstract function fetch_private_cert(&$request);
public function build_signature($request, $consumer, $token) {
public function build_signature($request, $consumer, $token)
{
$base_string = $request->get_signature_base_string();
$request->base_string = $base_string;
@ -203,7 +221,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
return base64_encode($signature);
}
public function check_signature($request, $consumer, $token, $signature) {
public function check_signature($request, $consumer, $token, $signature)
{
$decoded_sig = base64_decode($signature);
$base_string = $request->get_signature_base_string();
@ -224,7 +243,8 @@ abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
}
}
class OAuthRequest {
class OAuthRequest
{
private $parameters;
private $http_method;
private $http_url;
@ -233,9 +253,10 @@ class OAuthRequest {
public static $version = '1.0';
public static $POST_INPUT = 'php://input';
function __construct($http_method, $http_url, $parameters=NULL) {
function __construct($http_method, $http_url, $parameters = NULL)
{
@$parameters or $parameters = array();
$parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
$parameters = array_merge(OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
$this->parameters = $parameters;
$this->http_method = $http_method;
$this->http_url = $http_url;
@ -245,15 +266,16 @@ class OAuthRequest {
/**
* attempt to build up a request from what was passed to the server
*/
public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
public static function from_request($http_method = NULL, $http_url = NULL, $parameters = NULL)
{
$scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
? 'http'
: 'https';
? 'http'
: 'https';
@$http_url or $http_url = $scheme .
'://' . $_SERVER['HTTP_HOST'] .
':' .
$_SERVER['SERVER_PORT'] .
$_SERVER['REQUEST_URI'];
'://' . $_SERVER['HTTP_HOST'] .
':' .
$_SERVER['SERVER_PORT'] .
$_SERVER['REQUEST_URI'];
@$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
// We weren't handed any parameters, so let's find the ones relevant to
@ -269,10 +291,13 @@ class OAuthRequest {
// It's a POST request of the proper content-type, so parse POST
// parameters and add those overriding any duplicates from GET
if ($http_method == "POST"
&& @strstr($request_headers["Content-Type"],
"application/x-www-form-urlencoded")
) {
if (
$http_method == "POST"
&& @strstr(
$request_headers["Content-Type"],
"application/x-www-form-urlencoded"
)
) {
$post_data = OAuthUtil::parse_parameters(
file_get_contents(self::$POST_INPUT)
);
@ -287,26 +312,27 @@ class OAuthRequest {
);
$parameters = array_merge($parameters, $header_parameters);
}
}
// fix for friendica redirect system
$http_url = substr($http_url, 0, strpos($http_url,$parameters['pagename'])+strlen($parameters['pagename']));
unset( $parameters['pagename'] );
//echo "<pre>".__function__."\n"; var_dump($http_method, $http_url, $parameters, $_SERVER['REQUEST_URI']); killme();
$http_url = substr($http_url, 0, strpos($http_url, $parameters['pagename']) + strlen($parameters['pagename']));
unset($parameters['pagename']);
return new OAuthRequest($http_method, $http_url, $parameters);
}
/**
* pretty much a helper function to set up the request
*/
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = NULL)
{
@$parameters or $parameters = array();
$defaults = array("oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key);
$defaults = array(
"oauth_version" => OAuthRequest::$version,
"oauth_nonce" => OAuthRequest::generate_nonce(),
"oauth_timestamp" => OAuthRequest::generate_timestamp(),
"oauth_consumer_key" => $consumer->key
);
if ($token)
$defaults['oauth_token'] = $token->key;
@ -315,7 +341,8 @@ class OAuthRequest {
return new OAuthRequest($http_method, $http_url, $parameters);
}
public function set_parameter($name, $value, $allow_duplicates = true) {
public function set_parameter($name, $value, $allow_duplicates = true)
{
if ($allow_duplicates && isset($this->parameters[$name])) {
// We have already added parameter(s) with this name, so add to the list
if (is_scalar($this->parameters[$name])) {
@ -330,15 +357,18 @@ class OAuthRequest {
}
}
public function get_parameter($name) {
public function get_parameter($name)
{
return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
}
public function get_parameters() {
public function get_parameters()
{
return $this->parameters;
}
public function unset_parameter($name) {
public function unset_parameter($name)
{
unset($this->parameters[$name]);
}
@ -346,7 +376,8 @@ class OAuthRequest {
* The request parameters, sorted and concatenated into a normalized string.
* @return string
*/
public function get_signable_parameters() {
public function get_signable_parameters()
{
// Grab all parameters
$params = $this->parameters;
@ -366,7 +397,8 @@ class OAuthRequest {
* and the parameters (normalized), each urlencoded
* and the concated with &.
*/
public function get_signature_base_string() {
public function get_signature_base_string()
{
$parts = array(
$this->get_normalized_http_method(),
$this->get_normalized_http_url(),
@ -381,7 +413,8 @@ class OAuthRequest {
/**
* just uppercases the http method
*/
public function get_normalized_http_method() {
public function get_normalized_http_method()
{
return strtoupper($this->http_method);
}
@ -389,7 +422,8 @@ class OAuthRequest {
* parses the url and rebuilds it to be
* scheme://host/path
*/
public function get_normalized_http_url() {
public function get_normalized_http_url()
{
$parts = parse_url($this->http_url);
$port = @$parts['port'];
@ -400,7 +434,8 @@ class OAuthRequest {
$port or $port = ($scheme == 'https') ? '443' : '80';
if (($scheme == 'https' && $port != '443')
|| ($scheme == 'http' && $port != '80')) {
|| ($scheme == 'http' && $port != '80')
) {
$host = "$host:$port";
}
return "$scheme://$host$path";
@ -409,11 +444,12 @@ class OAuthRequest {
/**
* builds a url usable for a GET request
*/
public function to_url() {
public function to_url()
{
$post_data = $this->to_postdata();
$out = $this->get_normalized_http_url();
if ($post_data) {
$out .= '?'.$post_data;
$out .= '?' . $post_data;
}
return $out;
}
@ -421,9 +457,10 @@ class OAuthRequest {
/**
* builds the data one would send in a POST request
*/
public function to_postdata($raw = false) {
public function to_postdata($raw = false)
{
if ($raw)
return($this->parameters);
return $this->parameters;
else
return OAuthUtil::build_http_query($this->parameters);
}
@ -431,15 +468,15 @@ class OAuthRequest {
/**
* builds the Authorization: header
*/
public function to_header($realm=null) {
public function to_header($realm = null)
{
$first = true;
if($realm) {
if ($realm) {
$out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
$first = false;
} else
$out = 'Authorization: OAuth';
$total = array();
foreach ($this->parameters as $k => $v) {
if (substr($k, 0, 5) != "oauth") continue;
if (is_array($v)) {
@ -447,20 +484,22 @@ class OAuthRequest {
}
$out .= ($first) ? ' ' : ',';
$out .= OAuthUtil::urlencode_rfc3986($k) .
'="' .
OAuthUtil::urlencode_rfc3986($v) .
'"';
'="' .
OAuthUtil::urlencode_rfc3986($v) .
'"';
$first = false;
}
return $out;
}
public function __toString() {
public function __toString()
{
return $this->to_url();
}
public function sign_request($signature_method, $consumer, $token) {
public function sign_request($signature_method, $consumer, $token)
{
$this->set_parameter(
"oauth_signature_method",
$signature_method->get_name(),
@ -470,7 +509,8 @@ class OAuthRequest {
$this->set_parameter("oauth_signature", $signature, false);
}
public function build_signature($signature_method, $consumer, $token) {
public function build_signature($signature_method, $consumer, $token)
{
$signature = $signature_method->build_signature($this, $consumer, $token);
return $signature;
}
@ -478,33 +518,35 @@ class OAuthRequest {
/**
* util function: current timestamp
*/
private static function generate_timestamp() {
private static function generate_timestamp()
{
return time();
}
/**
* util function: current nonce
*/
private static function generate_nonce() {
$mt = microtime();
$rand = mt_rand();
return md5($mt . $rand); // md5s look nicer than numbers
private static function generate_nonce()
{
return Friendica\Util\Strings::getRandomHex(32);
}
}
class OAuthServer {
class OAuthServer
{
protected $timestamp_threshold = 300; // in seconds, five minutes
protected $version = '1.0'; // hi blaine
protected $signature_methods = array();
protected $data_store;
function __construct($data_store) {
function __construct($data_store)
{
$this->data_store = $data_store;
}
public function add_signature_method($signature_method) {
public function add_signature_method($signature_method)
{
$this->signature_methods[$signature_method->get_name()] =
$signature_method;
}
@ -515,7 +557,8 @@ class OAuthServer {
* process a request_token request
* returns the request token on success
*/
public function fetch_request_token(&$request) {
public function fetch_request_token(&$request)
{
$this->get_version($request);
$consumer = $this->get_consumer($request);
@ -536,7 +579,8 @@ class OAuthServer {
* process an access_token request
* returns the access token on success
*/
public function fetch_access_token(&$request) {
public function fetch_access_token(&$request)
{
$this->get_version($request);
$consumer = $this->get_consumer($request);
@ -556,23 +600,24 @@ class OAuthServer {
/**
* verify an api call, checks all the parameters
*/
public function verify_request(&$request) {
public function verify_request(&$request)
{
$this->get_version($request);
$consumer = $this->get_consumer($request);
//echo __file__.__line__.__function__."<pre>"; var_dump($consumer); die();
$token = $this->get_token($request, $consumer, "access");
$this->check_signature($request, $consumer, $token);
return array($consumer, $token);
return [$consumer, $token];
}
// Internals from here
/**
* version 1
*/
private function get_version(&$request) {
private function get_version(&$request)
{
$version = $request->get_parameter("oauth_version");
if (!$version) {
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
// Chapter 7.0 ("Accessing Protected Ressources")
$version = '1.0';
}
@ -585,9 +630,10 @@ class OAuthServer {
/**
* figure out the signature with some defaults
*/
private function get_signature_method(&$request) {
private function get_signature_method(&$request)
{
$signature_method =
@$request->get_parameter("oauth_signature_method");
@$request->get_parameter("oauth_signature_method");
if (!$signature_method) {
// According to chapter 7 ("Accessing Protected Ressources") the signature-method
@ -595,12 +641,14 @@ class OAuthServer {
throw new OAuthException('No signature method parameter. This parameter is required');
}
if (!in_array($signature_method,
array_keys($this->signature_methods))) {
if (!in_array(
$signature_method,
array_keys($this->signature_methods)
)) {
throw new OAuthException(
"Signature method '$signature_method' not supported " .
"try one of the following: " .
implode(", ", array_keys($this->signature_methods))
"try one of the following: " .
implode(", ", array_keys($this->signature_methods))
);
}
return $this->signature_methods[$signature_method];
@ -609,7 +657,8 @@ class OAuthServer {
/**
* try to find the consumer for the provided request's consumer key
*/
private function get_consumer(&$request) {
private function get_consumer(&$request)
{
$consumer_key = @$request->get_parameter("oauth_consumer_key");
if (!$consumer_key) {
throw new OAuthException("Invalid consumer key");
@ -626,10 +675,13 @@ class OAuthServer {
/**
* try to find the token for the provided request's token key
*/
private function get_token(&$request, $consumer, $token_type="access") {
private function get_token(&$request, $consumer, $token_type = "access")
{
$token_field = @$request->get_parameter('oauth_token');
$token = $this->data_store->lookup_token(
$consumer, $token_type, $token_field
$consumer,
$token_type,
$token_field
);
if (!$token) {
throw new OAuthException("Invalid $token_type token: $token_field");
@ -641,7 +693,8 @@ class OAuthServer {
* all-in-one function to check the signature on a request
* should guess the signature method appropriately
*/
private function check_signature(&$request, $consumer, $token) {
private function check_signature(&$request, $consumer, $token)
{
// this should probably be in a different method
$timestamp = @$request->get_parameter('oauth_timestamp');
$nonce = @$request->get_parameter('oauth_nonce');
@ -658,7 +711,7 @@ class OAuthServer {
$token,
$signature
);
if (!$valid_sig) {
throw new OAuthException("Invalid signature");
@ -668,12 +721,13 @@ class OAuthServer {
/**
* check that the timestamp is new enough
*/
private function check_timestamp($timestamp) {
if( ! $timestamp )
private function check_timestamp($timestamp)
{
if (!$timestamp)
throw new OAuthException(
'Missing timestamp parameter. The parameter is required'
);
// verify that timestamp is recentish
$now = time();
if (abs($now - $timestamp) > $this->timestamp_threshold) {
@ -686,8 +740,9 @@ class OAuthServer {
/**
* check that the nonce is not repeated
*/
private function check_nonce($consumer, $token, $nonce, $timestamp) {
if( ! $nonce )
private function check_nonce($consumer, $token, $nonce, $timestamp)
{
if (!$nonce)
throw new OAuthException(
'Missing nonce parameter. The parameter is required'
);
@ -703,65 +758,73 @@ class OAuthServer {
throw new OAuthException("Nonce already used: $nonce");
}
}
}
class OAuthDataStore {
function lookup_consumer($consumer_key) {
class OAuthDataStore
{
function lookup_consumer($consumer_key)
{
// implement me
}
function lookup_token($consumer, $token_type, $token) {
function lookup_token($consumer, $token_type, $token)
{
// implement me
}
function lookup_nonce($consumer, $token, $nonce, $timestamp) {
function lookup_nonce($consumer, $token, $nonce, $timestamp)
{
// implement me
}
function new_request_token($consumer, $callback = null) {
function new_request_token($consumer, $callback = null)
{
// return a new token attached to this consumer
}
function new_access_token($token, $consumer, $verifier = null) {
function new_access_token($token, $consumer, $verifier = null)
{
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
}
}
class OAuthUtil {
public static function urlencode_rfc3986($input) {
if (is_array($input)) {
return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
} else if (is_scalar($input)) {
return str_replace(
'+',
' ',
str_replace('%7E', '~', rawurlencode($input))
);
} else {
return '';
class OAuthUtil
{
public static function urlencode_rfc3986($input)
{
if (is_array($input)) {
return array_map(['OAuthUtil', 'urlencode_rfc3986'], $input);
} else if (is_scalar($input)) {
return str_replace(
'+',
' ',
str_replace('%7E', '~', rawurlencode($input))
);
} else {
return '';
}
}
}
// This decode function isn't taking into consideration the above
// modifications to the encoding process. However, this method doesn't
// seem to be used anywhere so leaving it as is.
public static function urldecode_rfc3986($string) {
public static function urldecode_rfc3986($string)
{
return urldecode($string);
}
// Utility function for turning the Authorization: header into
// parameters, has to do some unescaping
// Can filter out any non-oauth parameters if needed (default behaviour)
public static function split_header($header, $only_allow_oauth_parameters = true) {
public static function split_header($header, $only_allow_oauth_parameters = true)
{
$pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
$offset = 0;
$params = array();
$params = [];
while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
$match = $matches[0];
$header_name = $matches[2][0];
@ -780,7 +843,8 @@ class OAuthUtil {
}
// helper to try to sort out headers for people who aren't running apache
public static function get_headers() {
public static function get_headers()
{
if (function_exists('apache_request_headers')) {
// we need this to get the actual Authorization: header
// because apache tends to tell us it doesn't exist
@ -790,22 +854,22 @@ class OAuthUtil {
// we always want the keys to be Cased-Like-This and arh()
// returns the headers in the same case as they are in the
// request
$out = array();
foreach( $headers AS $key => $value ) {
$out = [];
foreach ($headers as $key => $value) {
$key = str_replace(
" ",
"-",
ucwords(strtolower(str_replace("-", " ", $key)))
);
" ",
"-",
ucwords(strtolower(str_replace("-", " ", $key)))
);
$out[$key] = $value;
}
} else {
// otherwise we don't have apache and are just going to have to hope
// that $_SERVER actually contains what we need
$out = array();
if( isset($_SERVER['CONTENT_TYPE']) )
$out = [];
if (isset($_SERVER['CONTENT_TYPE']))
$out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
if( isset($_ENV['CONTENT_TYPE']) )
if (isset($_ENV['CONTENT_TYPE']))
$out['Content-Type'] = $_ENV['CONTENT_TYPE'];
foreach ($_SERVER as $key => $value) {
@ -828,12 +892,13 @@ class OAuthUtil {
// This function takes a input like a=b&a=c&d=e and returns the parsed
// parameters like this
// array('a' => array('b','c'), 'd' => 'e')
public static function parse_parameters( $input ) {
public static function parse_parameters($input)
{
if (!isset($input) || !$input) return array();
$pairs = explode('&', $input);
$parsed_parameters = array();
$parsed_parameters = [];
foreach ($pairs as $pair) {
$split = explode('=', $pair, 2);
$parameter = OAuthUtil::urldecode_rfc3986($split[0]);
@ -846,7 +911,7 @@ class OAuthUtil {
if (is_scalar($parsed_parameters[$parameter])) {
// This is the first duplicate, so transform scalar (string) into an array
// so we can add the duplicates
$parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
$parsed_parameters[$parameter] = [$parsed_parameters[$parameter]];
}
$parsed_parameters[$parameter][] = $value;
@ -857,7 +922,8 @@ class OAuthUtil {
return $parsed_parameters;
}
public static function build_http_query($params) {
public static function build_http_query($params)
{
if (!$params) return '';
// Urlencode both keys and values
@ -869,7 +935,7 @@ class OAuthUtil {
// Ref: Spec: 9.1.1 (1)
uksort($params, 'strcmp');
$pairs = array();
$pairs = [];
foreach ($params as $parameter => $value) {
if (is_array($value)) {
// If two or more parameters share the same name, they are sorted by their value
@ -887,5 +953,3 @@ class OAuthUtil {
return implode('&', $pairs);
}
}
?>

View file

@ -1,83 +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);
killme();
}
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;
}

View file

@ -1,319 +0,0 @@
<?php
/* ACL selector json backend */
use Friendica\App;
use Friendica\Content\Widget;
use Friendica\Core\ACL;
use Friendica\Core\Addon;
use Friendica\Core\Protocol;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Item;
use Friendica\Util\Proxy as ProxyUtils;
require_once 'include/dba.php';
function acl_content(App $a)
{
if (!local_user()) {
return '';
}
$start = defaults($_REQUEST, 'start' , 0);
$count = defaults($_REQUEST, 'count' , 100);
$search = defaults($_REQUEST, 'search' , '');
$type = defaults($_REQUEST, 'type' , '');
$conv_id = defaults($_REQUEST, 'conversation', null);
// For use with jquery.textcomplete for private mail completion
if (!empty($_REQUEST['query'])) {
if (!$type) {
$type = 'm';
}
$search = $_REQUEST['query'];
}
logger("Searching for ".$search." - type ".$type." conversation ".$conv_id, LOGGER_DEBUG);
if ($search != '') {
$sql_extra = "AND `name` LIKE '%%" . DBA::escape($search) . "%%'";
$sql_extra2 = "AND (`attag` LIKE '%%" . DBA::escape($search) . "%%' OR `name` LIKE '%%" . DBA::escape($search) . "%%' OR `nick` LIKE '%%" . DBA::escape($search) . "%%')";
} else {
/// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
$sql_extra = $sql_extra2 = '';
}
// count groups and contacts
$group_count = 0;
if ($type == '' || $type == 'g') {
$r = q("SELECT COUNT(*) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra",
intval(local_user())
);
$group_count = (int) $r[0]['g'];
}
$sql_extra2 .= ' ' . Widget::unavailableNetworks();
$contact_count = 0;
if ($type == '' || $type == 'c') {
// autocomplete for editor mentions
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` >= `failure_update`
AND `notify` != '' $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'f') {
// autocomplete for editor mentions of forums
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND (`forum` OR `prv`)
AND `success_update` >= `failure_update`
AND `notify` != '' $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'm') {
// autocomplete for Private Messages
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self`
AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` >= `failure_update`
AND `network` IN ('%s', '%s', '%s') $sql_extra2",
intval(local_user()),
DBA::escape(Protocol::ACTIVITYPUB),
DBA::escape(Protocol::DFRN),
DBA::escape(Protocol::DIASPORA)
);
$contact_count = (int) $r[0]['c'];
} elseif ($type == 'a') {
// autocomplete for Contacts
$r = q("SELECT COUNT(*) AS c FROM `contact`
WHERE `uid` = %d AND NOT `self`
AND NOT `pending` $sql_extra2",
intval(local_user())
);
$contact_count = (int) $r[0]['c'];
}
$tot = $group_count + $contact_count;
$groups = [];
$contacts = [];
if ($type == '' || $type == 'g') {
/// @todo We should cache this query.
// This can be done when we can delete cache entries via wildcard
$r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
FROM `group`
INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
$sql_extra
GROUP BY `group`.`name`, `group`.`id`
ORDER BY `group`.`name`
LIMIT %d,%d",
intval(local_user()),
intval($start),
intval($count)
);
foreach ($r as $g) {
$groups[] = [
'type' => 'g',
'photo' => 'images/twopeople.png',
'name' => htmlentities($g['name']),
'id' => intval($g['id']),
'uids' => array_map('intval', explode(',', $g['uids'])),
'link' => '',
'forum' => '0'
];
}
if ((count($groups) > 0) && ($search == '')) {
$groups[] = ['separator' => true];
}
}
$r = [];
if ($type == '') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s', '%s'))
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::OSTATUS),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'c') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'f') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
AND (`forum` OR `prv`)
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::STATUSNET)
);
} elseif ($type == 'm') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s', '%s')
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user()),
DBA::escape(Protocol::ACTIVITYPUB),
DBA::escape(Protocol::DFRN),
DBA::escape(Protocol::DIASPORA)
);
} elseif ($type == 'a') {
$r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
WHERE `uid` = %d AND `pending` = 0 AND `success_update` >= `failure_update`
$sql_extra2
ORDER BY `name` ASC ",
intval(local_user())
);
} elseif ($type == 'x') {
// autocomplete for global contact search (e.g. navbar search)
$search = notags(trim($_REQUEST['search']));
$mode = $_REQUEST['smode'];
$r = ACL::contactAutocomplete($search, $mode);
$contacts = [];
foreach ($r as $g) {
$contacts[] = [
'photo' => ProxyUtils::proxifyUrl($g['photo'], false, ProxyUtils::SIZE_MICRO),
'name' => $g['name'],
'nick' => defaults($g, 'addr', $g['url']),
'network' => $g['network'],
'link' => $g['url'],
'forum' => !empty($g['community']) ? 1 : 0,
];
}
$o = [
'start' => $start,
'count' => $count,
'items' => $contacts,
];
echo json_encode($o);
exit;
}
if (DBA::isResult($r)) {
$forums = [];
foreach ($r as $g) {
$entry = [
'type' => 'c',
'photo' => ProxyUtils::proxifyUrl($g['micro'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlentities($g['name']),
'id' => intval($g['id']),
'network' => $g['network'],
'link' => $g['url'],
'nick' => htmlentities(defaults($g, 'attag', $g['nick'])),
'addr' => htmlentities(defaults($g, 'addr', $g['url'])),
'forum' => !empty($g['forum']) || !empty($g['prv']) ? 1 : 0,
];
if ($entry['forum']) {
$forums[] = $entry;
} else {
$contacts[] = $entry;
}
}
if (count($forums) > 0) {
if ($search == '') {
$forums[] = ['separator' => true];
}
$contacts = array_merge($forums, $contacts);
}
}
$items = array_merge($groups, $contacts);
if ($conv_id) {
// In multi threaded posts the conv_id is not the parent of the whole thread
$parent_item = Item::selectFirst(['parent'], ['id' => $conv_id]);
if (DBA::isResult($parent_item)) {
$conv_id = $parent_item['parent'];
}
/*
* if $conv_id is set, get unknown contacts in thread
* but first get known contacts url to filter them out
*/
$known_contacts = array_map(function ($i) {
return $i['link'];
}, $contacts);
$unknown_contacts = [];
$condition = ["`parent` = ?", $conv_id];
$params = ['order' => ['author-name' => true]];
$authors = Item::selectForUser(local_user(), ['author-link'], $condition, $params);
$item_authors = [];
while ($author = Item::fetch($authors)) {
$item_authors[$author['author-link']] = $author['author-link'];
}
DBA::close($authors);
foreach ($item_authors as $author) {
if (in_array($author, $known_contacts)) {
continue;
}
$contact = Contact::getDetailsByURL($author);
if (count($contact) > 0) {
$unknown_contacts[] = [
'type' => 'c',
'photo' => ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO),
'name' => htmlentities($contact['name']),
'id' => intval($contact['cid']),
'network' => $contact['network'],
'link' => $contact['url'],
'nick' => htmlentities(defaults($contact, 'nick', $contact['addr'])),
'addr' => htmlentities(defaults($contact, 'addr', $contact['url'])),
'forum' => $contact['forum']
];
}
}
$items = array_merge($items, $unknown_contacts);
$tot += count($unknown_contacts);
}
$results = [
'tot' => $tot,
'start' => $start,
'count' => $count,
'groups' => $groups,
'contacts' => $contacts,
'items' => $items,
'type' => $type,
'search' => $search,
];
Addon::callHooks('acl_lookup_end', $results);
$o = [
'tot' => $results['tot'],
'start' => $results['start'],
'count' => $results['count'],
'items' => $results['items'],
];
echo json_encode($o);
exit;
}

File diff suppressed because it is too large Load diff

View file

@ -1,111 +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\System;
use Friendica\Database\DBA;
use Friendica\Model;
use Friendica\Module;
use Friendica\Util\Proxy as ProxyUtils;
require_once 'include/dba.php';
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);
$photo_menu = '';
$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' => $rr['url'],
'itemurl' => defaults($contact_details, 'addr', $rr['url']),
'name' => htmlentities($contact_details['name']),
'thumb' => ProxyUtils::proxifyUrl($contact_details['thumb'], false, ProxyUtils::SIZE_THUMB),
'img_hover' => htmlentities($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 = get_markup_template('viewcontact_template.tpl');
$o .= replace_macros($tpl, [
//'$title' => L10n::t('Friends of %s', htmlentities($c[0]['name'])),
'$tab_str' => $tab_str,
'$contacts' => $entries,
'$paginate' => $pager->renderFull($total),
]);
return $o;
}

View file

@ -1,51 +0,0 @@
<?php
use Friendica\App;
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;
killme();
}

View file

@ -2,19 +2,18 @@
/**
* @file mod/api.php
*/
use Friendica\App;
use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\System;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Module\Login;
require_once 'include/api.php';
require_once __DIR__ . '/../include/api.php';
function oauth_get_client($request)
function oauth_get_client(OAuthRequest $request)
{
$params = $request->get_parameters();
$token = $params['oauth_token'];
@ -37,7 +36,7 @@ function api_post(App $a)
return;
}
if (count($a->user) && x($a->user, 'uid') && $a->user['uid'] != local_user()) {
if (count($a->user) && !empty($a->user['uid']) && $a->user['uid'] != local_user()) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
@ -58,10 +57,10 @@ function api_content(App $a)
} catch (Exception $e) {
echo "<pre>";
var_dump($e);
killme();
exit();
}
if (x($_POST, 'oauth_yes')) {
if (!empty($_POST['oauth_yes'])) {
$app = oauth_get_client($request);
if (is_null($app)) {
return "Invalid request. Unknown token.";
@ -78,11 +77,11 @@ function api_content(App $a)
$glue = "?";
}
$a->internalRedirect($consumer->callback_url . $glue . 'oauth_token=' . OAuthUtil::urlencode_rfc3986($params['oauth_token']) . '&oauth_verifier=' . OAuthUtil::urlencode_rfc3986($verifier));
killme();
exit();
}
$tpl = get_markup_template("oauth_authorize_done.tpl");
$o = replace_macros($tpl, [
$tpl = Renderer::getMarkupTemplate("oauth_authorize_done.tpl");
$o = Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Authorize application connection'),
'$info' => L10n::t('Return to your app and insert this Securty Code:'),
'$code' => $verifier,
@ -103,8 +102,8 @@ function api_content(App $a)
return "Invalid request. Unknown token.";
}
$tpl = get_markup_template('oauth_authorize.tpl');
$o = replace_macros($tpl, [
$tpl = Renderer::getMarkupTemplate('oauth_authorize.tpl');
$o = Renderer::replaceMacros($tpl, [
'$title' => L10n::t('Authorize application connection'),
'$app' => $app,
'$authorize' => L10n::t('Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'),
@ -116,5 +115,5 @@ function api_content(App $a)
}
echo api_call($a);
killme();
exit();
}

View file

@ -1,32 +0,0 @@
<?php
/**
* @file mod/apps.php
*/
use Friendica\Content\Nav;
use Friendica\Core\Config;
use Friendica\Core\L10n;
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 = get_markup_template('apps.tpl');
return replace_macros($tpl, [
'$title' => $title,
'$apps' => $apps,
]);
}

View file

@ -1,56 +0,0 @@
<?php
/**
* @file mod/attach.php
*/
use Friendica\App;
use Friendica\Core\L10n;
use Friendica\Database\DBA;
use Friendica\Util\Security;
require_once 'include/dba.php';
function attach_init(App $a)
{
if ($a->argc != 2) {
notice(L10n::t('Item not available.') . EOL);
return;
}
$item_id = intval($a->argv[1]);
// Check for existence, which will also provide us the owner uid
$r = DBA::selectFirst('attach', [], ['id' => $item_id]);
if (!DBA::isResult($r)) {
notice(L10n::t('Item was not found.'). EOL);
return;
}
$sql_extra = Security::getPermissionsSQLByUserId($r['uid']);
// Now we'll see if we can access the attachment
$r = q("SELECT * FROM `attach` WHERE `id` = '%d' $sql_extra LIMIT 1",
DBA::escape($item_id)
);
if (!DBA::isResult($r)) {
notice(L10n::t('Permission denied.') . EOL);
return;
}
// Use quotes around the filename to prevent a "multiple Content-Disposition"
// error in Chrome for filenames with commas in them
header('Content-type: ' . $r[0]['filetype']);
header('Content-length: ' . $r[0]['filesize']);
if (isset($_GET['attachment']) && $_GET['attachment'] === '0') {
header('Content-disposition: filename="' . $r[0]['filename'] . '"');
} else {
header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"');
}
echo $r[0]['data'];
killme();
// NOTREACHED
}

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