create repo with zip download from github

This commit is contained in:
cafeteroclub 2021-07-19 08:15:56 -03:00
parent c02f2dfbbd
commit 06666b8d98
2159 changed files with 589907 additions and 0 deletions

View File

@ -0,0 +1,14 @@
codecov:
branch: develop
ci:
- drone.friendi.ca
coverage:
precision: 2
round: down
range: "70...100"
status:
project: off
patch: off
comment: off

View File

@ -0,0 +1,10 @@
# editorconfig tool configuration
# see http://editorconfig.org for docs
root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespaces = true
indent_style = tab

2
friendica-2021.01/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Disable LF normalization for all files
* -text

View File

@ -0,0 +1,60 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: Bug
assignees: ''
---
<!--
Please fill out this template with all the information you have. The more info you can provide the easier it will be to help you out or fix the problem you are seeing. For trouble with the UI dont forget to add a screenshot or two. Please do your best!
Please note that this template is only for bugs. Please use other templates in case of feature requests or support requests
Lastly, be sure to preview your issue before saving. Thanks!
-->
- [ ] I have searched open and closed issues for duplicates
<!--
You can search all issues here
https://github.com/friendica/friendica/issues?utf8=%E2%9C%93&q=is%3Aissue
Replace [ ] with [X] once you've searched
-->
### Bug Description
<!-- Give an overall summary of the issue. -->
### Steps to Reproduce
<!-- Using bullet points, list the steps that reproduce the bug. -->
1. step one
2. step two
3. step three
Actual Result:
<!-- Describe the details of the buggy behaviour. -->
Expected Result:
<!-- Describe in detail what the correct behavior should be. -->
### Screenshots
<!-- How to take screenshots on all OSes: https://www.take-a-screenshot.org/
You can drag and drop images into this text box. -->
### Platform Info
Friendica Version:
<!-- You can see Friendicas version number at Help -> About this site -> Site/Friendica Version -->
Friendica Source:
PHP version:
SQL version:

View File

@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Friendica Community Support
url: https://forum.friendi.ca/
about: Please ask and answer questions here.

View File

@ -0,0 +1,22 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: New Feature
assignees: ''
---
### Is the feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Like `I'm always frustrated when [...]`
### Describe the feature you'd like
<!-- A clear and concise description of waht you want to happen. -->
### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or feature you've considered. -->
### Additional context

View File

@ -0,0 +1,10 @@
---
name: Question / Support
about: Select this if you have a question
title: ''
labels: Support Request
assignees: ''
---
# For general question about Friendica, please try to find a solution at https://wiki.friendi.ca first.

View File

@ -0,0 +1,101 @@
name: Testing Friendica
on: [push, pull_request]
jobs:
friendica:
name: Friendica (PHP ${{ matrix.php-versions }})
runs-on: ubuntu-latest
services:
mariadb:
image: mariadb:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: test
MYSQL_PASSWORD: test
MYSQL_USER: test
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
redis:
image: redis
ports:
- 6379/tcp
options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
memcached:
image: memcached
ports:
- 11211/tcp
strategy:
fail-fast: false
matrix:
php-versions: ['7.2', '7.3', '7.4']
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
tools: pecl, composer:v1
extensions: pdo_mysql, gd, zip, opcache, ctype, pcntl, ldap, apcu, memcached, redis, imagick, memcache
coverage: xdebug
ini-values: apc.enabled=1, apc.enable_cli=1
- name: Start mysql service
run: sudo /etc/init.d/mysql start
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get composer cache directory
id: composercache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composercache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --prefer-dist
- name: Copy default Friendica config
run: cp config/local-sample.config.php config/local.config.php
- name: Verify MariaDB connection
env:
PORT: ${{ job.services.mariadb.ports[3306] }}
run: |
while ! mysqladmin ping -h"127.0.0.1" -P"$PORT" --silent; do
sleep 1
done
- name: Setup MYSQL database
env:
PORT: ${{ job.services.mariadb.ports[3306] }}
run: |
mysql -h"127.0.0.1" -P"$PORT" -utest -ptest test < database.sql
- name: Test with Parallel-lint
run: vendor/bin/parallel-lint --exclude vendor/ --exclude view/asset/ .
- name: Test with phpunit
run: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover clover.xml
env:
MYSQL_HOST: 127.0.0.1
MYSQL_PORT: ${{ job.services.mariadb.ports[3306] }}
MYSQL_DATABASE: test
MYSQL_PASSWORD: test
MYSQL_USER: test
REDIS_PORT: ${{ job.services.redis.ports[6379] }}
REDIS_HOST: 127.0.0.1
MEMCACHED_PORT: ${{ job.services.memcached.ports[11211] }}
MEMCACHE_PORT: ${{ job.services.memcached.ports[11211] }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
file: clover.xml

81
friendica-2021.01/.gitignore vendored Normal file
View File

@ -0,0 +1,81 @@
favicon.*
/.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
#ignore documentation, it should be newly built
/doc/html
#ignore reports, should be generated with every build
report/
#ignore config files from eclipse, we don't want IDE files in our repository
.project
.buildpath
.externalToolBuilders
.settings
#ignore OSX .DS_Store files
.DS_Store
#ignore NetBeans IDE's private files (at least)
/nbproject/private/
Ignore config files from VSCode
/.vscode/
#ignore smarty cache
/view/smarty3/compiled/
#ignore cache folders
/privacy_image_cache/
/photo/
/proxy/
nbproject
#ignore vagrant dir
.vagrant/
#ignore local folder
/local/
#ignore config files from Visual Studio
/.vs/
/php_friendica.phpproj
/php_friendica.sln
/php_friendica.phpproj.user
#ignore things from transifex-client
venv/
#ignore Composer dependencies
/vendor
/view/asset
#ignore config files from JetBrains
/.idea
#ignore addons directory
/addons
/addon
#ignore base .htaccess
/.htaccess
#ignore filesystem storage default path
/storage
#Ignore log folder
/log

0
friendica-2021.01/.gitmodules vendored Normal file
View File

View File

@ -0,0 +1,43 @@
# This file is meant to be copied to ".htaccess" on Apache-powered web servers.
# The created .htaccess file can be edited manually and will not be overwritten by Friendica updates.
Options -Indexes
AddType application/x-java-archive .jar
AddType audio/ogg .oga
#AddHandler php53-cgi .php
<FilesMatch "\.(out|log)$">
<IfModule authz_host_module>
#Apache 2.4
Require all denied
</IfModule>
<IfModule !authz_host_module>
#Apache 2.2
Deny from all
</IfModule>
</FilesMatch>
<IfModule mod_rewrite.c>
RewriteEngine on
# Protect repository directory from browsing
RewriteRule "(^|/)\.git" - [F]
# Rewrite current-style URLs of the form 'index.php?pagename=x'.
# Also place auth information into REMOTE_USER for sites running
# in CGI mode.
# If you have troubles or use VirtualDocumentRoot
# uncomment this and set it to the path where your friendica installation is
# i.e.:
# Friendica url: http://some.example.com
# RewriteBase /
# Friendica url: http://some.example.com/friendica
# RewriteBase /friendica/
#
#RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?pagename=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA]
</IfModule>

View File

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

1728
friendica-2021.01/CHANGELOG Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,294 @@
23n
Abinoam P. Marques Jr.
Abraham Pérez Hernández
Abrax
Adam Clark
Adam Jurkiewicz
Adam Magness
Aditoo
AgnesElisa
Albert
Alberto Díaz Tormo
Aleksandr "M.O.Z.G" Dikov
Alex
Alexander An
Alexander Fortin
Alexander Kampmann
Alexandre Alapetite
Alexey Adamov
AlfredSK
Andi
Andi Stadler
Andreas H.
Andreas Neustifter
Andrej Stieben
André Alves
André Lohan
Andy
Andy Hee
Angristan
Anthronaut
Antron Samurai
Arian - Cazare Muncitori
Asher Pen
Athalbert
aweiher
axelt
balderino
Balázs Úr
Beanow
beardyunixer
Beatriz Vital
Beluga
Ben
Ben Roberts
ben-utzer
BinkaDroid
Bjoessi
bufalo1973
ButterflyOfFire
Calango Jr
Carlos Solís
Carsten Pfeiffer
Casper
Cat Gray
Chris Case
Christian González
Christian M. Grube
Christian Vogeley
Christian Wiwie
Cohan Robinson
Copiis Praeesse
CrystalStiletto
Cyboulette
Cyryl Sochacki
czarnystokrotek
Damien Goutte-Gattat
Daniel Dupriest
Daria Początek
David
David Martín Miranda
David Rabel
Dean Townsley
Denis Chenu
dependabot[bot]
Devlon Duthie
Diego Souza
Domovoy
Doru DEACONU
Dylan Thiedeke
Développeur égaré
eddy2508
Eelco Maljaars
effex7
Elena
emilia.krawczyk
Eric Côté
erik
Erkan Yilmaz
Eugene Veresk
Fabian Dost
Fabio Comuni
felixgilles
Filip Bugaj
Filip H.F. "FiXato" Slagter
FlxAlbroscheit
foss
Francesco Apruzzese
Frank Dieckmann
Frederico Gonçalves Guimarães
Gerhard Seeber
gerhard6380
Gert Cauwenberg
GLComo
greeneyedred
Gregory Smith
guzzisti
Haakon Meland Eriksen
Hans Meine
Hauke
Hauke Altmann
Herbert Thielen
hlad
hoergen
Hubert Kościański
Hypolite Petovan
Ilmari
ImgBotApp
irhen
Jakob
Jens Tautenhahn
jensp
Jeroen De Meerleer
jeroenpraat
Joan Bar
JOduMonT
joe slam
Johannes Schwab
John Brazil
Jonatan Nyberg
Jonny Tischbein
Josef Moravek
juanman
julia.domagalska
Julio Cova
Karel
Karolina
Kastal András
Keenan Pepper
Keith Fernie
Klaus Weidenbach
Koyu Berteon
kPherox
Kris
Lea1995polish
Leberwurscht
Leonard Lausen
Lionel Triay
loma-one
loma1
Lorem Ipsum
Ludovic Grossard
Lynn Stephenson
maase2
Mai Anh Nguyen
Manuel Pérez Monís
Marcin Klessa
Marcin Mikołajczak
Marcus Müller
Marie Olive
Mariusz Pisz
marmor
Martin Schmitt
Mateusz Mikos
Mats Sjöberg
Matthew Exon
Matthias
Matthias Moritz
Mauro Batini
Max Weller
mhnxo
Michael Johnston
Michael Vogel
Michal Šupler
Michalina
Mike Macgirvin
miqrogroove
mpanhans
mytbk
nathilia-peirce
Nicola Spanti
nobody
Olaf Conradi
Oliver
Olivier
Olivier Mehani
Olivier Migeot
ozero dien
Paolo Wave
Pascal
Pascal Deklerck
Pavel Morozov
PerigGouanvic
peter
Peter Liebetrau
peturisfeld
Phigger Phigger
Philipp
Philipp Holzer
Pierre Rudloff
Piotr Blonkowski
pokerazor
R C
Rabuzarus
Radek
Rafael Garau
Rain Hawk
Rainulf Pineda
Ralf Thees
Ralph
Ratten
rcmaniac
rebeka-catalina
René Wagner
repat
Ricardo Pereira
Rik 4
RJ Madsen
Roger Meyer
Roland Häder
Rui Andrada
rwa
RyDroid
S.Krumbholz
Sakałoŭ Alaksiej
Sam
Samuli Valavuo
Sandro Santilli
Sebastian Egbers
sella
Seth
Silke Meyer
Simon L'nu
Simó Albert i Beltran
softmetz
soko1
Spencer Dub
St John Karp
Stanislav N.
Steffen K9
StefOfficiel
steve jobs
Sveinn í Felli
Sven Anders
Sylke Vicious
Sylvain Lagacé
Sérgio Lima
Taekus
Tazman DeVille
teho
Thecross
Thomas
Thomas Willingham
thorsten23
Tim Stahel
TiMESPLiNTER
Tino
Tobias Diekershoff
Tobias Hößl
Tom
tomamplius
tomtom84
Tony Baldwin
Torbjörn Andersson
TORminator
trebor
tschlotfeldt
Tubuntu
Tupambae.org
U-SOUND\mike
ufic
Ulf Rompe
Unknown
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
Zane C. Bowers-Hadley
Zered
zotlabs
zottel
Zvi ben Yaakov (a.k.a rdc)
Михаил
Олексій Замковий
朱陈锬

View File

@ -0,0 +1,23 @@
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/ 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/
HTML_FILE_EXTENSION = .html
GENERATE_LATEX = NO
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
GENERATE_TODOLIST = YES
USE_MDFILE_AS_MAINPAGE = README.md
REFERENCED_BY_RELATION = YES
GENERATE_TREEVIEW = YES
ALIASES += "license=@par License:\n"
ALIASES += "fixme=\xrefitem fixme \"Fixme\" \"Fixme List\""
ALIASES += "FIXME=\fixme"
ALIASES += "TODO=\todo"
ALIASES += "BUG=\bug"
ALIASES += "hooks=\xrefitem hooks \"Hooks\" \"Hooks List\""

525
friendica-2021.01/LICENSE Normal file
View File

@ -0,0 +1,525 @@
Friendica Communications Server
Copyright (c) 2010-2020 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a wok means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with t
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
E to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version orch source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.

View File

@ -0,0 +1,46 @@
Friendica Social Communications Server
======================================
Welcome to the free social web.
Friendica is a decentralised communications platform that integrates social communication. Our platform links to independent social projects and corporate services.
Our mission is to free friends, family and colleagues from data-harvesting corporations; we aim for social communication to be free and open, while flowing between any provider as easily as email does.
Friendica connects you effortlessly to a federated communications network of several thousand servers, with more than half a million user registrations. You can directly connect to anyone on [Friendica]( https://friendi.ca), [Mastodon](https://joinmastodon.org/), [Diaspora](https://diasporafoundation.org/), [GnuSocial](https://gnu.io/social/), [Pleroma](https://pleroma.social/), or [Hubzilla](https://hubzilla.org/), regardless where each user profile is hosted.
With Friendica, you can also fully interact with anyone on Twitter, post on Facebook and receive any content on Tumblr, Wordpress or RSS. Friendica allows you to integrate most things on the web via a range of addons such as ITTT, Buffer; you will be able to easily control your own data as you decide.
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, 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, 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, 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, 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")
|*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")
|*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")
|*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")
|*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")
|*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, 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, desktop browser. Community post displayed.*|
## Endorsements
- [![Awesome Humane Tech](images/humane-tech-badge.svg)](https://github.com/humanetech-community/awesome-humane-tech) On August 12th 2020, Friendica was added to [the curated Awesome Humane Tech directory](https://github.com/humanetech-community/awesome-humane-tech) in [the "Fediverse" category](https://github.com/humanetech-community/awesome-humane-tech#fediverse).

View File

@ -0,0 +1 @@
2021.01

43
friendica-2021.01/Vagrantfile vendored Normal file
View File

@ -0,0 +1,43 @@
server_ip = "192.168.22.10"
server_memory = "2048" # MB
server_timezone = "UTC"
public_folder = "/vagrant"
Vagrant.configure(2) do |config|
# 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
# `vagrant box outdated`. This is not recommended.
config.vm.box_check_update = true
# Create a hostname, don't forget to put it to the `hosts` file
# This will point to the server's default virtual host
# TO DO: Make this work with virtualhost along-side xip.io URL
config.vm.hostname = "friendica.local"
# Create a static IP
config.vm.network :private_network, ip: server_ip
# Share a folder between host and guest
# config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", owner: "www-data", group: "vagrant"
config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", owner: "www-data", group: "www-data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
vb.memory = server_memory
end
# Enable provisioning with a shell script.
config.vm.provision "shell", path: "./bin/dev/vagrant_provision.sh"
# run: "always"
# run: "once"
end

279
friendica-2021.01/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

@ -0,0 +1,10 @@
# This file prevents browser access to Friendica command-line scripts on Apache-powered web servers.
# It isn't meant to be edited manually, please check the base Friendica folder for the .htaccess-dist file instead.
<IfModule authz_host_module>
Require all denied
</IfModule>
<IfModule !authz_host_module>
Order Allow,Deny
Deny from all
</IfModule>

View File

@ -0,0 +1,91 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* 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 the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ejabberd extauth script for the integration with friendica
*
* Originally written for joomla by Dalibor Karlovic <dado@krizevci.info>
* modified for Friendica by Michael Vogel <icarus@dabo.de>
* published under GPL
*
* Latest version of the original script for joomla is available at:
* http://87.230.15.86/~dado/ejabberd/joomla-login
*
* Installation:
*
* - Change it's owner to whichever user is running the server, ie. ejabberd
* $ chown ejabberd:ejabberd /path/to/friendica/bin/auth_ejabberd.php
*
* - Change the access mode so it is readable only to the user ejabberd and has exec
* $ chmod 700 /path/to/friendica/bin/auth_ejabberd.php
*
* - Edit your ejabberd.yml file and add after "shaper:":
*
* auth_method: [external]
* extauth_program: "/path/to/friendica/bin/auth_ejabberd.php"
* auth_use_cache: false
*
* - Restart your ejabberd service, you should be able to login with your friendica auth info
*
* Other hints:
* - if your users have a space or a @ in their nickname, they'll run into trouble
* registering with any client so they should be instructed to replace these chars
* " " (space) is replaced with "%20"
* "@" is replaced with "(a)"
*
*/
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice;
use Friendica\App\Mode;
use Friendica\Security\ExAuth;
use Psr\Log\LoggerInterface;
if (sizeof($_SERVER["argv"]) == 0) {
die();
}
$directory = dirname($_SERVER["argv"][0]);
if (substr($directory, 0, 1) != DIRECTORY_SEPARATOR) {
$directory = $_SERVER["PWD"] . DIRECTORY_SEPARATOR . $directory;
}
$directory = realpath($directory . DIRECTORY_SEPARATOR . "..");
chdir($directory);
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabberd']]);
\Friendica\DI::init($dice);
$appMode = $dice->create(Mode::class);
if ($appMode->isNormal()) {
/** @var ExAuth $oAuth */
$oAuth = $dice->create(ExAuth::class);
$oAuth->readStdin();
}

Binary file not shown.

10
friendica-2021.01/bin/console Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
dir=$(cd "${0%[/\\]*}" > /dev/null; pwd)
if [[ -d /proc/cygdrive && $(which php) == $(readlink -n /proc/cygdrive)/* ]]; then
# We are in Cgywin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
fi
php "${dir}/console.php" "$@"

View File

@ -0,0 +1,4 @@
@echo OFF
:: in case DelayedExpansion is on and a path contains !
setlocal DISABLEDELAYEDEXPANSION
php "%~dp0console.php" %*

View File

@ -0,0 +1,36 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* 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 the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice;
use Psr\Log\LoggerInterface;
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]);
(new Friendica\Core\Console($dice, $argv))->execute();

236
friendica-2021.01/bin/daemon.php Executable file
View File

@ -0,0 +1,236 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* 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 the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Run the worker from a daemon.
*
* This script was taken from http://php.net/manual/en/function.pcntl-fork.php
*/
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice;
use Friendica\Core\Logger;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Util\DateTimeFormat;
use Psr\Log\LoggerInterface;
// Get options
$shortopts = 'f';
$longopts = ['foreground'];
$options = getopt($shortopts, $longopts);
// Ensure that daemon.php is executed from the base path of the installation
if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
$directory = dirname($_SERVER["argv"][0]);
if (substr($directory, 0, 1) != "/") {
$directory = $_SERVER["PWD"] . "/" . $directory;
}
$directory = realpath($directory . "/..");
chdir($directory);
}
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']]);
DI::init($dice);
$a = DI::app();
if (DI::mode()->isInstall()) {
die("Friendica isn't properly installed yet.\n");
}
DI::config()->load();
if (empty(DI::config()->get('system', 'pidfile'))) {
die(<<<TXT
Please set system.pidfile in config/local.config.php. For example:
'system' => [
'pidfile' => '/path/to/daemon.pid',
],
TXT
);
}
$pidfile = DI::config()->get('system', 'pidfile');
if (in_array("start", $_SERVER["argv"])) {
$mode = "start";
}
if (in_array("stop", $_SERVER["argv"])) {
$mode = "stop";
}
if (in_array("status", $_SERVER["argv"])) {
$mode = "status";
}
$foreground = array_key_exists('f', $options) || array_key_exists('foreground', $options);
if (!isset($mode)) {
die("Please use either 'start', 'stop' or 'status'.\n");
}
if (empty($_SERVER["argv"][0])) {
die("Unexpected script behaviour. This message should never occur.\n");
}
$pid = null;
if (is_readable($pidfile)) {
$pid = intval(file_get_contents($pidfile));
}
if (empty($pid) && in_array($mode, ["stop", "status"])) {
DI::config()->set('system', 'worker_daemon_mode', false);
die("Pidfile wasn't found. Is the daemon running?\n");
}
if ($mode == "status") {
if (posix_kill($pid, 0)) {
die("Daemon process $pid is running.\n");
}
unlink($pidfile);
DI::config()->set('system', 'worker_daemon_mode', false);
die("Daemon process $pid isn't running.\n");
}
if ($mode == "stop") {
posix_kill($pid, SIGTERM);
unlink($pidfile);
Logger::notice("Worker daemon process was killed", ["pid" => $pid]);
DI::config()->set('system', 'worker_daemon_mode', false);
die("Worker daemon process $pid was killed.\n");
}
if (!empty($pid) && posix_kill($pid, 0)) {
die("Daemon process $pid is already running.\n");
}
Logger::notice('Starting worker daemon.', ["pid" => $pid]);
if (!$foreground) {
echo "Starting worker daemon.\n";
// Switch over to daemon mode.
if ($pid = pcntl_fork()) {
return; // Parent
}
fclose(STDIN); // Close all of the standard
// Enabling this seem to block a running php process with 100% CPU usage when there is an outpout
// fclose(STDOUT); // file descriptors as we
// fclose(STDERR); // are running as a daemon.
DBA::disconnect();
register_shutdown_function('shutdown');
if (posix_setsid() < 0) {
return;
}
if ($pid = pcntl_fork()) {
return; // Parent
}
$pid = getmypid();
file_put_contents($pidfile, $pid);
// We lose the database connection upon forking
DBA::reconnect();
}
DI::config()->set('system', 'worker_daemon_mode', true);
// Just to be sure that this script really runs endlessly
set_time_limit(0);
$wait_interval = intval(DI::config()->get('system', 'cron_interval', 5)) * 60;
$do_cron = true;
$last_cron = 0;
// Now running as a daemon.
while (true) {
if (!$do_cron && ($last_cron + $wait_interval) < time()) {
Logger::info('Forcing cron worker call.', ["pid" => $pid]);
$do_cron = true;
}
if ($do_cron || (!DI::process()->isMaxLoadReached() && Worker::entriesExists() && Worker::isReady())) {
Worker::spawnWorker($do_cron);
} else {
Logger::info('Cool down for 5 seconds', ['pid' => $pid]);
sleep(5);
}
if ($do_cron) {
// We force a reconnect of the database connection.
// This is done to ensure that the connection don't get lost over time.
DBA::reconnect();
$last_cron = time();
}
$start = time();
Logger::info("Sleeping", ["pid" => $pid, 'until' => gmdate(DateTimeFormat::MYSQL, $start + $wait_interval)]);
do {
$seconds = (time() - $start);
// logarithmic wait time calculation.
// Background: After jobs had been started, they often fork many workers.
// To not waste too much time, the sleep period increases.
$arg = (($seconds + 1) / ($wait_interval / 9)) + 1;
$sleep = min(1000000, round(log10($arg) * 1000000, 0));
usleep($sleep);
$timeout = ($seconds >= $wait_interval);
} while (!$timeout && !Worker::IPCJobsExists());
if ($timeout) {
$do_cron = true;
Logger::info("Woke up after $wait_interval seconds.", ["pid" => $pid, 'sleep' => $wait_interval]);
} else {
$do_cron = false;
Logger::info("Worker jobs are calling to be forked.", ["pid" => $pid]);
}
}
function shutdown() {
posix_kill(posix_getpid(), SIGHUP);
}

View File

@ -0,0 +1,113 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
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 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
in your fav editor to check for obvious mistakes and doubled entries.
Initially written by Tobias Diekershoff for the Friendica Project. Released under
the terms of the AGPL version 3 or later, same as Friendica.
"""
from sys import argv
import os, glob, subprocess
# a list of names to not include, those people get into the list by other names
# but they use different names on different systems and automatical mapping does
# 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', 'hoergen oostende', 'Friendica', 'vinzv',
'Vincent Vindarel']
# 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])
print('> base directory is assumed to be: '+path)
# a place to store contributors
contributors = ["Andi Stadler", "Ratten", "Roger Meyer", "Vít Šesták 'v6ak'"]
# get the contributors
print('> getting contributors to the friendica core repository')
p = subprocess.Popen(['git', 'shortlog', '--no-merges', '-s'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
c = iter(p.stdout.readline, b'')
for i in c:
name = i.decode().split('\t')[1].split('\n')[0]
if not name in contributors and name not in dontinclude:
contributors.append(name)
n1 = len(contributors)
print(' > found %d contributors' % n1)
# get the contributors to the addons
try:
os.chdir(path+'/addon')
# get the contributors
print('> getting contributors to the addons')
p = subprocess.Popen(['git', 'shortlog', '--no-merges', '-s'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
c = iter(p.stdout.readline, b'')
for i in c:
name = i.decode().split('\t')[1].split('\n')[0]
if not name in contributors and name not in dontinclude:
contributors.append(name)
except FileNotFoundError:
print(' > no addon directory found ( THE LIST OF CONTRIBUTORS WILL BE INCOMPLETE )')
n2 = len(contributors)
print(' > found %d new contributors' % (n2-n1))
print('> total of %d contributors to the repositories of friendica' % n2)
os.chdir(path)
# get the translators
print('> getting translators')
intrans = False
for f in glob.glob(path+'/view/lang/*/messages.po'):
i = open(f, 'r')
l = i.readlines()
i.close()
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)
if "# Translators:" in ll:
intrans = True
# get the translators from the addons
for f in glob.glob(path+'/addon/*/lang/*/messages.po'):
i = open(f, 'r')
l = i.readlines()
i.close()
for ll in l:
if intrans and ll.strip()=='':
intrans = False;
# 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
n3 = len(contributors)
print(' > found %d translators' % (n3-n2))
print('> found a total of %d contributors and translators' % n3)
contributors.sort(key=str.lower)
f = open(path+'/CREDITS.txt', 'w')
f.write("\n".join(contributors))
f.close()
print('> list saved to CREDITS.txt')

View File

@ -0,0 +1,47 @@
#!/bin/bash
command -v uglifyjs >/dev/null 2>&1 || { echo >&2 "I require UglifyJS but it's not installed. Aborting."; exit 1; }
MINIFY_CMD=uglifyjs
JSFILES=(
"view/js/ajaxupload.js"
"view/js/country.js"
"view/js/main.js"
"vendor/asset/base64/base64.min.js"
"view/theme/frost/js/jquery.divgrow-1.3.1.f1.js"
"view/theme/frost/js/main.js"
"view/theme/frost/js/theme.js"
"view/theme/frost-mobile/js/jquery.divgrow-1.3.1.f1.js"
"view/theme/frost-mobile/js/main.js"
"view/theme/frost-mobile/js/theme.js"
"view/theme/decaf-mobile/js/theme.js"
)
JSFILES2=(
"library/colorbox/jquery.colorbox.js"
)
for i in ${JSFILES[@]}
do
MINFILE=${i%%.js}.min.js
echo "Minifying $i into $MINFILE"
rm $MINFILE
$MINIFY_CMD -o $MINFILE $i
done
for i in ${JSFILES2[@]}
do
MINFILE=${i%%.js}-min.js
echo "Minifying $i into $MINFILE"
rm $MINFILE
$MINIFY_CMD -o $MINFILE $i
done
for i in ${JSFILES3[@]}
do
MINFILE=${i%%_src.js}.js
echo "Minifying $i into $MINFILE"
rm $MINFILE
$MINIFY_CMD -o $MINFILE $i
done

View File

@ -0,0 +1,106 @@
#!/bin/bash
#Script to setup the vagrant instance for running friendica
#
#DO NOT RUN on your physical machine as this won't be of any use
#and f.e. deletes your /var/www/ folder!
echo "Friendica configuration settings"
sudo apt-get update
# Install virtualbox guest additions
sudo apt-get install virtualbox-guest-x11
#Selfsigned cert
echo ">>> Installing *.xip.io self-signed SSL"
SSL_DIR="/etc/ssl/xip.io"
DOMAIN="*.xip.io"
EXTRADOMAIN="friendica.local"
PASSPHRASE="vaprobash"
SUBJ="
C=US/
ST=Connecticut/
O=Vaprobash/
localityName=New Haven/
commonName=$DOMAIN/
subjectAltName=DNS:$EXTRADOMAIN
"
sudo mkdir -p "$SSL_DIR"
sudo openssl genrsa -out "$SSL_DIR/xip.io.key" 4096
sudo openssl req -new -subj "$(echo -n "$SUBJ" | tr "\n" "/")" -key "$SSL_DIR/xip.io.key" -out "$SSL_DIR/xip.io.csr" -passin pass:$PASSPHRASE
sudo openssl x509 -req -days 365 -in "$SSL_DIR/xip.io.csr" -signkey "$SSL_DIR/xip.io.key" -out "$SSL_DIR/xip.io.crt"
#Install apache2
echo ">>> Installing Apache2 webserver"
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
#Install php
echo ">>> Installing PHP7"
sudo apt-get install -y php libapache2-mod-php php-cli php-mysql php-curl php-gd php-mbstring php-xml imagemagick php-imagick php-zip
sudo systemctl restart apache2
#Install mysql
echo ">>> Installing Mysql"
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
# adding grant privileges to mysql root user from everywhere
# thx to http://stackoverflow.com/questions/7528967/how-to-grant-mysql-privileges-in-a-bash-script for this
MYSQL=`which mysql`
Q1="GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;"
Q2="FLUSH PRIVILEGES;"
SQL="${Q1}${Q2}"
$MYSQL -uroot -proot -e "$SQL"
# add a separate database user for friendica
$MYSQL -uroot -proot -e "CREATE USER 'friendica'@'localhost' identified by 'friendica';"
$MYSQL -uroot -proot -e "GRANT ALL PRIVILEGES ON friendica.* TO 'friendica'@'localhost';"
$MYSQL -uroot -proot -e "FLUSH PRIVILEGES"
systemctl restart mysql
#configure rudimentary mail server (local delivery only)
#add Friendica accounts for local user accounts, use email address like vagrant@friendica.local, read the email with 'mail'.
debconf-set-selections <<< "postfix postfix/mailname string friendica.local"
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
# install deps with composer
sudo apt install unzip
cd /var/www
sudo -u www-data php bin/composer.phar install
# initial config file for friendica in vagrant
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
# import test database
$MYSQL -uroot -proot friendica < /vagrant/friendica_test_data.sql
# create cronjob - activate if you have enough memory in you dev VM
echo "*/10 * * * * cd /vagrant; /usr/bin/php bin/worker.php" >> friendicacron
sudo crontab friendicacron
sudo rm friendicacron
# friendica needs write access to /tmp
sudo chmod 777 /tmp

View File

@ -0,0 +1,177 @@
#!/usr/bin/env bash
# Run this as sudo!
# I move this file to /usr/local/bin/vhost and run command 'vhost' from anywhere, using sudo.
#
# Show Usage, Output to STDERR
#
function show_usage {
cat <<- _EOF_
Create a new vHost in Ubuntu Server
Assumes /etc/apache2/sites-available and /etc/apache2/sites-enabled setup used
-d DocumentRoot - i.e. /var/www/yoursite
-h Help - Show this menu.
-s ServerName - i.e. example.com or sub.example.com
-a ServerAlias - i.e. *.example.com or another domain altogether
-p File path to the SSL certificate. Directories only, no file name.
If using an SSL Certificate, also creates a port :443 vhost as well.
This *ASSUMES* a .crt and a .key file exists
at file path /provided-file-path/your-server-or-cert-name.[crt|key].
Otherwise you can except Apache errors when you reload Apache.
Ensure Apache's mod_ssl is enabled via "sudo a2enmod ssl".
-c Certificate filename. "xip.io" becomes "xip.io.key" and "xip.io.crt".
Example Usage. Serve files from /var/www/xip.io at http(s)://192.168.33.10.xip.io
using ssl files from /etc/ssl/xip.io/xip.io.[key|crt]
sudo vhost -d /var/www/xip.io -s 192.168.33.10.xip.io -p /etc/ssl/xip.io -c xip.io
_EOF_
exit 1
}
#
# Output vHost skeleton, fill with userinput
# To be outputted into new file
#
function create_vhost {
cat <<- _EOF_
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName $ServerName
$ServerAlias
DocumentRoot $DocumentRoot
<Directory $DocumentRoot>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
ErrorLog \${APACHE_LOG_DIR}/$ServerName-error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog \${APACHE_LOG_DIR}/$ServerName-access.log combined
</VirtualHost>
_EOF_
}
function create_ssl_vhost {
cat <<- _EOF_
<VirtualHost *:443>
ServerAdmin webmaster@localhost
ServerName $ServerName
$ServerAlias
DocumentRoot $DocumentRoot
<Directory $DocumentRoot>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
ErrorLog \${APACHE_LOG_DIR}/$ServerName-error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog \${APACHE_LOG_DIR}/$ServerName-access.log combined
SSLEngine on
SSLCertificateFile $CertPath/$CertName.crt
SSLCertificateKeyFile $CertPath/$CertName.key
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
BrowserMatch "MSIE [2-6]" \\
nokeepalive ssl-unclean-shutdown \\
downgrade-1.0 force-response-1.0
# MSIE 7 and newer should be able to use keepalive
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</VirtualHost>
_EOF_
}
#Sanity Check - are there two arguments with 2 values?
if [ "$#" -lt 4 ]; then
show_usage
fi
CertPath=""
#Parse flags
while getopts "d:s:a:p:c:h" OPTION; do
case $OPTION in
h)
show_usage
;;
d)
DocumentRoot=$OPTARG
;;
s)
ServerName=$OPTARG
;;
a)
Alias=$OPTARG
;;
p)
CertPath=$OPTARG
;;
c)
CertName=$OPTARG
;;
*)
show_usage
;;
esac
done
# If alias is set:
if [ "$Alias" != "" ]; then
ServerAlias="ServerAlias "$Alias
else
ServerAlias=""
fi
# If CertName doesn't get set, set it to ServerName
if [ "$CertName" == "" ]; then
CertName=$ServerName
fi
if [ ! -d $DocumentRoot ]; then
mkdir -p $DocumentRoot
#chown USER:USER $DocumentRoot #POSSIBLE IMPLEMENTATION, new flag -u ?
fi
if [ -f "$DocumentRoot/$ServerName.conf" ]; then
echo 'vHost already exists. Aborting'
show_usage
else
create_vhost > /etc/apache2/sites-available/${ServerName}.conf
# Add :443 handling
if [ "$CertPath" != "" ]; then
create_ssl_vhost >> /etc/apache2/sites-available/${ServerName}.conf
fi
# Enable Site
cd /etc/apache2/sites-available/ && a2ensite ${ServerName}.conf
service apache2 reload
fi

View File

@ -0,0 +1,111 @@
#!/bin/bash
FULLPATH=$(dirname $(readlink -f "$0"))
if [ "$1" == "--help" -o "$1" == "-h" ]
then
echo "$(basename $(readlink -f "$0")) [options]"
echo
echo "-a | --addon <name> extract strings from addon 'name'"
echo "-s | --single single addon mode: extract string from current folder"
exit
fi
MODE='default'
ADDONNAME=
if [ "$1" == "--addon" -o "$1" == "-a" ]
then
MODE='addon'
if [ -z $2 ]; then echo -e "ERROR: missing addon name\n\nrun_xgettext.sh -a <addonname>"; exit 1; fi
ADDONNAME=$2
if [ ! -d "$FULLPATH/../addon/$ADDONNAME" ]; then echo "ERROR: addon '$ADDONNAME' not found"; exit 2; fi
fi
if [ "$1" == "--single" -o "$1" == "-s" ]
then
MODE='single'
fi
case "$MODE" in
'addon')
cd "$FULLPATH/../addon/$ADDONNAME"
mkdir -p "$FULLPATH/../addon/$ADDONNAME/lang/C"
OUTFILE="$FULLPATH/../addon/$ADDONNAME/lang/C/messages.po"
FINDSTARTDIR="."
FINDOPTS="-path ./vendor -prune -or"
;;
'single')
FULLPATH=$PWD
ADDONNAME=$(basename $FULLPATH)
mkdir -p "$FULLPATH/lang/C"
OUTFILE="$FULLPATH/lang/C/messages.po"
FINDSTARTDIR="."
FINDOPTS="-path ./vendor -prune -or"
echo "Extract strings for single addon '$ADDONNAME'"
;;
'default')
cd "$FULLPATH/.."
OUTFILE="$FULLPATH/../view/lang/C/messages.po"
FINDSTARTDIR="."
# skip addon folder
FINDOPTS="( -path ./addon -or -path ./addons -or -path ./addons-extra -or -path ./tests -or -path ./view/lang -or -path ./view/smarty3 -or -path ./vendor ) -prune -or"
F9KVERSION=$(cat ./VERSION);
echo "Friendica version $F9KVERSION"
;;
esac
KEYWORDS="-k -kt -ktt:1,2"
echo "Extract strings to $OUTFILE.."
rm "$OUTFILE"; touch "$OUTFILE"
find_result=$(find "$FINDSTARTDIR" $FINDOPTS -name "*.php" -type f)
total_files=$(wc -l <<< "${find_result}")
for file in $find_result
do
((count++))
echo -ne " \r"
echo -ne "Reading file $count/$total_files..."
# On Windows, find still outputs the name of pruned folders
if [ ! -d "$file" ]
then
xgettext $KEYWORDS -j -o "$OUTFILE" --from-code=UTF-8 "$file" || exit 1
sed -i "s/CHARSET/UTF-8/g" "$OUTFILE"
fi
done
echo -ne "\n"
echo "Interpolate metadata.."
sed -i "s/^\"Plural-Forms.*$//g" "$OUTFILE"
case "$MODE" in
'addon'|'single')
sed -i "s/SOME DESCRIPTIVE TITLE./ADDON $ADDONNAME/g" "$OUTFILE"
sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER//g" "$OUTFILE"
sed -i "s/FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.//g" "$OUTFILE"
sed -i "s/PACKAGE VERSION//g" "$OUTFILE"
sed -i "s/PACKAGE/Friendica $ADDONNAME addon/g" "$OUTFILE"
;;
'default')
sed -i "s/SOME DESCRIPTIVE TITLE./FRIENDICA Distributed Social Network/g" "$OUTFILE"
sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/2010-$(date +%Y) the Friendica Project/g" "$OUTFILE"
sed -i "s/FIRST AUTHOR <EMAIL@ADDRESS>, YEAR./Mike Macgirvin, 2010/g" "$OUTFILE"
sed -i "s/PACKAGE VERSION/$F9KVERSION/g" "$OUTFILE"
sed -i "s/PACKAGE/Friendica/g" "$OUTFILE"
;;
esac
if [ "" != "$1" -a "$MODE" == "default" ]
then
UPDATEFILE="$(readlink -f ${FULLPATH}/$1)"
echo "Merging new strings to $UPDATEFILE.."
msgmerge -U $OUTFILE $UPDATEFILE
fi
echo "Done."

View File

@ -0,0 +1,38 @@
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* 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 the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* During installation we need to check if register_argc_argv is
* enabled for the command line PHP processor, because otherwise
* deliveries will fail. So we will do a shell exec of php and
* execute this file with a command line argument, and see if it
* echoes the argument back to us. Otherwise notify the person
* that their installation doesn't meet the system requirements.
*
*/
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
if (($_SERVER["argc"] > 1) && isset($_SERVER["argv"][1])) {
echo $_SERVER["argv"][1];
} else {
echo '';
}

View File

@ -0,0 +1,68 @@
#!/usr/bin/php
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* 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 the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* 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}]
*/
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
$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

@ -0,0 +1,85 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* 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 the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Starts the background processing
*/
if (php_sapi_name() !== 'cli') {
header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden');
exit();
}
use Dice\Dice;
use Friendica\App;
use Friendica\Core\Process;
use Friendica\Core\Update;
use Friendica\Core\Worker;
use Friendica\DI;
use Psr\Log\LoggerInterface;
// Get options
$shortopts = 'sn';
$longopts = ['spawn', 'no_cron'];
$options = getopt($shortopts, $longopts);
// Ensure that worker.php is executed from the base path of the installation
if (!file_exists("boot.php") && (sizeof($_SERVER["argv"]) != 0)) {
$directory = dirname($_SERVER["argv"][0]);
if (substr($directory, 0, 1) != '/') {
$directory = $_SERVER["PWD"] . '/' . $directory;
}
$directory = realpath($directory . '/..');
chdir($directory);
}
require dirname(__DIR__) . '/vendor/autoload.php';
$dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php');
$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']]);
DI::init($dice);
$a = DI::app();
// Check the database structure and possibly fixes it
Update::check($a->getBasePath(), true, DI::mode());
// Quit when in maintenance
if (!DI::mode()->has(App\Mode::MAINTENANCEDISABLED)) {
return;
}
DI::baseUrl()->saveByURL(DI::config()->get('system', 'url'));
$spawn = array_key_exists('s', $options) || array_key_exists('spawn', $options);
if ($spawn) {
Worker::spawnWorker();
exit();
}
$run_cron = !array_key_exists('n', $options) && !array_key_exists('no_cron', $options);
Worker::processQueue($run_cron);
Worker::unclaimProcess();
DI::process()->end();

610
friendica-2021.01/boot.php Normal file
View File

@ -0,0 +1,610 @@
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* 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 the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Friendica is a communications platform for integrated social communications
* utilising decentralised communications and linkage to several indie social
* projects - as well as popular mainstream providers.
*
* Our mission is to free our friends and families from the clutches of
* data-harvesting corporations, and pave the way to a future where social
* communications are free and open and flow between alternate providers as
* easily as email does today.
*/
use Friendica\Core\Protocol;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Notify;
use Friendica\Util\BasePath;
use Friendica\Util\DateTimeFormat;
define('FRIENDICA_PLATFORM', 'Friendica');
define('FRIENDICA_CODENAME', 'Red Hot Poker');
define('FRIENDICA_VERSION', '2021.01');
define('DFRN_PROTOCOL_VERSION', '2.23');
define('NEW_UPDATE_ROUTINE_VERSION', 1170);
/**
* Constant with a HTML line break.
*
* Contains a HTML line break (br) element and a real carriage return with line
* feed for the source.
* This can be used in HTML and JavaScript where needed a line break.
*/
define('EOL', "<br />\r\n");
/**
* 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.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
*/
define('PNG_QUALITY', 8);
/**
* 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).
* Modify this value using
*
* 'system' => [
* 'max_image_length' => 'n',
* ...
* ],
*
* 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.
*/
define('MAX_IMAGE_LENGTH', -1);
/**
* Not yet used
*/
define('DEFAULT_DB_ENGINE', 'InnoDB');
/** @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
*
* Type of the community page
* @{
*/
define('CP_NO_INTERNAL_COMMUNITY', -2);
define('CP_NO_COMMUNITY_PAGE', -1);
define('CP_USERS_ON_SERVER', 0);
define('CP_GLOBAL_COMMUNITY', 1);
define('CP_USERS_AND_GLOBAL', 2);
/**
* @}
*/
/**
* These numbers are used in stored permissions
* and existing allocations MUST NEVER BE CHANGED
* OR RE-ASSIGNED! You may only add to them.
*/
$netgroup_ids = [
Protocol::DFRN => (-1),
Protocol::ZOT => (-2),
Protocol::OSTATUS => (-3),
Protocol::FEED => (-4),
Protocol::DIASPORA => (-5),
Protocol::MAIL => (-6),
Protocol::FACEBOOK => (-8),
Protocol::LINKEDIN => (-9),
Protocol::XMPP => (-10),
Protocol::MYSPACE => (-11),
Protocol::GPLUS => (-12),
Protocol::PUMPIO => (-13),
Protocol::TWITTER => (-14),
Protocol::DIASPORA2 => (-15),
Protocol::STATUSNET => (-16),
Protocol::NEWS => (-18),
Protocol::ICALENDAR => (-19),
Protocol::PNUT => (-20),
Protocol::PHANTOM => (-127),
];
/**
* Maximum number of "people who like (or don't like) this" that we will list by name
*/
define('MAX_LIKERS', 75);
/**
* @name Notify
*
* Email notification options
* @{
*/
/** @deprecated since 2020.03, use Notify\Type::INTRO instead */
define('NOTIFY_INTRO', Notify\Type::INTRO);
/** @deprecated since 2020.03, use Notify\Type::CONFIRM instead */
define('NOTIFY_CONFIRM', Notify\Type::CONFIRM);
/** @deprecated since 2020.03, use Notify\Type::WALL instead */
define('NOTIFY_WALL', Notify\Type::WALL);
/** @deprecated since 2020.03, use Notify\Type::COMMENT instead */
define('NOTIFY_COMMENT', Notify\Type::COMMENT);
/** @deprecated since 2020.03, use Notify\Type::MAIL instead */
define('NOTIFY_MAIL', Notify\Type::MAIL);
/** @deprecated since 2020.03, use Notify\Type::SUGGEST instead */
define('NOTIFY_SUGGEST', Notify\Type::SUGGEST);
/** @deprecated since 2020.03, use Notify\Type::PROFILE instead */
define('NOTIFY_PROFILE', Notify\Type::PROFILE);
/** @deprecated since 2020.03, use Notify\Type::TAG_SELF instead */
define('NOTIFY_TAGSELF', Notify\Type::TAG_SELF);
/** @deprecated since 2020.03, use Notify\Type::TAG_SHARE instead */
define('NOTIFY_TAGSHARE', Notify\Type::TAG_SHARE);
/** @deprecated since 2020.03, use Notify\Type::POKE instead */
define('NOTIFY_POKE', Notify\Type::POKE);
/** @deprecated since 2020.03, use Notify\Type::SHARE instead */
define('NOTIFY_SHARE', Notify\Type::SHARE);
/** @deprecated since 2020.12, use Notify\Type::SYSTEM instead */
define('NOTIFY_SYSTEM', Notify\Type::SYSTEM);
/* @}*/
/**
* @name Gravity
*
* Item weight for query ordering
* @{
*/
define('GRAVITY_PARENT', 0);
define('GRAVITY_ACTIVITY', 3);
define('GRAVITY_COMMENT', 6);
define('GRAVITY_UNKNOWN', 9);
/* @}*/
/**
* @name Priority
*
* Process priority for the worker
* @{
*/
define('PRIORITY_UNDEFINED', 0);
define('PRIORITY_CRITICAL', 10);
define('PRIORITY_HIGH', 20);
define('PRIORITY_MEDIUM', 30);
define('PRIORITY_LOW', 40);
define('PRIORITY_NEGLIGIBLE', 50);
define('PRIORITIES', [PRIORITY_CRITICAL, PRIORITY_HIGH, PRIORITY_MEDIUM, PRIORITY_LOW, PRIORITY_NEGLIGIBLE]);
/* @}*/
/**
* @name Social Relay settings
*
* See here: https://github.com/jaywink/social-relay
* and here: https://wiki.diasporafoundation.org/Relay_servers_for_public_posts
* @{
*/
define('SR_SCOPE_NONE', '');
define('SR_SCOPE_ALL', 'all');
define('SR_SCOPE_TAGS', 'tags');
/* @}*/
// Normally this constant is defined - but not if "pcntl" isn't installed
if (!defined("SIGTERM")) {
define("SIGTERM", 15);
}
/**
* Depending on the PHP version this constant does exist - or not.
* See here: http://php.net/manual/en/curl.constants.php#117928
*/
if (!defined('CURLE_OPERATION_TIMEDOUT')) {
define('CURLE_OPERATION_TIMEDOUT', CURLE_OPERATION_TIMEOUTED);
}
/**
* Returns the user id of locally logged in user or false.
*
* @return int|bool user id or false
*/
function local_user()
{
if (!empty($_SESSION['authenticated']) && !empty($_SESSION['uid'])) {
return intval($_SESSION['uid']);
}
return false;
}
/**
* Returns the public contact id of logged in user or false.
*
* @return int|bool public contact id or false
*/
function public_contact()
{
static $public_contact_id = false;
if (!$public_contact_id && !empty($_SESSION['authenticated'])) {
if (!empty($_SESSION['my_address'])) {
// Local user
$public_contact_id = intval(Contact::getIdForURL($_SESSION['my_address'], 0, false));
} elseif (!empty($_SESSION['visitor_home'])) {
// Remote user
$public_contact_id = intval(Contact::getIdForURL($_SESSION['visitor_home'], 0, false));
}
} elseif (empty($_SESSION['authenticated'])) {
$public_contact_id = false;
}
return $public_contact_id;
}
/**
* Returns public contact id of authenticated site visitor or false
*
* @return int|bool visitor_id or false
*/
function remote_user()
{
if (empty($_SESSION['authenticated'])) {
return false;
}
if (!empty($_SESSION['visitor_id'])) {
return intval($_SESSION['visitor_id']);
}
return false;
}
/**
* Show an error message to user.
*
* This function save text in session, to be shown to the user at next page load
*
* @param string $s - Text of notice
*/
function notice($s)
{
if (empty($_SESSION)) {
return;
}
$a = DI::app();
if (empty($_SESSION['sysmsg'])) {
$_SESSION['sysmsg'] = [];
}
if ($a->interactive) {
$_SESSION['sysmsg'][] = $s;
}
}
/**
* Show an info message to user.
*
* This function save text in session, to be shown to the user at next page load
*
* @param string $s - Text of notice
*/
function info($s)
{
$a = DI::app();
if (empty($_SESSION['sysmsg_info'])) {
$_SESSION['sysmsg_info'] = [];
}
if ($a->interactive) {
$_SESSION['sysmsg_info'][] = $s;
}
}
function feed_birthday($uid, $tz)
{
/**
* Determine the next birthday, but only if the birthday is published
* in the default profile. We _could_ also look for a private profile that the
* recipient can see, but somebody could get mad at us if they start getting
* public birthday greetings when they haven't made this info public.
*
* Assuming we are able to publish this info, we are then going to convert
* the start time from the owner's timezone to UTC.
*
* This will potentially solve the problem found with some social networks
* where birthdays are converted to the viewer's timezone and salutations from
* elsewhere in the world show up on the wrong day. We will convert it to the
* viewer's timezone also, but first we are going to convert it from the birthday
* person's timezone to GMT - so the viewer may find the birthday starting at
* 6:00PM the day before, but that will correspond to midnight to the birthday person.
*/
$birthday = '';
if (!strlen($tz)) {
$tz = 'UTC';
}
$profile = DBA::selectFirst('profile', ['dob'], ['uid' => $uid]);
if (DBA::isResult($profile)) {
$tmp_dob = substr($profile['dob'], 5);
if (intval($tmp_dob)) {
$y = DateTimeFormat::timezoneNow($tz, 'Y');
$bd = $y . '-' . $tmp_dob . ' 00:00';
$t_dob = strtotime($bd);
$now = strtotime(DateTimeFormat::timezoneNow($tz));
if ($t_dob < $now) {
$bd = $y + 1 . '-' . $tmp_dob . ' 00:00';
}
$birthday = DateTimeFormat::convert($bd, 'UTC', $tz, DateTimeFormat::ATOM);
}
}
return $birthday;
}
/**
* Check if current user has admin role.
*
* @return bool true if user is an admin
*/
function is_site_admin()
{
$a = DI::app();
$admin_email = DI::config()->get('config', 'admin_email');
$adminlist = explode(',', str_replace(' ', '', $admin_email));
return local_user() && $admin_email && in_array($a->user['email'] ?? '', $adminlist);
}
/**
* Returns the complete URL of the current page, e.g.: http(s)://something.com/network
*
* Taken from http://webcheatsheet.com/php/get_current_page_url.php
*/
function curPageURL()
{
$pageURL = 'http';
if (!empty($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) {
$pageURL .= "s";
}
$pageURL .= "://";
if ($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443") {
$pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
} else {
$pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
}
return $pageURL;
}
function get_temppath()
{
$temppath = DI::config()->get("system", "temppath");
if (($temppath != "") && System::isDirectoryUsable($temppath)) {
// We have a temp path and it is usable
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 != "") && System::isDirectoryUsable($temppath)) {
// Always store the real path, not the path through symlinks
$temppath = BasePath::getRealPath($temppath);
// To avoid any interferences with other systems we create our own directory
$new_temppath = $temppath . "/" . DI::baseUrl()->getHostname();
if (!is_dir($new_temppath)) {
/// @TODO There is a mkdir()+chmod() upwards, maybe generalize this (+ configurable) into a function/method?
mkdir($new_temppath);
}
if (System::isDirectoryUsable($new_temppath)) {
// The new path is usable, we are happy
DI::config()->set("system", "temppath", $new_temppath);
return $new_temppath;
} else {
// We can't create a subdirectory, strange.
// But the directory seems to work, so we use it but don't store it.
return $temppath;
}
}
// Reaching this point means that the operating system is configured badly.
return '';
}
function get_cachefile($file, $writemode = true)
{
$cache = get_itemcachepath();
if ((!$cache) || (!is_dir($cache))) {
return "";
}
$subfolder = $cache . "/" . substr($file, 0, 2);
$cachepath = $subfolder . "/" . $file;
if ($writemode) {
if (!is_dir($subfolder)) {
mkdir($subfolder);
chmod($subfolder, 0777);
}
}
return $cachepath;
}
function clear_cache($basepath = "", $path = "")
{
if ($path == "") {
$basepath = get_itemcachepath();
$path = $basepath;
}
if (($path == "") || (!is_dir($path))) {
return;
}
if (substr(realpath($path), 0, strlen($basepath)) != $basepath) {
return;
}
$cachetime = (int) DI::config()->get('system', 'itemcache_duration');
if ($cachetime == 0) {
$cachetime = 86400;
}
if (is_writable($path)) {
if ($dh = opendir($path)) {
while (($file = readdir($dh)) !== false) {
$fullpath = $path . "/" . $file;
if ((filetype($fullpath) == "dir") && ($file != ".") && ($file != "..")) {
clear_cache($basepath, $fullpath);
}
if ((filetype($fullpath) == "file") && (filectime($fullpath) < (time() - $cachetime))) {
unlink($fullpath);
}
}
closedir($dh);
}
}
}
function get_itemcachepath()
{
// Checking, if the cache is deactivated
$cachetime = (int) DI::config()->get('system', 'itemcache_duration');
if ($cachetime < 0) {
return "";
}
$itemcache = DI::config()->get('system', 'itemcache');
if (($itemcache != "") && System::isDirectoryUsable($itemcache)) {
return BasePath::getRealPath($itemcache);
}
$temppath = get_temppath();
if ($temppath != "") {
$itemcache = $temppath . "/itemcache";
if (!file_exists($itemcache) && !is_dir($itemcache)) {
mkdir($itemcache);
}
if (System::isDirectoryUsable($itemcache)) {
DI::config()->set("system", "itemcache", $itemcache);
return $itemcache;
}
}
return "";
}
/**
* Returns the path where spool files are stored
*
* @return string Spool path
*/
function get_spoolpath()
{
$spoolpath = DI::config()->get('system', 'spoolpath');
if (($spoolpath != "") && System::isDirectoryUsable($spoolpath)) {
// We have a spool path and it is usable
return $spoolpath;
}
// We don't have a working preconfigured spool path, so we take the temp path.
$temppath = get_temppath();
if ($temppath != "") {
// To avoid any interferences with other systems we create our own directory
$spoolpath = $temppath . "/spool";
if (!is_dir($spoolpath)) {
mkdir($spoolpath);
}
if (System::isDirectoryUsable($spoolpath)) {
// The new path is usable, we are happy
DI::config()->set("system", "spoolpath", $spoolpath);
return $spoolpath;
} else {
// We can't create a subdirectory, strange.
// But the directory seems to work, so we use it but don't store it.
return $temppath;
}
}
// Reaching this point means that the operating system is configured badly.
return "";
}
if (!function_exists('exif_imagetype')) {
function exif_imagetype($file)
{
$size = getimagesize($file);
return $size[2];
}
}
function validate_include(&$file)
{
$orig_file = $file;
$file = realpath($file);
if (strpos($file, getcwd()) !== 0) {
return false;
}
$file = str_replace(getcwd() . "/", "", $file, $count);
if ($count != 1) {
return false;
}
if ($orig_file !== $file) {
return false;
}
$valid = false;
if (strpos($file, "include/") === 0) {
$valid = true;
}
if (strpos($file, "addon/") === 0) {
$valid = true;
}
// Simply return flag
return $valid;
}

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="friendica" default="test">
<!-- ====================================================== -->
<!-- Target: clean-test -->
<!-- deletes directories with old test reports -->
<!-- ====================================================== -->
<target name="clean-test">
<delete dir="report" />
</target>
<!-- ====================================================== -->
<!-- Target: prepare-test -->
<!-- creates directories for test reports -->
<!-- ====================================================== -->
<target name="prepare-test" depends="clean-test">
<mkdir dir="report" />
</target>
<!-- =================================== -->
<!-- Target: test -->
<!-- this target runs all test files -->
<!-- =================================== -->
<target name="test" depends="prepare-test">
<!-- coverage-setup database="./report/coverage-database">
<fileset dir=".">
<include name="**/*.php" />
<exclude name="*test.php"/>
<exclude name="index.php"/>
<exclude name="library/**"/>
<exclude name="doc/**"/>
<exclude name=".."/>
</fileset>
</coverage-setup -->
<phpunit printsummary="true">
<batchtest>
<fileset dir="tests">
<include name="*test.php" />
</fileset>
</batchtest>
<formatter type="xml" todir="report" outfile="testlog.xml" />
</phpunit>
<phpunitreport infile="report/testlog.xml" todir="report" />
<!-- coverage-report outfile="report/coverage-database">
<report todir="report" styledir="/home/phing/etc" />
</coverage-report -->
</target>
<!-- ===================================================== -->
<!-- Target: clean-doc -->
<!-- this target removes documentation from a previous run -->
<!-- ===================================================== -->
<target name="doc-clean">
<echo msg="Removing old documentation..." />
<delete dir="./doc/api/" />
<echo msg="Generate documentation directory..." />
<mkdir dir="./doc/api/" />
</target>
<!-- ====================================== -->
<!-- Target: doc -->
<!-- this target builds all documentation -->
<!-- ====================================== -->
<target name="doc" depends="doc-clean">
<echo msg="Building documentation..." />
<docblox title="Friendica API" destdir="./doc/api">
<fileset dir=".">
<include name="**/*.php" />
<include name="README"/>
<include name="INSTALL.txt"/>
<include name="LICENSE"/>
</fileset>
</docblox>
</target>
</project>

View File

@ -0,0 +1,136 @@
{
"name": "friendica/friendica",
"description": "A decentralized social network part of The Federation",
"type": "project",
"keywords": [
"social network",
"dfrn",
"ostatus",
"diaspora"
],
"license": "AGPL-3.0+",
"support": {
"issues": "https://github.com/friendica/friendica/issues"
},
"require": {
"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.8",
"ezyang/htmlpurifier": "^4.7",
"friendica/json-ld": "^1.0",
"league/html-to-markdown": "^4.8",
"level-2/dice": "^4",
"lightopenid/lightopenid": "dev-master",
"matriphe/iso-639": "^1.2",
"michelf/php-markdown": "^1.7",
"mobiledetect/mobiledetectlib": "^2.8",
"monolog/monolog": "^1.25",
"nikic/fast-route": "^1.3",
"paragonie/hidden-string": "^1.0",
"patrickschur/language-detection": "^3.4",
"pear/console_table": "^1.3",
"phpseclib/phpseclib": "^2.0",
"pragmarx/google2fa": "^5.0",
"pragmarx/recovery": "^0.1.0",
"psr/container": "^1.0",
"seld/cli-prompt": "^1.0",
"smarty/smarty": "^3.1",
"xemlock/htmlpurifier-html5": "^0.1.11",
"fxp/composer-asset-plugin": "^1.4",
"bower-asset/base64": "^1.0",
"bower-asset/chart-js": "^2.8",
"bower-asset/dompurify": "^1.0",
"bower-asset/fork-awesome": "^1.1",
"bower-asset/vue": "^2.6",
"npm-asset/cropperjs": "1.2.2",
"npm-asset/es-jquery-sortable": "^0.9.13",
"npm-asset/fullcalendar": "^3.10",
"npm-asset/imagesloaded": "4.1.4",
"npm-asset/jquery": "^2.0",
"npm-asset/jquery-colorbox": "^1.6",
"npm-asset/jquery-datetimepicker": "^2.5",
"npm-asset/jgrowl": "^1.4",
"npm-asset/moment": "^2.24",
"npm-asset/perfect-scrollbar": "0.6.16",
"npm-asset/textcomplete": "^0.18.2",
"npm-asset/typeahead.js": "^0.11.1"
},
"repositories": [
{
"type": "vcs",
"url": "https://git.friendi.ca/friendica/php-json-ld"
}
],
"autoload": {
"psr-4": {
"Friendica\\": "src/",
"Friendica\\Addon\\": "addon/"
},
"files": [
"include/conversation.php",
"include/dba.php",
"include/enotify.php",
"boot.php"
]
},
"autoload-dev": {
"psr-4": {
"Friendica\\Test\\": "tests/"
}
},
"config": {
"platform": {
"php": "7.0"
},
"autoloader-suffix": "Friendica",
"optimize-autoloader": true,
"preferred-install": "dist",
"fxp-asset": {
"installer-paths": {
"npm-asset-library": "view/asset",
"bower-asset-library": "view/asset"
}
}
},
"archive": {
"exclude": [
"/.*",
"/*file",
"!/.htaccess-dist",
"/tests",
"/*.xml",
"/composer.*",
"/log",
"/cache",
"/photo",
"/proxy",
"/addon",
"!/vendor",
"!/view/asset"
]
},
"require-dev": {
"phpdocumentor/reflection-docblock": "^3.0.2",
"phpunit/php-token-stream": "^1.4.2",
"mikey179/vfsstream": "^1.6",
"mockery/mockery": "^1.2",
"johnkary/phpunit-speedtrap": "1.1",
"php-parallel-lint/php-parallel-lint": "^1.2"
},
"scripts": {
"test": "phpunit"
}
}

5165
friendica-2021.01/composer.lock generated Normal file

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

@ -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',
],
];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,703 @@
# Friendica API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following specific endpoints.
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints uses the [Friendica API entities](help/API-Entities).
## Endpoints
### GET api/friendica/events
Returns a list of [Event](help/API-Entities#Event) entities for the current logged in user.
#### Parameters
- `since_id`: (optional) minimum event id for pagination
- `count`: maximum number of items returned, default 20
### GET api/externalprofile/show
Returns a [Contact](help/API-Entities#Contact) entity for the provided profile URL.
#### Parameters
- `profileurl`: Profile URL
### GET api/statuses/public_timeline
Returns a list of public [Items](help/API-Entities#Item) posted on this node.
Equivalent of the local community page.
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `exclude_replies`: don't show replies (default: false)
* `conversation_id`: Shows all statuses of a given conversation.
* `include_entities`: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
* `trim_user`
### GET api/statuses/networkpublic_timeline
Returns a list of public [Items](help/API-Entities#Item) this node is aware of.
Equivalent of the global community page.
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `exclude_replies`: don't show replies (default: false)
* `conversation_id`: Shows all statuses of a given conversation.
* `include_entities`: "true" shows entities for pictures and links (Default: false)
### GET api/statuses/replies
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `include_entities`: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
* `include_rts`
* `trim_user`
* `contributor_details`
---
### GET api/conversation/show
Unofficial Twitter command. It shows all direct answers (excluding the original post) to a given id.
#### Parameters
* `id`: id of the post
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `include_entities`: "true" shows entities for pictures and links (Default: false)
#### Unsupported parameters
* `include_rts`
* `trim_user`
* `contributor_details`
### GET api/statusnet/conversation
Alias of [`api/conversation/show`](#GET+api%2Fconversation%2Fshow).
### GET api/statusnet/config
Returns the public Friendica node configuration.
### GET api/gnusocial/config
Alias of [`api/statusnet/config`](#GET+api%2Fstatusnet%2Fconfig).
### GET api/statusnet/version
Returns a fake static StatusNet protocol version.
### GET api/gnusocial/version
Alias of [`api/statusnet/version`](#GET+api%2Fstatusnet%2Fversion).
---
### POST api/friendica/activity/[verb]
Add or remove an activity from an item.
'verb' can be one of:
* `like`
* `dislike`
* `attendyes`
* `attendno`
* `attendmaybe`
To remove an activity, prepend the verb with "un", eg. "unlike" or "undislike"
Attend verbs disable eachother: that means that if "attendyes" was added to an item, adding "attendno" remove previous "attendyes".
Attend verbs should be used only with event-related items (there is no check at the moment).
#### Parameters
* `id`: item id
#### Return values
On success:
json:
```"ok"```
xml:
```<ok>true</ok>```
On error:
HTTP 400 BadRequest
---
### GET api/direct_messages
Deprecated Twitter received direct message list endpoint.
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `include_entities`: "true" shows entities for pictures and links (Default: false)
* `friendica_verbose`: "true" enables different error returns (default: "false")
#### Unsupported parameters
* `skip_status`
### GET api/direct_messages/all
Returns all [Private Messages](help/API-Entities#Private+message).
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `friendica_verbose`: "true" enables different error returns (default: "false")
### GET api/direct_messages/conversation
Returns all replies of a single private message conversation. Returns [Private Messages](help/API-Entities#Private+message)
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `uri`: URI of the conversation
* `friendica_verbose`: "true" enables different error returns (default: "false")
### GET api/direct_messages/sent
Deprecated Twitter sent direct message list endpoint. Returns [Private Messages](help/API-Entities#Private+message).
#### Parameters
* `count`: Items per page (default: 20)
* `page`: page number
* `since_id`: minimum id
* `max_id`: maximum id
* `getText`: Defines the format of the status field. Can be "html" or "plain"
* `include_entities`: "true" shows entities for pictures and links (Default: false)
* `friendica_verbose`: "true" enables different error returns (default: "false")
### POST/PUT api/direct_messages/new
Deprecated Twitter direct message submission endpoint.
#### Parameters
* `user_id`: id of the user
* `screen_name`: screen name (for technical reasons, this value is not unique!)
* `text`: The message
* `replyto`: ID of the replied direct message
* `title`: Title of the direct message
### POST/DELETE api/direct_messages/destroy
Deprecated Twitter direct message deletion endpoint.
#### Parameters
* `id`: id of the message to be deleted
* `include_entities`: optional, currently not yet implemented
* `friendica_parenturi`: optional, can be used for increased safety to delete only intended messages
* `friendica_verbose`: "true" enables different error returns (default: "false")
#### Return values
On success:
* JSON return as defined for Twitter API not yet implemented
* on friendica_verbose=true: JSON return {"result":"ok","message":"message deleted"}
On error:
HTTP 400 BadRequest
* on friendica_verbose=true: different JSON returns {"result":"error","message":"xyz"}
### GET api/friendica/direct_messages_setseen
#### Parameters
* `id`: id of the message to be updated as seen
#### Return values
On success:
* JSON return `{"result": "ok", "message": "message set to seen"}`
On error:
* different JSON returns `{"result": "error", "message": "xyz"}`
### GET api/friendica/direct_messages_search (GET; AUTH)
Returns [Private Messages](help/API-Entities#Private+message) matching the provided search string.
#### Parameters
* `searchstring`: string for which the API call should search as '%searchstring%' in field 'body' of all messages of the authenticated user (caption ignored)
* `getText` (optional): `plain`|`html` If ommited, the title is prepended to the plaintext body in the `text` attribute of the private message objects.
* `getUserObjects` (optional): `true`|`false` If `false`, the `sender` and `recipient` attributes of the private message object are absent.
#### Return values
Returns only tested with JSON, XML might work as well.
On success:
* JSON return `{"success":"true", "search_results": array of found messages}`
* JSOn return `{"success":"false", "search_results": "nothing found"}`
On error:
* different JSON returns `{"result": "error", "message": "searchstring not specified"}`
---
### GET api/friendica/group_show
Return all or a specified group of the user with the containing contacts as array.
#### Parameters
* `gid`: optional, if not given, API returns all groups of the user
#### Return values
Array of:
* `name`: name of the group
* `gid`: id of the group
* `user`: array of [Contacts](help/API-Entities#Contact)
### POST/PUT api/friendica/group_create
Create the group with the posted array of contacts as members.
#### Parameters
* `name`: name of the group to be created
#### POST data
JSON data as Array like the result of [GET api/friendica/group_show](#GET+api%2Ffriendica%2Fgroup_show):
* `gid`
* `name`
* List of [Contacts](help/API-Entities#Contact)
#### Return values
Array of:
* `success`: true if successfully created or reactivated
* `gid`: gid of the created group
* `name`: name of the created group
* `status`: "missing user" | "reactivated" | "ok"
* `wrong users`: array of users, which were not available in the contact table
### POST api/friendica/group_update
Update the group with the posted array of contacts as members (post all members of the group to the call; function will remove members not posted).
#### Parameters
* `gid`: id of the group to be changed
* `name`: name of the group to be changed
#### POST data
JSON data as array like the result of [GET api/friendica/group_show](#GET+api%2Ffriendica%2Fgroup_show):
* `gid`
* `name`
* List of [Contacts](help/API-Entities#Contact)
#### Return values
Array of:
* `success`: true if successfully updated
* `gid`: gid of the changed group
* `name`: name of the changed group
* `status`: "missing user" | "ok"
* `wrong users`: array of users, which were not available in the contact table
### POST/DELETE api/friendica/group_delete
Delete the specified group of contacts; API call need to include the correct gid AND name of the group to be deleted.
#### Parameters
* `gid`: id of the group to be deleted
* `name`: name of the group to be deleted
#### Return values
Array of:
* `success`: true if successfully deleted
* `gid`: gid of the deleted group
* `name`: name of the deleted group
* `status`: "deleted" if successfully deleted
* `wrong users`: empty array
---
### GET api/friendica/notifications
Return last 50 [Notifications](help/API-Entities#Notification) for the current user, ordered by date with unseen item on top.
#### Parameters
none
### POST api/friendica/notifications/seen
Set notification as seen.
#### Parameters
- `id`: id of the notification to set seen
#### Return values
If the note is linked to an item, returns an [Item](help/API-Entities#Item).
Otherwise, a success status is returned:
* `success` (json) | `<status>success</status>` (xml)
---
### GET api/friendica/photo
Returns a [Photo](help/API-Entities#Photo).
#### Parameters
* `photo_id`: Resource id of a photo.
* `scale`: (optional) scale value of the photo
Returns data of a picture with the given resource.
If 'scale' isn't provided, returned data include full url to each scale of the photo.
If 'scale' is set, returned data include image data base64 encoded.
possibile scale value are:
* 0: original or max size by server settings
* 1: image with or height at <= 640
* 2: image with or height at <= 320
* 3: thumbnail 160x160
* 4: Profile image at 300x300
* 5: Profile image at 80x80
* 6: Profile image at 48x48
An image used as profile image has only scale 4-6, other images only 0-3
#### Return values
json:
```json
{
"id": "photo id",
"created": "date(YYYY-MM-DD HH:MM:SS)",
"edited": "date(YYYY-MM-DD HH:MM:SS)",
"title": "photo title",
"desc": "photo description",
"album": "album name",
"filename": "original file name",
"type": "mime type",
"height": "number",
"width": "number",
"profile": "1 if is profile photo",
"link": {
"<scale>": "url to image",
...
},
// if 'scale' is set
"datasize": "size in byte",
"data": "base64 encoded image data"
}
```
xml:
```xml
<photo>
<id>photo id</id>
<created>date(YYYY-MM-DD HH:MM:SS)</created>
<edited>date(YYYY-MM-DD HH:MM:SS)</edited>
<title>photo title</title>
<desc>photo description</desc>
<album>album name</album>
<filename>original file name</filename>
<type>mime type</type>
<height>number</height>
<width>number</width>
<profile>1 if is profile photo</profile>
<links type="array">
<link type="mime type" scale="scale number" href="image url"/>
...
</links>
</photo>
```
### GET api/friendica/photos/list
Returns the API user's [Photo List Items](help/API-Entities#Photo+List+Item).
#### Return values
json:
```json
[
{
"id": "resource_id",
"album": "album name",
"filename": "original file name",
"type": "image mime type",
"thumb": "url to thumb sized image"
},
...
]
```
xml:
```xml
<photos type="array">
<photo id="resource_id"
album="album name"
filename="original file name"
type="image mime type">
"url to thumb sized image"
</photo>
...
</photos>
```
### POST api/friendica/photo/create
Alias of [`api/friendica/photo/update`](#POST+api%2Ffriendica%2Fphoto%2Fupdate)
### POST api/friendica/photo/update
Saves data for the scales 0-2 to database (see above for scale description).
Call adds non-public entries to items table to enable authenticated contacts to comment/like the photo.
Client should pay attention to the fact that updated access rights are not transferred to the contacts. i.e. public photos remain publicly visible if they have been commented/liked before setting visibility back to a limited group.
Currently it is best to inform user that updating rights is not the right way to do this, and offer a solution to add photo as a new photo with the new rights instead.
#### Parameters
* `photo_id` (optional): if specified the photo with this id will be updated
* `media` (optional): image data as base64, only optional if photo_id is specified (new upload must have media)
* `desc` (optional): description for the photo, updated when photo_id is specified
* `album`: name of the album to be deleted (always necessary)
* `album_new` (optional): can be used to change the album of a single photo if photo_id is specified
* `allow_cid`/`allow_gid`/`deny_cid`/`deny_gid` (optional):
- on create: empty string or omitting = public photo, specify in format ```<x><y><z>``` for private photo
- on update: keys need to be present with empty values for changing a private photo to public
#### Return values
On success:
* new photo uploaded: JSON return with photo data (see [GET api/friendica/photo](#GET+api%2Ffriendica%2Fphoto))
* photo updated - changed photo data: JSON return with photo data (see [GET api/friendica/photo](#GET+api%2Ffriendica%2Fphoto))
* photo updated - changed info: JSON return `{"result": "updated", "message":"Image id 'xyz' has been updated."}`
* photo updated - nothing changed: JSON return `{"result": "cancelled","message": "Nothing to update for image id 'xyz'."}`
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no albumname specified", "no media data submitted", "photo not available", "acl data invalid"
* 500 INTERNALSERVERERROR: "image size exceeds PHP config settings, file was rejected by server",
"image size exceeds Friendica Config setting (uploaded size: x)",
"unable to process image data",
"image upload failed",
"unknown error - uploading photo failed, see Friendica log for more information",
"unknown error - update photo entry in database failed",
"unknown error - this error on uploading or updating a photo should never happen"
### DELETE api/friendica/photo/delete
Deletes a single image with the specified id, is not reversible -> ensure that client is asking user for being sure to do this
Sets item table entries for this photo to deleted = 1.
#### Parameters
* `photo_id`: id of the photo to be deleted
#### Return values
On success:
* JSON return
```json
{
"result": "deleted",
"message": "photo with id 'xyz' has been deleted from server."
}
```
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no photo_id specified", "photo not available"
* 500 INTERNALSERVERERROR: "unknown error on deleting photo", "problem with deleting items occurred"
---
### POST/DELETE api/friendica/photoalbum/delete
Deletes all images with the specified album name, is not reversible -> ensure that client is asking user for being sure to do this.
#### Parameters
* `album`: name of the album to be deleted
#### Return values
On success:
* JSON return
```json
{
"result": "deleted",
"message": "album 'xyz' with all containing photos has been deleted."
}
```
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no albumname specified", "album not available"
* 500 INTERNALSERVERERROR: "problem with deleting item occured", "unknown error - deleting from database failed"
### POST/PUT api/friendica/photoalbum/update
Changes the album name to album_new for all photos in album.
#### Parameters
* `album`: name of the album to be updated
* `album_new`: new name of the album
#### Return values
On success:
* JSON return
```json
{
"result": "updated",
"message":"album 'abc' with all containing photos has been renamed to 'xyz'."
}
```
On error:
* 403 FORBIDDEN: if not authenticated
* 400 BADREQUEST: "no albumname specified", "no new albumname specified", "album not available"
* 500 INTERNALSERVERERROR: "unknown error - updating in database failed"
---
### GET api/friendica/profile/show
Returns the [Profile](help/API-Entities#Profile) data of the authenticated user.
#### Return values
On success: Array of:
* `global_dir`: URL of the global directory set in server settings
* `friendica_owner`: user data of the authenticated user
* `profiles`: array of the profile data
On error:
HTTP 403 Forbidden: when no authentication was provided
HTTP 400 Bad Request: if given profile_id is not in the database or is not assigned to the authenticated user
General description of profile data in API returns:
- hide_friends: true if friends are hidden
- profile_photo
- profile_thumb
- publish: true if published on the server's local directory
- net_publish: true if published to global_dir
- fullname
- date_of_birth
- description
- xmpp
- homepage
- address
- locality
- region
- postal_code
- country
- pub_keywords
- custom_fields: list of public custom fields
---
### GET api/friendica/remoteauth
Similar as /redir, redirects to `url` after DFRN authentication.
#### Parameters
- `c_url`: url of remote contact to auth to
- `url`: string, url to redirect after auth
## Deprecated endpoints
- POST api/statuses/mediap

View File

@ -0,0 +1,81 @@
# GNU Social API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following endpoints defined in [the official GNU Social Twitter-like API reference](https://gnusocial.net/doc/twitterapi).
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints use the [Friendica API entities](help/API-Entities).
## Implemented endpoints
- GET api/account/rate_limit_status
- POST api/account/update_profile_image
- GET api/account/verify_credentials
- GET api/direct_messages
- POST/DELETE api/direct_messages/destroy
- POST api/direct_messages/new
- GET api/direct_messages/sent
- GET api/favorites
- POST api/favorites/create/:id
- POST api/favorites/destroy/:id
- GET api/followers/ids
- POST api/friendships/destroy
- GET api/friends/ids
- GET/POST api/help/test
- POST api/oauth/access_token
- POST api/oauth/request_token
- GET api/search
- GET api/statuses/show/:id
- POST api/statuses/destroy/:id
- GET api/statuses/followers
- GET api/statuses/friends
- GET api/statuses/friends_timeline
- GET api/statuses/friends_timeline/:username
- GET api/statuses/home_timeline
- GET api/statuses/mentions
- GET api/statuses/replies
- GET api/statuses/replies/:username
- POST api/statuses/retweet/:id
- GET api/statuses/public_timeline
- POST api/statuses/update
- GET api/statuses/user_timeline
- GET api/users/show
## Non-implemented endpoints
- statuses/retweeted_to_me
- statuses/retweeted_by_me
- statuses/retweets_of_me
- friendships/create
- friendships/exists
- friendships/show
- account/end_session
- account/update_delivery_device
- account/update_profile_background_image
- notifications/follow
- notifications/leave
- blocks/create
- blocks/destroy
- blocks/exists
- blocks/blocking
- oauth/authorize
- statusnet/groups/timeline
- statusnet/groups/show
- statusnet/groups/create
- statusnet/groups/join
- statusnet/groups/leave
- statusnet/groups/list
- statusnet/groups/list_all
- statusnet/groups/membership
- statusnet/groups/is_member
- statusnet/tags/timeline
- statusnet/media/upload
- statusnet/config

View File

@ -0,0 +1,44 @@
# Mastodon API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following endpoints defined in [the official Mastodon API reference](https://docs.joinmastodon.org/api/).
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/entities/).
## Implemented endpoints
- [`GET /api/v1//accounts/:id`](https://docs.joinmastodon.org/methods/accounts/#retrieve-information)
- [`GET /api/v1//accounts/:id/statuses`](https://docs.joinmastodon.org/methods/accounts/#retrieve-information)
- [`GET /api/v1/custom_emojis`](https://docs.joinmastodon.org/methods/instance/custom_emojis/)
- Doesn't return unicode emojis since they aren't using an image URL
- [`GET /api/v1/directory`](https://docs.joinmastodon.org/methods/instance/directory/)
- [`GET /api/v1/follow_requests`](https://docs.joinmastodon.org/methods/accounts/follow_requests#pending-follows)
- Returned IDs are specific to follow requests
- [`POST /api/v1/follow_requests/:id/authorize`](https://docs.joinmastodon.org/methods/accounts/follow_requests#accept-follow)
- `:id` is a follow request ID, not a regular account id
- [`POST /api/v1/follow_requests/:id/reject`](https://docs.joinmastodon.org/methods/accounts/follow_requests#reject-follow)
- `:id` is a follow request ID, not a regular account id
- `POST /api/v1/follow_requests/:id/ignore`
- Friendica-specific, hides the follow request from the list and prevents the remote contact from retrying.
- `:id` is a follow request ID, not a regular account id
- Returns a [Relationship](https://docs.joinmastodon.org/entities/relationship) object.
- [`GET /api/v1/instance`](https://docs.joinmastodon.org/methods/instance#fetch-instance)
- [`GET /api/v1/instance/peers`](https://docs.joinmastodon.org/methods/instance#list-of-connected-domains)
- [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/)
- [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/)
## Non-implemented endpoints
- [`GET /api/v1/instance/activity`](https://docs.joinmastodon.org/methods/instance#weekly-activity)

View File

@ -0,0 +1,306 @@
# Twitter API
* [Home](help)
* [Using the APIs](help/api)
## Overview
Friendica provides the following endpoints defined in the [official Twitter API reference](https://developer.twitter.com/en/docs/api-reference-index).
Authentication is the same as described in [Using the APIs](help/api#Authentication).
## Entities
These endpoints use the [Friendica API entities](help/API-Entities).
## Different behaviour
* `screen_name`: The nick name in Friendica is only unique in each network but not for all networks. The users are searched in the following priority: Friendica, StatusNet/GNU Social, Diaspora, pump.io, Twitter. If no contact was found by this way, then the first contact is taken.
* `include_entities`: Default is "false". If set to "true" then the plain text is formatted so that links are having descriptions.
## Friendica-specific return values
* `cid`: Contact id of the user (important for "contact_allow" and "contact_deny")
* `network`: network of the user
## Unsupported parameters
* `cursor`
* `trim_user`
* `contributor_details`
* `place_id`
* `display_coordinates`
* `include_rts`: To-Do
* `include_my_retweet`: Retweets in Friendica are implemented in a different way
## Implemented endpoints
- [POST api/oauth/access_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token)
- Unsupported parameters:
- `x_auth_password`
- `x_auth_username`
- `x_auth_mode`
- [POST api/oauth/request_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/request_token)
- Unsupported parameter:
- `x_auth_access_type`
- [GET api/account/verify_credentials](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials)
- Unsupported parameter:
- `include_email`
- [POST api/account/update_profile](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile)
- Unsupported parameters:
- `url`
- `location`
- `profile_link_color`
- `include_entities`
- `skip_status`
- [POST api/account/update_profile_image](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image)
- Additional parameter:
- `profile_id` (optional): Numerical id of the profile for which the image should be used, default is changing the default profile.
- [POST api/statuses/update](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update)
- Unsupported parameter:
- `display_coordinates`
- [POST api/statuses/update_with_media (deprecated)](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update_with_media)
- [POST api/media/upload](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload)
- Additional return value:
- `image.friendica_preview_url`: image preview url
- [POST api/media/metadata/create](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create)
- [GET api/users/show](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show)
- [GET api/users/search](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search)
- Unsupported parameters:
- `page`
- `count`
- `include_entities`
- [GET api/users/lookup](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-lookup)
- Unsupported parameters:
- `screen_name`
- `include_entities`
- [GET api/search/tweets](https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets)
- Unsupported parameters:
- `geocode`
- `lang`
- `locale`
- `result_type`
- `until`
- `include_entities`
- [GET api/saved_searches/list](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-saved_searches-list)
- [GET api/statuses/home_timeline](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-home_timeline)
- Alias: `GET api/statuses/friends_timeline`
- [GET api/statuses/user_timeline](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline)
- [GET api/statuses/mentions (deprecated)](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-mentions_timeline)
- [GET api/statuses/show/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-show-id)
- [POST api/statuses/retweet/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id)
- [POST api/statuses/destroy/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-destroy-id)
- [GET api/statuses/followers (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list)
- Alias: `GET api/statuses/friends`
- [GET api/favorites (deprecated)](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-favorites-list)
- Unsupported parameters:
- `user_id`: Favorites aren't returned for other users than self
- `screen_name`: Favorites aren't returned for other users than self
- [POST api/favorites/create](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-create)
- [POST api/favorites/destroy](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-destroy)
- [GET api/lists/list](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list)
- [GET api/lists/ownerships](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships)
- Unsupported parameters:
- `slug`
- `owner_screen_name`
- `owner_id`
- `include_entities`
- [GET api/lists/statuses](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-statuses)
- Unsupported parameters:
- `screen_name`
- `count`
- [GET api/lists/subscriptions](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscriptions)
- [POST api/lists/update](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update)
- Unsupported parameters:
- `slug`
- `name`
- `mode`
- `description`
- `owner_screen_name`
- `owner_id`
- [POST api/lists/create](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-create)
- Unsupported parameters:
- `mode`
- `description`
- [POST api/lists/destroy](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy)
- Unsupported parameters:
- `owner_screen_name`
- `owner_id`
- `slug`
- [GET api/blocks/list](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-list)
- [GET api/friendships/incoming](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-incoming)
- Unsupported parameters
- `stringify_ids`
- - [GET api/followers/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids)
- [GET api/followers/list](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list)
- [GET api/friends/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids)
- [GET api/friends/list](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-list)
- Additional parameters:
- `since_id`: You can use the `next_cursor` value to load the next page.
- `max_id`: You can use the inverse of the `previous_cursor` value to load the previous page.
- Unsupported parameter:
- `skip_status`: No status is returned even if it isn't set to true.
- Caveats:
- `cursor` trumps `since_id` trumps `max_id` if any combination is provided.
- `user_id` must be the ID of a contact associated with a local user account.
- `screen_name` must be associated with a local user account.
- `screen_name` trumps `user_id` if both are provided (undocumented Twitter behavior).
- Will succeed but return an empty array for users hiding their contact lists.
- [POST api/friendships/destroy](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-destroy)
## Non-implemented endpoints
- [GET oauth/authenticate](https://developer.twitter.com/en/docs/basics/authentication/api-reference/authenticate)
- [GET oauth/authorize](https://developer.twitter.com/en/docs/basics/authentication/api-reference/authorize)
- [POST oauth/invalidate_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_access_token)
- [POST oauth2/invalidate_token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_bearer_token)
- [POST oauth2/token](https://developer.twitter.com/en/docs/basics/authentication/api-reference/token)
- [GET lists/members](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members)
- [GET lists/members/show](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members-show)
- [GET lists/memberships](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-memberships)
- [GET lists/show](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-show)
- [GET lists/subscribers](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers)
- [GET lists/subscribers/show](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers-show)
- [POST lists/members/create](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create)
- [POST lists/members/create_all](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create_all)
- [POST lists/members/destroy](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy)
- [POST lists/members/destroy_all](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy_all)
- [POST lists/subscribers/create](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-create)
- [POST lists/subscribers/destroy](https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-destroy)
- [GET friendships/lookup](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-lookup)
- [GET friendships/no_retweets/ids](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-no_retweets-ids)
- [GET friendships/outgoing](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-outgoing)
- [GET friendships/show](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-show)
- [GET users/suggestions (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions)
- [GET users/suggestions/:slug (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug)
- [GET users/suggestions/:slug/members (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug-members)
- [POST friendships/create](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-create)
- [POST friendships/update](https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-update)
- [GET account/settings](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-settings)
- [GET saved_searches/show/:id](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-saved_searches-show-id)
- [GET users/profile_banner](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-users-profile_banner)
- [POST account/remove_profile_banner](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-remove_profile_banner)
- [POST account/settings](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-settings)
- [POST account/update_profile_background_image (deprecated)](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_background_image)
- [POST account/update_profile_banner](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_banner)
- [POST saved_searches/create](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-saved_searches-create)
- [POST saved_searches/destroy/:id](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-saved_searches-destroy-id)
- [GET blocks/ids](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-ids)
- [GET mutes/users/ids](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-ids)
- [GET mutes/users/list](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-list)
- [POST blocks/create](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-create)
- [POST blocks/destroy](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-destroy)
- [POST mutes/users/create](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-create)
- [POST mutes/users/destroy](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-destroy)
- [POST users/report_spam](https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-users-report_spam)
- [GET collections/entries](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/get-collections-entries)
- [GET collections/list](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/get-collections-list)
- [GET collections/show](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/get-collections-show)
- [POST collections/create](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-create)
- [POST collections/destroy](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-destroy)
- [POST collections/entries/add](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-add)
- [POST collections/entries/curate](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-curate)
- [POST collections/entries/move](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-move)
- [POST collections/entries/remove](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-entries-remove)
- [POST collections/update](https://developer.twitter.com/en/docs/tweets/curate-a-collection/api-reference/post-collections-update)
- [POST statuses/filter](https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter)
- [GET statuses/mentions_timeline](https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-mentions_timeline)
- [GET favorites/list](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-favorites-list)
- [GET statuses/lookup](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-lookup)
- [GET statuses/oembed](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-oembed)
- [GET statuses/retweeters/ids](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweeters-ids)
- [GET statuses/retweets/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweets-id)
- [GET statuses/retweets_of_me](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweets_of_me)
- [POST statuses/unretweet/:id](https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-unretweet-id)
- [GET statuses/sample](https://developer.twitter.com/en/docs/tweets/sample-realtime/api-reference/get-statuses-sample)
- [GET compliance/firehose](https://developer.twitter.com/en/docs/tweets/compliance/api-reference/compliance-firehose)
- [DELETE custom_profiles/destroy.json](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/delete-profile)
- [GET custom_profiles/:id](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/get-profile)
- [GET custom_profiles/list](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/get-profile-list)
- [POST custom_profiles/new.json](https://developer.twitter.com/en/docs/direct-messages/custom-profiles/api-reference/new-profile)
- [DELETE direct_messages/events/destroy](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message-event)
- [GET direct_messages/events/list](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/list-events)
- [GET direct_messages/events/show](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-event)
- [POST direct_messages/events/new (message_create)](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/new-event)
- [POST direct_messages/indicate_typing](https://developer.twitter.com/en/docs/direct-messages/typing-indicator-and-read-receipts/api-reference/new-typing-indicator)
- [POST direct_messages/mark_read](https://developer.twitter.com/en/docs/direct-messages/typing-indicator-and-read-receipts/api-reference/new-read-receipt)
- [DELETE direct_messages/welcome_messages/destroy](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/delete-welcome-message)
- [DELETE direct_messages/welcome_messages/rules/destroy](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/delete-welcome-message-rule)
- [PUT direct_messages/welcome_messages/update](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/update-welcome-message)
- [GET direct_messages/welcome_messages/list](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/list-welcome-messages)
- [GET direct_messages/welcome_messages/rules/list](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/list-welcome-message-rules)
- [GET direct_messages/welcome_messages/rules/show](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/get-welcome-message-rule)
- [GET direct_messages/welcome_messages/show](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/get-welcome-message)
- [POST direct_messages/welcome_messages/new](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/new-welcome-message)
- [POST direct_messages/welcome_messages/rules/new](https://developer.twitter.com/en/docs/direct-messages/welcome-messages/api-reference/new-welcome-message-rule)
- [GET media/upload (STATUS)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/get-media-upload-status)
- [POST media/subtitles/create](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-subtitles-create)
- [POST media/subtitles/delete](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-subtitles-delete)
- [POST media/upload (APPEND)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-append)
- [POST media/upload (FINALIZE)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-finalize)
- [POST media/upload (INIT)](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-init)
- [GET trends/available](https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available)
- [GET trends/closest](https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-closest)
- [GET trends/place](https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place)
- [GET geo/id/:place_id](https://developer.twitter.com/en/docs/geo/place-information/api-reference/get-geo-id-place_id)
- [GET geo/reverse_geocode](https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-reverse_geocode)
- [GET geo/search](https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-search)

View File

@ -0,0 +1,90 @@
Accesskeys reference
=======================
* [Home](help)
Access keys are keyboard shortcuts that allow you to easily navigate the user interface.
Access keys are currently not available with the Frio theme.
The specific key combinations depend on how your browser's the modifier key setting.
For an overview of modifier keys in different browsers, have a lookat [Wikipedia](https://en.wikipedia.org/wiki/Access_key) article.
For example, for moving to profile page in Firefox, press these three keys simultaneously.
[Shift] [Alt] [p]
General
-------
* p - Profile
* n - Network
* c - Community
* s - Search
* a - Admin
* f - Notifications
* u - User menu
../community
--------
* l - Local community
* g - Global community
../profile
--------
* m - Status Messages and Posts
* r - Profile Details
* h - Photo Albums
* v - Videos
* e - Events and Calendar
* t - Personal Notes
* k - View Contacts
../contacts (contact list)
---------
* g - Suggestions
* l - Show all Contacts
* o - Only show unblocked contacts
* b - Only show blocked contacts
* i - Only show ignored contacts
* y - Only show archived contacts
* h - Only show hidden contacts
* e - Edit contact groups
../contacts (single contact view)
-------------------------------
* m - Status messages
* o - Profile
* t - Contacts
* d - Common friends
* r - Advanced
../message
--------
* m - New message
../network
--------
* e - Sort by Comment Date
* t - Sort by Post Date
* r - Conversation (Posts that mention or involve you)
* w - New posts
* b - Bookmarks
* m - Favourite Posts
../notifications
--------------
* y - System
* w - Network
* r - Personal
* h - Home
* i - Introductions
../settings
---------
* o - Account
* p - Profiles
* t - Additional features
* w - Social Networks
* l - Addons
* d - Delegations
* b - Connected apps
* e - Export personal data
* r - Remove account

View File

@ -0,0 +1,109 @@
Account Basics
==============
* [Home](help)
Registration
---
Not all Friendica sites allow open registration.
If registration is allowed, you will see a "Register" link immediately below the login prompt on the site's home page.
Following this link will take you to the site registration page.
The strength of our network is that lots of different sites are all completely compatible with each other.
If the site you're visting doesn't allow registration, or you think you might prefer another one, there is a [list of public servers here](https://dir.friendica.social/servers) and hopefully you will find one that meets your needs.
If you'd like to have your own server, you can do that too.
Visit [the Friendica website](http://friendi.ca/) to download the code with setup instructions.
It's a very simple installation process that anybody experienced in hosting websites, or with basic Linux experience can handle easily.
### OpenID
The first field on the Registration page is for an OpenID address.
If you do not have an OpenID address or do not wish to use OpenID, leave this field blank.
If you have an OpenID account elsewhere and wish to use it, enter the address into this field and click 'Register'.
Friendica will attempt to extract as much information as possible from your OpenID provider and return to this page with those items already filled in.
### Your Full Name
Please provide your full name **as you would like it to be displayed on this system**.
Most people use their real name for this, but you're under no obligation to do so yourself.
### Email Address
Please provide a valid email address.
Your email address is **never** published.
We need this to send you account information and your login details.
You may also occasionally receive notifications of incoming messages or items requiring your attention, but you have the possibility to completely disable these from your Settings page once you have logged in.
This doesn't have to be your primary email address, but it does need to be a real email address.
You can't get your initial password, or reset a lost password later without it.
This is the only bit of personal information that has to be accurate.
### Nickname
A nickname is used to generate web addresses for many of your personal pages, and is also treated like an email address when establishing communications with others.
Due to the way that the nickname is used, it has some limitations.
It must contain only US-ASCII text characters and numbers, and must also start with a text character.
It also must be unique on this system.
This is used in many places to identify your account, and once set it cannot be changed.
### Directory Publishing
The registration form also allows you to choose whether or not to list your account in the online directory of your node.
This is like a "phone book" and you may choose to be unlisted.
We recommend that you select 'Yes' so that other people (friends, family, etc.) will be able to find you.
If you choose 'No', you will essentially be invisible and have few opportunities for interaction.
Whichever you choose, this can be changed any time from your Settings page after you login.
### Register
Once you have provided the necessary details, click the 'Register' button.
An email will be sent to you providing your account login details.
Please check your email (including spam folders) for your registration details and initial password.
Login Page
---
On the 'Login' page, please enter your login information that was provided during registration.
You may use either your nickname or email address as a Login Name.
If you use your account to manage other accounts and these all have the same email address, please enter the nickname for the account you wish to manage.
If your account has been OpenID enabled, you may use your OpenID address as a login name and leave the password blank.
You will be redirected to your OpenID provider to complete your authorisation.
Otherwise, enter your password.
This will have been initially provided in your registration email message.
Your password is case-sensitive, so please check your 'Caps Lock' key if you are having difficulty logging in.
Changing Your Password
---
After your first login, please visit the 'Settings' page from the top menu bar and change your password to something that you will remember.
Getting Started
---
A link with ['Tips for New Members'](newmember) will show up on your network and home pages for two weeks providing key information for getting started.
Retrieving Personal Data
---
You can export a copy of your personal data in JSON format from the "Export personal data" link at the top of your settings page.
You need this file to relocate your Friendica account to another node.
This might be necessary, e.g. if your node suffers a severe hardware problem and is not recoverable.
See Also
---
* [Profiles](help/Profiles)
* [Global Directory](help/Making-Friends#The+Directories)
* [Groups and Privacy](help/Groups-and-Privacy)
* [Move Account](help/Move-Account)
* [Remove Account](help/Remove-Account)

View File

@ -0,0 +1,299 @@
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 function get(string $reference);
public function put(string $data, string $reference = '');
public function delete(string $reference);
public function getOptions();
public function saveOptions(array $data);
public function __toString();
public static function getName();
}
```
- `get(string $reference)` returns data pointed by `$reference`
- `put(string $data, string $reference)` saves data in `$data` to position `$reference`, or a new position if `$reference` is empty.
- `delete(string $reference)` delete data pointed by `$reference`
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(array $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'
'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
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.
`DI::facStorage()->register(string $class)` is used to register the backend class.
When the plugin is uninstalled, registered backends must be unregistered using
`DI::facStorage()->unregister(string $class)`.
You have to register a new hook in your addon, listening on `storage_instance(App $a, array $data)`.
In case `$data['name']` is your storage class name, you have to instance a new instance of your `Friendica\Model\Storage\IStorage` class.
Set the instance of your class as `$data['storage']` to pass it back to the backend.
This is necessary because it isn't always clear, if you need further construction arguments.
## Adding tests
**Currently testing is limited to core Friendica only, this shows theoretically how tests should work in the future**
Each new Storage class should be added to the test-environment at [Storage Tests](https://github.com/friendica/friendica/tree/develop/tests/src/Model/Storage/).
Add a new test class which's naming convention is `StorageClassTest`, which extend the `StorageTest` in the same directory.
Override the two necessary instances:
```php
use Friendica\Model\Storage\IStorage;
abstract class StorageTest
{
// returns an instance of your newly created storage class
abstract protected function getInstance();
// Assertion for the option array you return for your new StorageClass
abstract protected function assertOption(IStorage $storage);
}
```
## 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\IConfig;
use Friendica\Core\L10n;
class SampleStorageBackend implements IStorage
{
const NAME = 'Sample Storage';
/** @var IConfig */
private $config;
/** @var L10n */
private $l10n;
/**
* SampleStorageBackend constructor.
* @param IConfig $config The configuration of Friendica
*
* You can add here every dynamic class as dependency you like and add them to a private field
* Friendica automatically creates these classes and passes them as argument to the constructor
*/
public function __construct(IConfig $config, L10n $l10n)
{
$this->config = $config;
$this->l10n = $l10n;
}
public function get(string $reference)
{
// we return always the same image data. Which file we load is defined by
// a config key
$filename = $this->config->get('storage', 'samplestorage', 'sample.jpg');
return file_get_contents($filename);
}
public function put(string $data, string $reference = '')
{
if ($reference === '') {
$reference = 'sample';
}
// we don't save $data !
return $reference;
}
public function delete(string $reference)
{
// we pretend to delete the data
return true;
}
public function getOptions()
{
$filename = $this->config->get('storage', 'samplestorage', 'sample.jpg');
return [
'filename' => [
'input', // will use a simple text input
$this->l10n->t('The file to return'), // the label
$filename, // the current value
$this->l10n->t('Enter the path to a file'), // the help text
// no extra data for 'input' type..
],
];
}
public function saveOptions(array $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'];
}
$this->config->set('storage', 'samplestorage', $newfilename);
// no errors, return empty array
return [];
}
public function __toString()
{
return self::NAME;
}
public static function getName()
{
return self::NAME;
}
}
```
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\Addon\samplestorage\SampleStorageBackend;
use Friendica\DI;
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
DI::storageManager()->register(SampleStorageBackend::class);
}
function samplestorage_unistall()
{
// when the plugin is uninstalled, we unregister the backend.
DI::storageManager()->unregister(SampleStorageBackend::class);
}
function samplestorage_storage_instance(\Friendica\App $a, array $data)
{
if ($data['name'] === SampleStorageBackend::getName()) {
// instance a new sample storage instance and pass it back to the core for usage
$data['storage'] = new SampleStorageBackend(DI::config(), DI::l10n(), DI::cache());
}
}
```
**Theoretically - until tests for Addons are enabled too - create a test class with the name `addon/tests/SampleStorageTest.php`:
```php
use Friendica\Model\Storage\IStorage;
use Friendica\Test\src\Model\Storage\StorageTest;
class SampleStorageTest extends StorageTest
{
// returns an instance of your newly created storage class
protected function getInstance()
{
// create a new SampleStorageBackend instance with all it's dependencies
// Have a look at DatabaseStorageTest or FilesystemStorageTest for further insights
return new SampleStorageBackend();
}
// Assertion for the option array you return for your new StorageClass
protected function assertOption(IStorage $storage)
{
$this->assertEquals([
'filename' => [
'input',
'The file to return',
'sample.jpg',
'Enter the path to a file'
],
], $storage->getOptions());
}
}
```

View File

@ -0,0 +1,803 @@
Friendica Addon development
==============
* [Home](help)
Please see the sample addon 'randplace' for a working example of using some of these features.
Addons work by intercepting event hooks - which must be registered.
Modules work by intercepting specific page requests (by URL path).
## 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".
## PHP addon hooks
Register your addon hooks during installation.
\Friendica\Core\Hook::register($hookname, $file, $function);
`$hookname` is a string and corresponds to a known Friendica PHP hook.
`$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.
### Arguments
Your hook callback functions will be called with at least one and possibly two arguments
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
$a is the Friendica `App` class.
It contains a wealth of information about the current state of Friendica:
* which module has been called,
* configuration information,
* the page contents at the point the hook was invoked,
* profile and user information, etc.
It is recommeded you call this `$a` to match its usage elsewhere.
#### $b
$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:
```php
function <addon>_install()
{
\Friendica\Core\Hook::register('head', __FILE__, '<addon>_head');
...
}
function <addon>_head(App $a)
{
\Friendica\DI::page()->registerStylesheet(__DIR__ . '/relative/path/to/addon/stylesheet.css');
}
```
`__DIR__` is the folder path of your addon.
## JavaScript
### Global scripts
If your addon requires adding a script on all pages of Friendica, add the following hook:
```php
function <addon>_install()
{
\Friendica\Core\Hook::register('footer', __FILE__, '<addon>_footer');
...
}
function <addon>_footer(App $a)
{
\Friendica\DI::page()->registerFooterScript(__DIR__ . '/relative/path/to/addon/script.js');
}
```
`__DIR__` is the folder path of your addon.
### JavaScript hooks
The main Friendica script provides hooks via events dispatched on the `document` property.
In your Javascript file included as described above, add your event listener like this:
```js
document.addEventListener(name, callback);
```
- *name* is the name of the hook and corresponds to a known Friendica JavaScript hook.
- *callback* is a JavaScript anonymous function to execute.
More info about Javascript event listeners: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
#### Current JavaScript hooks
##### postprocess_liveupdate
Called at the end of the live update process (XmlHttpRequest) and on a post preview.
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 declare an empty function `<addon>_module()`.
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 `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
$a->argc = 3
$a->argv = array(0 => 'addon', 1 => 'arg1', 2 => 'arg2');
```
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
If your addon needs some template, you can use the Friendica template system.
Friendica uses [smarty3](http://www.smarty.net/) as a template engine.
Put your tpl files in the *templates/* subfolder of your addon.
In your code, like in the function addon_name_content(), load the template file and execute it passing needed values:
```php
use Friendica\Core\Renderer;
# load template file. first argument is the template name,
# second is the addon path relative to friendica top folder
$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 = Renderer::replaceMacros($tpl, array(
'title' => 'My beautiful addon',
));
```
See also the wiki page [Quick Template Guide](https://github.com/friendica/friendica/wiki/Quick-Template-Guide).
## Current PHP hooks
### authenticate
Called when a user attempts to login.
`$b` is an array containing:
- **username**: the supplied username
- **password**: the supplied password
- **authenticated**: set this to non-zero to authenticate the user.
- **user_record**: successful authentication must also return a valid user record from the database
### logged_in
Called after a user has successfully logged in.
`$b` contains the `$a->user` array.
### display_item
Called when formatting a post for display.
$b is an array:
- **item**: The item (array) details pulled from the database
- **output**: the (string) HTML representation of this item prior to adding it to the page
### post_local
Called when a status post or comment is entered on the local system.
`$b` is the item array of the information to be stored in the database.
Please note: body contents are bbcode - not HTML.
### post_local_end
Called when a local status post or comment has been stored on the local system.
`$b` is the item array of the information which has just been stored in the database.
Please note: body contents are bbcode - not HTML
### post_remote
Called when receiving a post from another source. This may also be used to post local activity or system generated messages.
`$b` is the item array of information to be stored in the database and the item body is bbcode.
### settings_form
Called when generating the HTML for the user Settings page.
`$b` is the HTML string of the settings page before the final `</form>` tag.
### settings_post
Called when the Settings pages are submitted.
`$b` is the $_POST array.
### addon_settings
Called when generating the HTML for the addon settings page.
`$b` is the (string) HTML of the addon settings page before the final `</form>` tag.
### addon_settings_post
Called when the Addon Settings pages are submitted.
`$b` is the $_POST array.
### profile_post
Called when posting a profile page.
`$b` is the $_POST array.
### profile_edit
Called prior to output of profile edit page.
`$b` is an array containing:
- **profile**: profile (array) record from the database
- **entry**: the (string) HTML of the generated entry
### profile_advanced
Called when the HTML is generated for the Advanced profile, corresponding to the Profile tab within a person's profile page.
`$b` is the HTML string representation of the generated profile.
The profile array details are in `$a->profile`.
### directory_item
Called from the Directory page when formatting an item for display.
`$b` is an array:
- **contact**: contact record array for the person from the database
- **entry**: the HTML string of the generated entry
### profile_sidebar_enter
Called prior to generating the sidebar "short" profile for a page.
`$b` is the person's profile array
### profile_sidebar
Called when generating the sidebar "short" profile for a page.
`$b` is an array:
- **profile**: profile record array for the person from the database
- **entry**: the HTML string of the generated entry
### contact_block_end
Called when formatting the block of contacts/friends on a profile sidebar has completed.
`$b` is an array:
- **contacts**: array of contacts
- **output**: the generated HTML string of the contact block
### bbcode
Called after conversion of bbcode to HTML.
`$b` is an HTML string converted text.
### html2bbcode
Called after tag conversion of HTML to bbcode (e.g. remote message posting)
`$b` is a string converted text
### head
Called when building the `<head>` sections.
Stylesheets should be registered using this hook.
`$b` is an HTML string of the `<head>` tag.
### page_header
Called after building the page navigation section.
`$b` is a string HTML of nav region.
### personal_xrd
Called prior to output of personal XRD file.
`$b` is an array:
- **user**: the user record array for the person
- **xml**: the complete XML string to be output
### home_content
Called prior to output home page content, shown to unlogged users.
`$b` is the HTML sring of section region.
### contact_edit
Called when editing contact details on an individual from the Contacts page.
$b is an array:
- **contact**: contact record (array) of target contact
- **output**: the (string) generated HTML of the contact edit page
### contact_edit_post
Called when posting the contact edit page.
`$b` is the `$_POST` array
### init_1
Called just after DB has been opened and before session start.
No hook data.
### page_end
Called after HTML content functions have completed.
`$b` is (string) HTML of content div.
### footer
Called after HTML content functions have completed.
Deferred Javascript files should be registered using this hook.
`$b` is (string) HTML of footer div/element.
### avatar_lookup
Called when looking up the avatar. `$b` is an array:
- **size**: the size of the avatar that will be looked up
- **email**: email to look up the avatar for
- **url**: the (string) generated URL of the avatar
### emailer_send_prepare
Called from `Emailer::send()` before building the mime message.
`$b` is an array of params to `Emailer::send()`.
- **fromName**: name of the sender
- **fromEmail**: email fo the sender
- **replyTo**: replyTo address to direct responses
- **toEmail**: destination email address
- **messageSubject**: subject of the 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()`.
`$b` is an array of params to `mail()`.
- **to**
- **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()`.
### nav_info
Called after the navigational menu is build in `include/nav.php`.
`$b` is an array containing `$nav` from `include/nav.php`.
### template_vars
Called before vars are passed to the template engine to render the page.
The registered function can add,change or remove variables passed to template.
`$b` is an array with:
- **template**: filename of template
- **vars**: array of vars passed to the template
### acl_lookup_end
Called after the other queries have passed.
The registered function can add, change or remove the `acl_lookup()` variables.
- **results**: array of the acl_lookup() vars
### prepare_body_init
Called at the start of prepare_body
Hook data:
- **item** (input/output): item array
### prepare_body_content_filter
Called before the HTML conversion in prepare_body. If the item matches a content filter rule set by an addon, it should
just add the reason to the filter_reasons element of the hook data.
Hook data:
- **item**: item array (input)
- **filter_reasons** (input/output): reasons array
### prepare_body
Called after the HTML conversion in `prepare_body()`.
Hook data:
- **item** (input): item array
- **html** (input/output): converted item body
- **is_preview** (input): post preview flag
- **filter_reasons** (input): reasons array
### prepare_body_final
Called at the end of `prepare_body()`.
Hook data:
- **item**: item array (input)
- **html**: converted item body (input/output)
### put_item_in_cache
Called after `prepare_text()` in `put_item_in_cache()`.
Hook data:
- **item** (input): item array
- **rendered-html** (input/output): final item body HTML
- **rendered-hash** (input/output): original item body hash
### magic_auth_success
Called when a magic-auth was successful.
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.
### probe_detect
Called before trying to detect the target network of a URL.
If any registered hook function sets the `result` key of the hook data array, it will be returned immediately.
Hook functions should also return immediately if the hook data contains an existing result.
Hook data:
- **uri** (input): the profile URI.
- **network** (input): the target network (can be empty for auto-detection).
- **uid** (input): the user to return the contact data for (can be empty for public contacts).
- **result** (output): Set by the hook function to indicate a successful detection.
## 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
Hook::callAll('init_1');
Hook::callAll('app_menu', $arr);
Hook::callAll('page_content_top', DI::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', DI::page()['content']);
### include/api.php
Hook::callAll('logged_in', $a->user);
Hook::callAll('authenticate', $addon_auth);
Hook::callAll('logged_in', $a->user);
### include/enotify.php
Hook::callAll('enotify', $h);
Hook::callAll('enotify_store', $datarray);
Hook::callAll('enotify_mail', $datarray);
Hook::callAll('check_item_notification', $notification_data);
### include/conversation.php
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);
### mod/directory.php
Hook::callAll('directory_item', $arr);
### mod/xrd.php
Hook::callAll('personal_xrd', $arr);
### mod/ping.php
Hook::callAll('network_ping', $arr);
### mod/parse_url.php
Hook::callAll("parse_link", $arr);
### src/Module/Delegation.php
Hook::callAll('home_init', $ret);
### mod/acl.php
Hook::callAll('acl_lookup_end', $results);
### mod/network.php
Hook::callAll('network_content_init', $arr);
Hook::callAll('network_tabs', $arr);
### mod/friendica.php
Hook::callAll('about_hook', $o);
### mod/subthread.php
Hook::callAll('post_local_end', $arr);
### mod/profiles.php
Hook::callAll('profile_post', $_POST);
Hook::callAll('profile_edit', $arr);
### mod/settings.php
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
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
Hook::callAll('profile_advanced', $o);
### mod/home.php
Hook::callAll('home_init', $ret);
Hook::callAll("home_content", $content);
### mod/poke.php
Hook::callAll('post_local_end', $arr);
### mod/contacts.php
Hook::callAll('contact_edit_post', $_POST);
Hook::callAll('contact_edit', $arr);
### mod/tagger.php
Hook::callAll('post_local_end', $arr);
### mod/uexport.php
Hook::callAll('uexport_options', $options);
### mod/register.php
Hook::callAll('register_post', $arr);
Hook::callAll('register_form', $arr);
### mod/item.php
Hook::callAll('post_local_start', $_REQUEST);
Hook::callAll('post_local', $datarray);
Hook::callAll('post_local_end', $datarray);
### mod/editpost.php
Hook::callAll('jot_tool', $jotplugins);
### src/Network/FKOAuth1.php
Hook::callAll('logged_in', $a->user);
### src/Render/FriendicaSmartyEngine.php
Hook::callAll("template_vars", $arr);
### src/App.php
Hook::callAll('load_config');
Hook::callAll('head');
Hook::callAll('footer');
Hook::callAll('route_collection');
### src/Model/Item.php
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);
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);
### src/Model/Contact.php
Hook::callAll('contact_photo_menu', $args);
Hook::callAll('follow', $arr);
### src/Model/Profile.php
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
Hook::callAll('event_updated', $event['id']);
Hook::callAll("event_created", $event['id']);
### src/Model/User.php
Hook::callAll('register_account', $uid);
Hook::callAll('remove_user', $user);
### src/Module/PermissionTooltip.php
Hook::callAll('lockview_content', $item);
### src/Content/ContactBlock.php
Hook::callAll('contact_block_end', $arr);
### src/Content/Text/BBCode.php
Hook::callAll('bbcode', $text);
Hook::callAll('bb2diaspora', $text);
### src/Content/Text/HTML.php
Hook::callAll('html2bbcode', $message);
### src/Content/Smilies.php
Hook::callAll('smilie', $params);
### src/Content/Feature.php
Hook::callAll('isEnabled', $arr);
Hook::callAll('get', $arr);
### src/Content/ContactSelector.php
Hook::callAll('network_to_name', $nets);
### src/Content/OEmbed.php
Hook::callAll('oembed_fetch_url', $embedurl, $j);
### src/Content/Nav.php
Hook::callAll('page_header', DI::page()['nav']);
Hook::callAll('nav_info', $nav);
### src/Core/Authentication.php
Hook::callAll('logged_in', $a->user);
### src/Core/StorageManager
Hook::callAll('storage_instance', $data);
### src/Worker/Directory.php
Hook::callAll('globaldir_update', $arr);
### src/Worker/Notifier.php
Hook::callAll('notifier_end', $target_item);
### src/Module/Login.php
Hook::callAll('login_hook', $o);
### src/Module/Logout.php
Hook::callAll("logging_out");
### src/Object/Post.php
Hook::callAll('render_location', $locate);
Hook::callAll('display_item', $arr);
### src/Core/ACL.php
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
Hook::callAll('logged_in', $a->user);
Hook::callAll('authenticate', $addon_auth);
### src/Core/Hook.php
self::callSingle(self::getApp(), 'hook_fork', $fork_hook, $hookdata);
### src/Core/L10n/L10n.php
Hook::callAll('poke_verbs', $arr);
### src/Core/Worker.php
Hook::callAll("proc_run", $arr);
### src/Util/Emailer.php
Hook::callAll('emailer_send_prepare', $params);
Hook::callAll("emailer_send", $hookdata);
### src/Util/Map.php
Hook::callAll('generate_map', $arr);
Hook::callAll('generate_named_map', $arr);
Hook::callAll('Map::getCoordinates', $arr);
### src/Util/Network.php
Hook::callAll('avatar_lookup', $avatar);
### src/Util/ParseUrl.php
Hook::callAll("getsiteinfo", $siteinfo);
### src/Protocol/DFRN.php
Hook::callAll('atom_feed_end', $atom);
Hook::callAll('atom_feed_end', $atom);
### src/Protocol/Email.php
Hook::callAll('email_getmessage', $message);
Hook::callAll('email_getmessage_end', $ret);
### view/js/main.js
document.dispatchEvent(new Event('postprocess_liveupdate'));

View File

@ -0,0 +1,659 @@
Friendica BBCode tags reference
========================
* [Creating posts](help/Text_editor)
## Inline
<style>
table.bbcodes {
margin: 1em 0;
background-color: #f9f9f9;
border: 1px solid #aaa;
border-collapse: collapse;
color: #000;
width: 100%;
}
table.bbcodes > tr > th,
table.bbcodes > tr > td,
table.bbcodes > * > tr > th,
table.bbcodes > * > tr > td {
border: 1px solid #aaa;
padding: 0.2em 0.4em
}
table.bbcodes > tr > th,
table.bbcodes > * > tr > th {
background-color: #f2f2f2;
text-align: center;
width: 50%
}
</style>
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[b]bold[/b]</td>
<td><strong>bold</strong></td>
</tr>
<tr>
<td>[i]italic[/i]</td>
<td><em>italic</em></td>
</tr>
<tr>
<td>[u]underlined[/u]</td>
<td><u>underlined</u></td>
</tr>
<tr>
<td>[s]strike[/s]</td>
<td><strike>strike</strike></td>
</tr>
<tr>
<td>[o]overline[/o]</td>
<td><span class="overline">overline</span></td>
</tr>
<tr>
<td>[color=red]red[/color]</td>
<td><span style="color: red;">red</span></td>
</tr>
<tr>
<td>[url=http://friendi.ca]Friendica[/url]</td>
<td><a href="http://friendi.ca" target="external-link">Friendica</a></td>
</tr>
<tr>
<td>[img]https://raw.githubusercontent.com/friendica/friendica/stable/images/friendica-32.jpg[/img]</td>
<td><img src="https://raw.githubusercontent.com/friendica/friendica/stable/images/friendica-32.jpg" alt="Immagine/foto"></td>
</tr>
<tr>
<td>[img=https://raw.githubusercontent.com/friendica/friendica/stable/images/friendica-32.jpg]The Friendica Logo[/img]</td>
<td><img src="https://raw.githubusercontent.com/friendica/friendica/stable/images/friendica-32.jpg" alt="The Friendica Logo"></td>
</tr>
<tr>
<td>[img=64x32]https://raw.githubusercontent.com/friendica/friendica/stable/images/friendica-32.jpg[/img]<br>
<br>Note: provided height is simply discarded.</td>
<td><img src="https://raw.githubusercontent.com/friendica/friendica/stable/images/friendica-32.jpg" style="width: 64px;"></td>
</tr>
<tr>
<td>[size=xx-small]small text[/size]</td>
<td><span style="font-size: xx-small;">small text</span></td>
</tr>
<tr>
<td>[size=xx-large]big text[/size]</td>
<td><span style="font-size: xx-large;">big text</span></td>
</tr>
<tr>
<td>[size=20]exact size[/size] (size can be any number, in pixels)</td>
<td><span style="font-size: 20px;">exact size</span></td>
</tr>
<tr>
<td>[font=serif]Serif font[/font]</td>
<td><span style="font-family: serif;">Serif font</span></td>
</tr>
</table>
### Links
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[url]http://friendi.ca[/url]</td>
<td><a href="http://friendi.ca">http://friendi.ca</a></td>
</tr>
<tr>
<td>[url=http://friendi.ca]Friendica[/url]</td>
<td><a href="http://friendi.ca">Friendica</a></td>
</tr>
<tr>
<td>[bookmark]http://friendi.ca[/bookmark]<br><br>
#^[url]http://friendi.ca[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendi.ca" rel="oembed"></a><a href="http://friendi.ca" target="_blank" rel="noopener noreferrer">http://friendi.ca</a></h4></span></td>
</tr>
<tr>
<td>[bookmark=http://friendi.ca]Bookmark[/bookmark]<br><br>
#^[url=http://friendi.ca]Bookmark[/url]<br><br>
#[url=http://friendi.ca]^[/url][url=http://friendi.ca]Bookmark[/url]</td>
<td><span class="oembed link"><h4>Friendica: <a href="http://friendi.ca" rel="oembed"></a><a href="http://friendi.ca" target="_blank" rel="noopener noreferrer">Bookmark</a></h4></span></td>
</tr>
<tr>
<td>[url=/posts/f16d77b0630f0134740c0cc47a0ea02a]Diaspora post with GUID[/url]</td>
<td><a href="/display/f16d77b0630f0134740c0cc47a0ea02a" target="_blank" rel="noopener noreferrer">Diaspora post with GUID</a></td>
</tr>
<tr>
<td>#Friendica</td>
<td>#<a href="/search?tag=Friendica">Friendica</a></td>
</tr>
<tr>
<td>@Mention</td>
<td>@<a href="javascript:void(0)">Mention</a></td>
</tr>
<tr>
<td>acct:account@friendica.host.com (WebFinger)</td>
<td><a href="/acctlink?addr=account@friendica.host.com" target="extlink">acct:account@friendica.host.com</a></td>
</tr>
<tr>
<td>[mail]user@mail.example.com[/mail]</td>
<td><a href="mailto:user@mail.example.com">user@mail.example.com</a></td>
</tr>
<tr>
<td>[mail=user@mail.example.com]Send an email to User[/mail]</td>
<td><a href="mailto:user@mail.example.com">Send an email to User</a></td>
</tr>
</table>
## Blocks
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[p]A paragraph of text[/p]</td>
<td><p>A paragraph of text</p></td>
</tr>
<tr>
<td>Inline [code]code[/code] in a paragraph</td>
<td>Inline <key>code</key> in a paragraph</td>
</tr>
<tr>
<td>[code]Multi<br>line<br>code[/code]</td>
<td><code>Multi
line
code</code></td>
</tr>
<tr>
<td>[code=php]function text_highlight($s,$lang)[/code]<sup><a href="#supported-code">1</a></sup></td>
<td><code><div class="hl-main"><ol class="hl-main"><li><span class="hl-code">&nbsp;</span><span class="hl-reserved">function</span><span class="hl-code"> </span><span class="hl-identifier">text_highlight</span><span class="hl-brackets">(</span><span class="hl-var">$s</span><span class="hl-code">,</span><span class="hl-var">$lang</span><span class="hl-brackets">)</span></li></ol></div></code></td>
</tr>
<tr>
<td>[quote]quote[/quote]</td>
<td><blockquote>quote</blockquote></td>
</tr>
<tr>
<td>[quote=Author]Author? Me? No, no, no...[/quote]</td>
<td><strong class="author">Author wrote:</strong><blockquote>Author? Me? No, no, no...</blockquote></td>
</tr>
<tr>
<td>[center]Centered text[/center]</td>
<td><div style="text-align:center;">Centered text</div></td>
</tr>
<tr>
<td>You should not read any further if you want to be surprised.[spoiler]There is a happy end.[/spoiler]</td>
<td>
<div class="wall-item-container">
You should not read any further if you want to be surprised.<br>
<span id="spoiler-wrap-0716e642" class="spoiler-wrap fakelink" onclick="openClose('spoiler-0716e642');">Click to open/close</span>
<blockquote class="spoiler" id="spoiler-0716e642" style="display: none;">There is a happy end.</blockquote>
<div class="body-attach"><div class="clear"></div></div>
</div>
</td>
</tr>
<tr>
<td>[spoiler=Author]Spoiler quote[/spoiler]</td>
<td>
<div class="wall-item-container">
<strong class="spoiler">Author wrote:</strong><br>
<span id="spoiler-wrap-a893765a" class="spoiler-wrap fakelink" onclick="openClose('spoiler-a893765a');">Click to open/close</span>
<blockquote class="spoiler" id="spoiler-a893765a" style="display: none;">Spoiler quote</blockquote>
<div class="body-attach"><div class="clear"></div></div>
</div>
</td>
</tr>
<tr>
<td>[hr] (horizontal line)</td>
<td><hr></td>
</tr>
</table>
<a name="supported-code">1</a>: Supported language parameter values for code highlighting:
- abap
- avrc
- cpp
- css
- diff
- dtd
- html
- java
- javascript
- js
- mysql
- perl
- php
- python
- ruby
- sh
- sql
- vbscript
- xml
### Titles
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[h1]Title 1[/h1]</td>
<td><h1>Title 1</h1></td>
</tr>
<tr>
<td>[h2]Title 2[/h2]</td>
<td><h2>Title 2</h2></td>
</tr>
<tr>
<td>[h3]Title 3[/h3]</td>
<td><h3>Title 3</h3></td>
</tr>
<tr>
<td>[h4]Title 4[/h4]</td>
<td><h4>Title 4</h4></td>
</tr>
<tr>
<td>[h5]Title 5[/h5]</td>
<td><h5>Title 5</h5></td>
</tr>
<tr>
<td>[h6]Title 6[/h6]</td>
<td><h6>Title 6</h6></td>
</tr>
</table>
### Tables
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[table]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Header 1[/th]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Header 2[/th]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[th]Header 2[/th]<br>
&nbsp;&nbsp;[/tr]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 1[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 2[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 3[/td]<br>
&nbsp;&nbsp;[/tr]<br>
&nbsp;&nbsp;[tr]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 4[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 5[/td]<br>
&nbsp;&nbsp;&nbsp;&nbsp;[td]Cell 6[/td]<br>
&nbsp;&nbsp;[/tr]<br>
[/table]</td>
<td>
<table>
<tbody>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>[table border=0]</td>
<td>
<table border="0">
<tbody>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>[table border=1]</td>
<td>
<table border="1">
<tbody>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
### Lists
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[ul]<br>
&nbsp;&nbsp;[li] First list element<br>
&nbsp;&nbsp;[li] Second list element<br>
[/ul]<br>
[list]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listbullet" style="list-style-type: circle;">
<li>First list element</li>
<li>Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[ol]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/ol]<br>
[list=1]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listdecimal" style="list-style-type: decimal;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listnone" style="list-style-type: none;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=i]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listlowerroman" style="list-style-type: lower-roman;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=I]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listupperroman" style="list-style-type: upper-roman;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=a]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listloweralpha" style="list-style-type: lower-alpha;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
<tr>
<td>[list=A]<br>
&nbsp;&nbsp;[*] First list element<br>
&nbsp;&nbsp;[*] Second list element<br>
[/list]</td>
<td>
<ul class="listupperalpha" style="list-style-type: upper-alpha;">
<li> First list element</li>
<li> Second list element</li>
</ul>
</td>
</tr>
</table>
## Embed
You can embed video, audio and more in a message.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[video]url[/video]</td>
<td>Where *url* can be an url to youtube, vimeo, soundcloud, or other sites wich supports oembed or opengraph specifications.</td>
</tr>
<tr>
<td>[video]Video file url[/video]
[audio]Audio file url[/audio]</td>
<td>Full URL to an ogg/ogv/oga/ogm/webm/mp4/mp3 file. An HTML5 player will be used to show it.</td>
</tr>
<tr>
<td>[youtube]Youtube URL[/youtube]</td>
<td>Youtube video OEmbed display. May not embed an actual player.</td>
</tr>
<tr>
<td>[youtube]Youtube video ID[/youtube]</td>
<td>Youtube player iframe embed.</td>
</tr>
<tr>
<td>[vimeo]Vimeo URL[/vimeo]</td>
<td>Vimeo video OEmbed display. May not embed an actual player.</td>
</tr>
<tr>
<td>[vimeo]Vimeo video ID[/vimeo]</td>
<td>Vimeo player iframe embed.</td>
</tr>
<tr>
<td>[embed]URL[/embed]</td>
<td>Embed OEmbed rich content.</td>
</tr>
<tr>
<td>[url]*url*[/url]</td>
<td>If *url* supports oembed or opengraph specifications the embedded object will be shown (eg, documents from scribd).
Page title with a link to *url* will be shown.</td>
</tr>
</table>
## Map
This requires "openstreetmap" or "Google Maps" addon version 1.3 or newer.
If the addon isn't activated, the raw coordinates are shown instead.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[map]address[/map]</td>
<td>Embeds a map centered on this address.</td>
</tr>
<tr>
<td>[map=lat,long]</td>
<td>Embeds a map centered on those coordinates.</td>
</tr>
<tr>
<td>[map]</td>
<td>Embeds a map centered on the post's location.</td>
</tr>
</table>
## Abstract for longer posts
If you want to spread your post to several third party networks you may have the problem that these networks have a length limitation like on Twitter.
Friendica uses a semi-intelligent mechanism to generate a fitting abstract.
But it can be useful to define a custom abstract that will only be displayed on the external network.
This is done with the [abstract]-element.
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>[abstract]Totally interesting! A must-see! Please click the link![/abstract]<br>
I want to tell you a really boring story that you really never wanted to hear.</td>
<td>Twitter would display the text <blockquote>Totally interesting! A must-see! Please click the link!</blockquote>
On Friendica you would only see the text after <blockquote>I want to tell you a really ...</blockquote></td>
</tr>
</table>
It is even possible to define abstracts for separate networks:
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>
[abstract]Hi friends Here are my newest pictures![/abstract]<br>
[abstract=twit]Hi my dear Twitter followers. Do you want to see my new
pictures?[/abstract]<br>
[abstract=apdn]Helly my dear followers on ADN. I made sone new pictures
that I wanted to share with you.[/abstract]<br>
Today I was in the woods and took some real cool pictures ...</td>
<td>For Twitter and App.net the system will use the defined abstracts.<br>
For other networks (e.g. when you are using the "statusnet" connector that is used to post to your GNU Social account) the general abstract element will be used.</td>
</tr>
</table>
If you use (for example) the "buffer" connector to post to Facebook or Google+ you can use this element to define an abstract for a longer blogpost that you don't want to post completely to these networks.
Networks like Facebook or Google+ aren't length limited.
For this reason the [abstract] element isn't used.
Instead you have to name the explicit network:
<table class="bbcodes">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>
[abstract]These days I had a strange encounter...[/abstract]<br>
[abstract=goog]Hello my dear Google+ followers. You have to read my newest blog post![/abstract]<br>
[abstract=face]Hello my Facebook friends. These days happened something really cool.[/abstract]<br>
While taking pictures in the woods I had a really strange encounter...</td>
<td>Google and Facebook will show the respective abstracts while the other networks will show the default one.<br>
<br>Meanwhile, Friendica won't show any of the abstracts.</td>
</tr>
</table>
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">
<tr>
<th>BBCode</th>
<th>Result</th>
</tr>
<tr>
<td>If you need to put literal BBCode in a message, [noparse], [nobb] or [pre] blocks prevent BBCode conversion:
<ul>
<li>[noparse][b]bold[/b][/noparse]</li>
<li>[nobb][b]bold[/b][/nobb]</li>
<li>[pre][b]bold[/b][/pre]</li>
</ul>
Note: [code] has priority over [noparse], [nobb] and [pre] which makes them display as BBCode tags in code blocks instead of being removed.
[code] blocks inside [noparse] will still be converted to a code block.
</td>
<td>[b]bold[/b]</td>
</tr>
<tr>
<td>Additionally, [noparse] and [pre] blocks prevent mention and hashtag conversion to links:
<ul>
<li>[noparse]@user@domain.tld #hashtag[/noparse]</li>
<li>[pre]@user@domain.tld #hashtag[/pre]</li>
</ul>
</td>
<td>@user@domain.tld #hashtag</td>
</tr>
<tr>
<td>Additionally, [pre] blocks preserve spaces:
<ul>
<li>[pre]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Spaces[/pre]</li>
</ul>
</td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Spaces</td>
</tr>
<tr>
<td>[nosmile] is used to disable smilies on a post by post basis<br>
<br>
[nosmile] ;-) :-O
</td>
<td>;-) :-O</td>
</tr>
<tr>
<td>Custom inline styles<br>
<br>
[style=text-shadow: 0 0 4px #CC0000;]You can change all the CSS properties of this block.[/style]</td>
<td><span style="text-shadow: 0 0 4px #cc0000;;">You can change all the CSS properties of this block.</span></td>
</tr>
<tr>
<td>Custom class block<br>
<br>
[class=custom]If the class exists, this block will have the custom class style applied.[/class]</td>
<td><pre>&lt;span class="custom"&gt;If the class exists,<br> this block will have the custom class<br> style applied.&lt;/span&gt;</pre></td>
</tr>
</table>

View File

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

View File

@ -0,0 +1,72 @@
Chats
=====
* [Home](help)
There are two possibilities to use chat on your friendica site
* IRC Chat
* Jappix
IRC-Chat Addon
---
After activating the addon, you can find the chat at [yoursite.com/irc](../irc).
Note: you can use this chat without any login at your site so that everyone could use it.
If you follow the link, you will see the login page of the IRC chat.
Now choose a nickname and a chatroom.
You can choose any name you like for the room, even something like #superchatwhosenameisonlyknownbyme.
Finally, solve the captchas and click the connect button.
The following window shows some text while connecting.
This text isn't important, just wait for the next window.
The first line shows your name and your current IP address.
The right part of the window shows all users.
The lower part of the window contains an input field.
Jappix Mini
---
The Jappix Mini Addon creates a chatbox for jabber- and XMPP-contacts.
You should already have a jabber/XMPP-account before setting up the addon.
You can find more information at [jabber.org](http://www.jabber.org/).
You can use several servers to create an account:
* [https://jappix.com](https://jappix.com)
* [http://xmpp.net](http://xmpp.net)
### 1. Basics
At first you have to get the current version. You can either pull it from [Github](https://github.com) like so:
$> cd /var/www/virtual/YOURSPACE/html/addon; git pull
Or you can download a tar archive here: [jappixmini.tgz](https://github.com/friendica/friendica-addons/blob/stable/jappixmini.tgz) (click at „view raw“).
Just unpack the file and rename the directory to „jappixmini“.
Next, upload this directory and the .tgz-file into your addon directory of your friendica installation.
Now you can activate the addon globally on the admin pages.
In the addon sidebar, you will find an entry of jappix now (where you can also find twitter, GNU Social and others).
The following page shows the settings of this addon.
Activate the BOSH proxy.
### 2. Settings
Go to your user account settings next and choose the addon page.
Scroll down until you find the Jappix Mini addon settings.
At first you have to activate the addon.
Now add your Jabber/XMPP name, the domain/server (without "http"; just "jappix.com").
For „Jabber BOSH Host“ you could use "https://bind.jappix.com/".
Note that you need another BOSH server if you do not use jappix.com for your XMPP account.
You can find further information in the „Configuration Help“-section below this fields.
At last you have enter your password (there are some more optional options, you can choose).
Finish these steps with "send" to save the entries.
Now, you should find the chatbox at the lower right corner of your browser window.
If you want to add contacts manually, you can click "add contact".

View File

@ -0,0 +1,120 @@
Using Composer
==============
* [Home](help)
* [Developer Intro](help/Developers-Intro)
Friendica uses [Composer](https://getcomposer.org) to manage dependencies libraries and the class autoloader both for libraries and namespaced Friendica classes.
It's a command-line tool that downloads required libraries into the `vendor` folder and makes any namespaced class in `src` available through the whole application through `boot.php`.
* [Class autoloading](help/autoloader)
## How to use Composer
If you don't have Composer installed on your system, Friendica ships with a copy of it at `bin/composer.phar`.
For the purpose of this help, all examples will use this path to run Composer commands, however feel free to replace them with your own way of calling Composer.
Composer requires PHP CLI and the following examples assume it's available system-wide.
### Installing/Updating Friendica
#### From Archive
If you just unpacked a Friendica release archive, you don't have to use Commposer at all, all the required libraries are already bundled in the archive.
#### Installing with Git
If you prefer to use `git`, you will have to run Composer to fetch the required libraries and build the autoloader before you can run Friendica.
Here are the typical commands you will have to run to do so:
````
~> git clone https://github.com/friendica/friendica.git friendica
~/friendica> cd friendica
~/friendica> bin/composer.phar install
````
That's it! Composer will take care of fetching all the required libraries in the `vendor` folder and build the autoloader to make those libraries available to Friendica.
#### Updating with Git
Updating Friendica to the current stable or the latest develop version is easy with Git, just remember to run Composer after every branch pull.
````
~> cd friendica
~/friendica> git pull
~/friendica> bin/composer.phar install
````
And that's it. If any library used by Friendica has been upgraded, Composer will fetch the version currently used by Friendica and refresh the autoloader to ensure the best performances.
### Developing Friendica
First of all, thanks for contributing to Friendica!
Composer is meant to be used by developers to maintain third-party libraries required by Friendica.
If you don't need to use any third-party library, then you don't need to use Composer beyond what is above to install/update Friendica.
#### Adding a third-party library to Friendica
Does your shiny new [Addon](help/Addons) need to rely on a third-party library not required by Friendica yet?
First of all, this library should be available on [Packagist](https://packagist.org) so that Composer knows how to fetch it directly just by mentioning its name in `composer.json`.
This file is the configuration of Friendica for Composer. It lists details about the Friendica project, but also a list of required dependencies and their target version.
Here's a simplified version of the one we currently use on Friendica:
````json
{
"name": "friendica/friendica",
"description": "A decentralized social network part of The Federation",
"type": "project",
...
"require": {
"ezyang/htmlpurifier": "~4.7.0",
"mobiledetect/mobiledetectlib": "2.8.*"
},
...
}
````
The important part is under the `require` key, this is a list of all the libraries Friendica may need to run.
As you can see, at the moment we only require two, HTMLPurifier and MobileDetect.
Each library has a different target version, and [per Composer documentation about version constraints](https://getcomposer.org/doc/articles/versions.md#writing-basic-version-constraints), this means that:
* We will update HTMLPurifier up to version 4.8.0 excluded
* We will update MobileDetect up to version 2.9.0 excluded
There are other operators you can use to allow Composer to update the package up to the next major version excluded.
Or you can specify the exact version of the library if you code requires it, and Composer will never update it although it isn't recommended.
To add a library, just add its Packagist identifier to the `require` list and set a target version string.
Then you should run `bin/composer.phar update` to add it to your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies.
#### Updating an existing dependency
If a package needs to be updated, whether to the next minor version or to the next major version provided you changed the adequate code in Friendica, simply edit `composer.json` to update the target version string of the relevant library.
Then you should run `bin/composer.phar update` to update it in your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies.
Please note that you should commit both `composer.json` and `composer.lock` with your work every time you make a change to the former.
## Composer FAQ
### I used the `composer` command and got a warning about not to run it as root.
See [https://getcomposer.org/root]().
Composer should be run as the web server user, usually `www-data` with Apache or `http` with nginx.
If you can't switch to the web server user using `su - [web user]`, you can directly run the Composer command with `sudo -u [web user]`.
### Running Composer with `sudo` complains about not being able to create the composer cache directory in `/root/.composer`
This is because `sudo` doesn't always change the `HOME` environment variable, which means that the command is run as the web server user but the system still uses `root` home directory.
However, you can temporarily change environment variable for the execution of a single command.
For Composer, this would be:
````
$> COMPOSER_HOME=/var/tmp/composer sudo -u [web user] bin/composer.phar [mode]
````
## Related
* [Class autoloading](help/autoloader)
* [How To Move Classes to `src`](help/Developer-How-To-Move-Classes-to-src)

View File

@ -0,0 +1,326 @@
Config values that can only be set in config/local.config.php
==========================================================
* [Home](help)
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
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
/*
* Comment block
*/
return [
'section1' => [
// Comment line
'key' => 'value',
],
'section2' => [
'array' => ['value0', 'value1', 'value2'],
],
];
```
### Configuration location
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.
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].config.php` which is loaded when the addon is activated.
### 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.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 {
margin: 1em 0;
background-color: #f9f9f9;
border: 1px solid #aaa;
border-collapse: collapse;
color: #000;
width: 100%;
}
table.config > tr > th,
table.config > tr > td,
table.config > * > tr > th,
table.config > * > tr > td {
border: 1px solid #aaa;
padding: 0.2em 0.4em
}
table.config > tr > th,
table.config > * > tr > th {
background-color: #f2f2f2;
text-align: center;
width: 50%
}
</style>
<table class="config">
<thead>
<tr>
<th>.htconfig.php</th>
<th>config/local.config.php</th>
</tr>
</thead>
<tbody>
<tr>
<td><pre>
$db_host = 'localhost';
$db_user = 'mysqlusername';
$db_pass = 'mysqlpassword';
$db_data = 'mysqldatabasename';
$a->config["system"]["db_charset"] = 'utf8mb4';
</pre></td>
<td><pre>
'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',
],
</pre></td>
</tr>
<tr>
<td><pre>
$a->config["section"]["key"] = array(
"value1",
"value2",
"value3"
);
</pre></td>
<td><pre>
'section' => [
'key' => ['value1', 'value2', 'value3'],
],
</pre></td>
</tr>
<tr>
<td><pre>
$a->config["key"] = "value";
</pre></td>
<td><pre>
'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',
],
</pre></td>
</tr>
<tr>
<td><pre>
$default_timezone = "value";
</pre></td>
<td><pre>
'system' => [
'default_timezone' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
$pidfile = "value";
</pre></td>
<td><pre>
'system' => [
'pidfile' => 'value',
],
</pre></td>
</tr>
<tr>
<td><pre>
$lang = "value";
</pre></td>
<td><pre>
'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',
]
If all of the following environment variables are set, Friendica will use them instead of the previously configured variables for the db:
MYSQL_HOST
MYSQL_PORT
MYSQL_USERNAME
MYSQL_PASSWORD
MYSQL_DATABASE
## 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.
Maybe they are part of a current development that isn't considered stable and will be added later in the administration page when it is considered safe.
Or it triggers something that isn't expected to be of public interest.
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 `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',
]
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',
]
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',
]

View File

@ -0,0 +1,72 @@
Connectors
==========
* [Home](help)
Connectors allow you to connect with external social networks and services.
They are only required for posting to existing accounts on Twitter or GNU Social.
There is also a connector for accessing your email INBOX.
If the following network connectors are installed on your system, select the following links to visit the appropriate settings page and configure them for your account:
* [Twitter](/settings/addon)
* [GNU Social](/settings/addon)
* [Email](/settings)
Instructions For Connecting To People On Specific Services
==========================================================
Friendica
---
You can either connect to others by providing your Identity Address on the 'Connect' page of any Friendica member.
Or you can put their Identity Address into the Connect box on your [Contacts](contacts) page.
Diaspora
---
Add the Diaspora 'handle' to the 'Connect/Follow' text box on your [Contacts](contacts) page.
GNU Social
---
This is described as the "federated social web" or OStatus contacts.
Please note that there are **no** privacy provisions on the OStatus network.
Any message which is delivered to **any** OStatus member is visible to anybody in the world and will negate any privacy settings that you have in effect.
These messages will also turn up in public searches.
Since OStatus communications do not use authentication, if you select the profile privacy option to hide your profile and messages from unknown viewers, OStatus members will **not** be able to receive your communications.
To connect with an OStatus member insert their profile URL or Identity address into the Connect box on your [Contacts](contacts) page.
The GNU Social connector may be used if you wish posts to appear on an OStatus site using an existing OStatus account.
It is not necessary to do this, as you may 'follow' OStatus members from Friendica and they may follow you (by placing their own Identity Address into your 'Connect' page).
Blogger, Wordpress, RSS feeds, arbitrary web pages
---
Put the URL into the Connect box on your [Contacts](contacts) page.
PLease note that you will not be able to reply to these contacts.
This feed reader feature will allow you to _connect_ with millions of pages on the internet.
All that the pages need to have is a discoverable feed using either the RSS or Atom syndication format, and which provides an author name and a site image in a form which we can extract.
Twitter
---
To follow a Twitter member, the Twitter-Connector (Addon) needs to be configured on your node.
If this is the case put the URL of the Twitter member's main page into the Connect box on your [Contacts](contacts) page.
To reply, you must have the Twitter connector installed, and reply using your own status editor.
Begin the message with @twitterperson replacing with the Twitter username.
Email
---
If the php module for IMAP support is available on your server, Friendica can connect to email contacts as well.
Configure the email connector from your [Settings](settings) page.
Once this has been done, you may enter an email address to connect with using the Connect box on your [Contacts](contacts) page.
They must be the sender of a message which is currently in your INBOX for the connection to succeed.
You may include email contacts in private conversations.

View File

@ -0,0 +1,239 @@
Domain-Driven-Design
==============
* [Home](help)
* [Developer Intro](help/Developers-Intro)
Friendica uses class structures inspired by Domain-Driven-Design programming patterns.
This page is meant to explain what it means in practical terms for Friendica development.
## Inspiration
- https://designpatternsphp.readthedocs.io/en/latest/Structural/DependencyInjection/README.html
- https://designpatternsphp.readthedocs.io/en/latest/Creational/SimpleFactory/README.html
- https://designpatternsphp.readthedocs.io/en/latest/More/Repository/README.html
- https://designpatternsphp.readthedocs.io/en/latest/Creational/FactoryMethod/README.html
- https://designpatternsphp.readthedocs.io/en/latest/Creational/Prototype/README.html
## Core concepts
### Models and Collections
Instead of anonymous arrays of arrays of database field values, we have Models and collections to take full advantage of PHP type hints.
Before:
```php
function doSomething(array $intros)
{
foreach ($intros as $intro) {
$introId = $intro['id'];
}
}
$intros = \Friendica\Database\DBA::selectToArray('intros', [], ['uid' => local_user()]);
doSomething($intros);
```
After:
```php
function doSomething(\Friendica\Collection\Introductions $intros)
{
foreach ($intros as $intro) {
/** @var $intro \Friendica\Model\Introduction */
$introId = $intro->id;
}
}
/** @var $intros \Friendica\Collection\Introductions */
$intros = \Friendica\DI::intro()->select(['uid' => local_user()]);
doSomething($intros);
```
### Dependency Injection
Under this concept, we want class objects to carry with them the dependencies they will use.
Instead of calling global/static function/methods, objects use their own class members.
Before:
```php
class Model
{
public $id;
function save()
{
return \Friendica\Database\DBA::update('table', get_object_vars($this), ['id' => $this->id]);
}
}
```
After:
```php
class Model
{
/**
* @var \Friendica\Database\Database
*/
protected $dba;
public $id;
function __construct(\Friendica\Database\Database $dba)
{
$this->dba = $dba;
}
function save()
{
return $this->dba->update('table', get_object_vars($this), ['id' => $this->id]);
}
}
```
The main advantage is testability.
Another one is avoiding dependency circles and avoid implicit initializing.
In the first example the method `save()` has to be tested with the `DBA::update()` method, which may or may not have dependencies itself.
In the second example we can mock `\Friendica\Database\Database`, e.g. overload the class by replacing its methods by placeholders, which allows us to test only `Model::save()` and nothing else implicitly.
The main drawback is lengthy constructors for dependency-heavy classes.
To alleviate this issue we are using [DiCe](https://r.je/dice) to simplify the instantiation of the higher level objects Friendica uses.
We also added a convenience factory named `\Friendica\DI` that creates some of the most common objects used in modules.
### Factories
Since we added a bunch of parameters to class constructors, instantiating objects has become cumbersome.
To keep it simple, we are using Factories.
Factories are classes used to generate other objects, centralizing the dependencies required in their constructor.
Factories encapsulate more or less complex creation of objects and create them redundancy free.
Before:
```php
$model = new Model(\Friendica\DI::dba());
$model->id = 1;
$model->key = 'value';
$model->save();
```
After:
```php
class Factory
{
/**
* @var \Friendica\Database\Database
*/
protected $dba;
function __construct(\Friendica\Database\Database $dba)
{
$this->dba;
}
public function create()
{
return new Model($this->dba);
}
}
$model = \Friendica\DI::factory()->create();
$model->id = 1;
$model->key = 'value';
$model->save();
```
Here, `DI::factory()` returns an instance of `Factory` that can then be used to create a `Model` object without having to care about its dependencies.
### Repositories
Last building block of our code architecture, repositories are meant as the interface between models and how they are stored.
In Friendica they are stored in a relational database but repositories allow models not to have to care about it.
Repositories also act as factories for the Model they are managing.
Before:
```php
class Model
{
/**
* @var \Friendica\Database\Database
*/
protected $dba;
public $id;
function __construct(\Friendica\Database\Database $dba)
{
$this->dba = $dba;
}
function save()
{
return $this->dba->update('table', get_object_vars($this), ['id' => $this->id]);
}
}
class Factory
{
/**
* @var \Friendica\Database\Database
*/
protected $dba;
function __construct(\Friendica\Database\Database $dba)
{
$this->dba;
}
public function create()
{
return new Model($this->dba);
}
}
$model = \Friendica\DI::factory()->create();
$model->id = 1;
$model->key = 'value';
$model->save();
```
After:
```php
class Model {
public $id;
}
class Repository extends Factory
{
/**
* @var \Friendica\Database\Database
*/
protected $dba;
function __construct(\Friendica\Database\Database $dba)
{
$this->dba;
}
public function create()
{
return new Model($this->dba);
}
public function save(Model $model)
{
return $this->dba->update('table', get_object_vars($model), ['id' => $model->id]);
}
}
$model = \Friendica\DI::repository()->create();
$model->id = 1;
$model->key = 'value';
\Friendica\DI::repository()->save($model);
```

View File

@ -0,0 +1,108 @@
How To Move Classes to `src`
==============
* [Home](help)
* [Developer Intro](help/Developers-Intro)
Friendica uses [Composer](help/Composer) to manage autoloading.
This means that all the PHP class files moved to the `src` folder will be [automatically included](help/autoloader) when the class it defines is first used in the flow.
This is an improvement over the current `require` usage since files will be included on an actual usage basis instead of the presence of a `require` call.
However, there are a significant number of items to check when moving a class file from the `include` folder to the `src` folder, and this page is there to list them.
## Decide the namespace
This isn't the most technical decision of them all, but it has long lasting consequences as it will be the name that will be used to refer to this class from now on.
There is [a shared Ethercalc sheet](https://ethercalc.org/friendica_classes) to suggest namespace/class names that lists all the already moved class files for inspiration.
A few pointers though:
* `Friendica` is the base namespace for all classes in the `src` folder
* Namespaces match the directory structure, with `Friendica` namespace being the base `src` directory. The `Config` class set in the `Friendica\Core` namespace is expected to be found at `src/Core/Config.php`.
* Namespaces can help group classes with a similar purpose or relevant to a particular feature
When you're done deciding the namespace, it's time to use it.
Let's say we choose `Friendica\Core` for the `Config` class.
## Use the namespace
To declare the namespace, the file `src/Core/Config.php` must start with the following statement:
````php
namespace Friendica\Core;
````
From now on, the `Config` class can be referred to as `Friendica\Core\Config`, however it isn't very practical, especially when the class was previously used as `Config`.
Thankfully, PHP provides namespace shortcuts through `use`.
This language construct just provides a different naming scheme for a namespace or a class, but doesn't trigger the autoload mechanism on its own.
Here are the different ways you can use `use`:
````php
// No use
$config = new Friendica\Core\Config();
````
````php
// Namespace shortcut
use Friendica\Core;
$config = new Core\Config();
````
````php
// Class name shortcut
use Friendica\Core\Config;
$config = new Config();
````
````php
// Aliasing
use Friendica\Core\Config as Cfg;
$config = new Cfg();
````
Whatever the style chosen, a repository-wide search has to be done to find all the class name usage and either use the fully-qualified class name (including the namespace) or add a `use` statement at the start of each relevant file.
## Escape non-namespace classes
The class file you just moved is now in the `Friendica` namespace, but it probably isn't the case for all the classes referenced in this file.
Since we added a `namespace Friendica\Core;` to the file, all the class names still declared in `include` will be implicitly understood as `Friendica\Core\ClassName`, which is rarely what we expect.
To avoid `Class Friendica\Core\ClassName not found` errors, all the `include`-declared class names have to be prepended with a `\`, it tells the autoloader not to look for the class in the namespace but in the global space where non-namespaced classes are set.
If there are only a handful of references to a single non-namespaced class, just prepending `\` is enough. However, if there are many instance, we can use `use` again.
````php
namespace Friendica\Core;
...
if (\DBM::is_result($r)) {
...
}
````
````php
namespace Friendica\Core;
use Friendica\Database\DBM;
if (DBM::is_result($r)) {
...
}
````
## Remove any useless `require`
Now that you successfully moved your class to the autoloaded `src` folder, there's no need to include this file anywhere in the app ever again.
Please remove all the `require_once` mentions of the former file, as they will provoke a Fatal Error even if the class isn't used.
## Miscellaneous tips
When you are done with moving the class, please run `php bin/console.php typo` from the Friendica base directory to check for obvious mistakes.
Howevever, this tool isn't bullet-proof, and a staging install of Friendica is recommended to test your class move without impairing your production server if you host one.
Most of Friendica processes are run in the background, so make sure to turn on your debug log to check for errors that wouldn't show up while simply browsing Friendica.
Check the class file for any magic constant `__FILE__` or `__DIR__`, as their value changed since you moved the class in the file tree.
Most of the time it's used for debugging purposes but there can be instances where it's used to create cache folders for example.
## Related
* [Class autoloading](help/autoloader)
* [Using Composer](help/Composer)

View File

@ -0,0 +1,158 @@
# Where to get started to help improve Friendica
<!-- markdownlint-disable MD010 MD013 -->
* [Home](help)
Do you want to help us improve Friendica?
Here we have compiled some hints on how to get started and some tasks to help you choose.
A project like Friendica is the sum of many different contributions.
**Very different skills are required to make good software, not all of them involve coding!**
We are looking for helpers in all areas, whether you write text or code, whether you spread the word to convince people or design new icons.
Whether you feel like an expert or like a newbie - join us with your ideas!
## Contact us
The discussion of Friendica development takes place in the following Friendica forums:
* The main [forum for Friendica development](https://forum.friendi.ca/profile/developers)
## Help other users
Remember the questions you had when you first tried Friendica?
A good place to start can be to help new people find their way around Friendica in the [general support forum](https://forum.friendi.ca/prufile/helpers).
Welcome them, answer their questions, point them to documentation or ping other helpers directly if you can't help but think you know who can.
## Translation
The documentation contains help on how to translate Friendica [at Transifex](/help/translations) where the UI is translated.
If you don't want to translate the UI, or it is already done to your satisfaction, you might want to work on the translation of the /help files?
## Design
Are you good at designing things?
If you have seen Friendica you probably have ideas to improve it, haven't you?
* If you would like to work with us on enhancing the user interface, please join the [forum for Friendica development](https://forum.friendi.ca/profile/developers).
* Make plans for a better Friendica interface design and share them with us.
* Tell us if you are able to realize your ideas or what kind of help you need.
We can't promise we have the right skills in the group but we'll try.
* Choose a thing to start with, e.g. work on the icon set of your favorite theme
## Programming
Friendica uses an implementation of [Domain-Driven-Design](help/Developer-Domain-Driven-Design), please make sure to check out the provided links for hints at the expected code architecture.
### Composer
Friendica uses [Composer](https://getcomposer.org) to manage dependencies libraries and the class autoloader both for libraries and namespaced Friendica classes.
It's a command-line tool that downloads required libraries into the `vendor` folder and makes any namespaced class in `src` available through the whole application through `boot.php`.
If you want to have git automatically update the dependencies with composer, you can use the `post-merge` [git-hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) with a script similar to this one:
#/usr/bin/env bash
# MIT © Sindre Sorhus - sindresorhus.com
# forked by Gianluca Guarini
# phponly by Ivo Bathke ;)
# modified for Friendica by Tobias Diekershoff
changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
check_run() {
echo "$changed_files" | grep --quiet "$1" && eval "$2"
}
# `composer install` if the `composer.lock` file gets changed
# to update all the php dependencies
check_run composer.lock "bin/composer.phar install --no-dev"
just place it into `.git/hooks/post-merge` and make it executable.
* [Class autoloading](help/autoloader)
* [Using Composer](help/Composer)
* [How To Move Classes to `src`](help/Developer-How-To-Move-Classes-to-src)
### Coding standards
For the sake of consistency between contribution and general code readability, Friendica follows the widespread [PSR-2 coding standards](http://www.php-fig.org/psr/psr-2/) to the exception of a few rules.
Here's a few primers if you are new to Friendica or to the PSR-2 coding standards:
* Indentation is tabs, period (not PSR-2).
* By default, strings are enclosed in single quotes, but feel free to use double quotes if it makes more sense (SQL queries, adding tabs and line feeds).
* Operators are wrapped by spaces, e.g. `$var === true`, `$var = 1 + 2` and `'string' . $concat . 'enation'`
* Braces are mandatory in conditions
* Boolean operators are `&&` and `||` for PHP conditions, `AND` and `OR` for SQL queries
* No closing PHP tag
* No trailing spaces
* Array declarations use the new square brackets syntax
* Quoting style is single quotes by default, except for needed string interpolation, SQL query strings by convention and comments that should stay in natural language.
Don't worry, you don't have to know by heart the PSR-2 coding standards to start contributing to Friendica.
There are a few tools you can use to check or fix your files before you commit.
For documentation we use the standard of *one sentence per line* for the `md` files in the `/doc` and `/doc/$lng` subdirectories.
#### Check with [PHP Code Sniffer](https://github.com/squizlabs/PHP_CodeSniffer)
This tool checks your files against a variety of coding standards, including PSR-2, and ouputs a report of all the standard violations.
You can simply install it through PEAR: `pear install PHP_CodeSniffer`
Once it is installed and available in your PATH, here's the command to run before committing your work:
$> phpcs --standard=ruleset.xml <file or directory>
The output is a list of all the coding standards violations that you should fix before committing your work.
Additionally, `phpcs` integrates with a few IDEs (Eclipse, Netbeans, PHPStorm...) so that you don't have to fiddle with the command line.
#### Fix with PHP Code Beautifier and Fixer (phpbcf) included in PHP Code Sniffer
If you're getting a massive list of standards violations when running `phpcs`, it can be annoying to fix all the violations by hand.
Thankfully, PHP Code Sniffer is shipped with an automatic code fixer that can take care of the tedious task for you.
Here's the command to automatically fix the files you created/modified:
$> phpcbf --standard=ruleset.xml <file or directory>
If the command-line tools `diff` and `patch` are unavailabe for you, `phpcbf` can use slightly slower PHP equivalents by using the `--no-patch` argument.
### 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 base directory of the project sources.
Run
$> 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.
If you find missing documentation, don't hesitate to contact us and write it down to enhance the code documentation.
### Issues
Have a look at our [issue tracker](https://github.com/friendica/friendica) on github!
* Try to reproduce a bug that needs more inquiries and write down what you find out.
* If a bug looks fixed, ask the bug reporters for feedback to find out if the bug can be closed.
* Fix a bug if you can. Please make the pull request against the *develop* branch of the repository.
* There is a *[Junior Job](https://github.com/friendica/friendica/issues?q=is%3Aopen+is%3Aissue+label%3A"Junior+Jobs")* label for issues we think might be a good point to start with.
But you don't have to limit yourself to those issues.
### Web interface
The thing many people want most is a better interface, preferably a responsive Friendica theme.
This is a piece of work!
If you want to get involved here:
* Look at the first steps that were made (e.g. the clean theme).
Ask us to find out whom to talk to about their experiences.
* Talk to design people if you know any.
* Let us know about your plans [in the dev forum](https://forum.friendi.ca/profile/developers)
Do not worry about cross-posting.
### Client software
As Friendica is using a [Twitter/GNU Social compatible API](help/api) any of the clients for those platforms should work with Friendica as well.
Furthermore there are several client projects, especially for use with Friendica.
If you are interested in improving those clients, please contact the developers of the clients directly.
* Android / LinageOS: **Friendiqa** [src](https://git.friendi.ca/lubuwest/Friendiqa)/[Google Play](https://play.google.com/store/apps/details?id=org.qtproject.friendiqa) developed by [Marco R](https://freunde.ma-nic.de/profile/marco)
* iOS: *currently no client*
* SailfishOS: **Friendiy** [src](https://kirgroup.com/projects/fabrixxm/harbour-friendly) - developed by [Fabio](https://kirgroup.com/profile/fabrixxm/profile)
* Windows: **Friendica Mobile** for Windows versions [before 8.1](http://windowsphone.com/s?appid=e3257730-c9cf-4935-9620-5261e3505c67) and [Windows 10](https://www.microsoft.com/store/apps/9nblggh0fhmn) - developed by [Gerhard Seeber](http://mozartweg.dyndns.org/friendica/profile/gerhard/profile)

View File

@ -0,0 +1,23 @@
# Export / Import of followed Contacts
* [Home](help)
In addition to [move your account](help/Move-Account) you can export and import the list of accounts you follow.
The exported list is stored as CSV file that is compatible to the format used by other platforms as e.g. Mastodon or Pleroma.
## Export of followed Contacts
To export the list of accounts that you follow, go to the [Settings Export personal date](settings/userexport) and click the [Export Contacts to CSV](settings/userexport/contact).
## Import of followed Contacts
To import contacts from a CSV file, go to the [Settings page](settings).
At the bottom of the *account settings* page you'll find the *import contacts* section.
Upload the CSV file there.
### Supported File Format
The CSV file *must* contain at least one column.
In the first column the table should contain either the handle or URL of an followed account.
(one account per row.)
Other columns in the CSV file will be ignored.

View File

@ -0,0 +1,239 @@
Frequently Asked Questions - FAQ
==============
* [Home](help)
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)**
* **[How to create a RSS feed of the stream?](help/FAQ#rss)**
* **[Are there any clients for friendica I can use?](help/FAQ#clients)**
* **[Where I can find help?](help/FAQ#help)**
Admins
* **[Can I configure multiple domains with the same code instance?](help/FAQ#multiple)**
* **[Where can I find the source code of friendica, addons and themes?](help/FAQ#sources)**
* **[I've changed the my email address now the admin panel is gone?](help/FAQ#adminaccount1)**
* **[Can there be more then just one admin for a node?](help/FAQ#adminaccount2)**
* **[The Database structure seems not to be updated. What can I do?](help/FAQ#dbupdate)**
User
--------
<a name="ssl"></a>
### Why do I get warnings about SSL certificates?
SSL (Secure Socket Layer) is a technology to encrypt data transfer between computers.
Sometimes your browser warns you about a missing or invalid certificate.
These warnings can have three reasons:
1. The server you are connected to doesn't offer SSL encryption.
2. The server has a self-signed certificate (not recommended).
3. The certificate is expired.
We recommend to talk to the admin(s) of the affected friendica server. (Admins, please see the respective section of the [admin manual](help/SSL).)
<a name="upload"></a>
### How can I upload images, files, links, videos and sound files to posts?
You can upload images from your computer using the [editor](help/Text_editor).
An overview of all uploaded images is listed at *yourpage.com/photos/profilename*.
On that page, you can also upload images directly and choose if your contacts will receive a message about this upload.
Generally, you can attach any kind of file to a post.
This is possible by using the "paper-clip"-symbol in the editor.
These files will be linked to your post and can be downloaded by your contacts.
But it's not possible to get a preview for these items.
Because of this, this upload method is only recommended for office or zipped files.
If you want to share content from Dropbox, Owncloud or any other [filehoster](http://en.wikipedia.org/wiki/Comparison_of_file_hosting_services), use the "link"-button (chain-symbol).
When you're adding URLs of other webpages with the "link"-button, Friendica tries to create a small preview.
If this doesn't work, try to add the link by typing: [url=http://example.com]*self-chosen name*[/url].
You can also add video and audio files to posts.
However, instead of a direct upload you have to use one of the following methods:
1. Add the video or audio link of a hoster (Youtube, Vimeo, Soundcloud and anyone else with oembed/opengraph-support). Videos will be shown with a preview image you can click on to start. SoundCloud directly inserts a player to your post.
2. If you have your own server, you can upload multimedia files via FTP and insert the URL.
Friendica uses HTML5 for embedding content.
Therefore, the supported files are dependent on your browser and operating system.
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>
### Is it possible to have different avatars per profile?
Yes.
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.
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?
We prevent direct communication with **blocked contacts**.
They are not included in delivery, and their own posts to you are not imported.
However their conversations with your friends will still be visible in your stream.
If you remove a contact completely, they can send you another friend request.
Blocked contacts cannot do this. They cannot communicate with you directly, only through friends.
**Ignored contacts** are included in delivery - they will receive your posts and private messages.
However we do not import their posts or private messages to you.
Like blocking, you will still see this person's comments to posts made by your friends.
An addon called "blockem" can be installed to collapse/hide all posts from a particular person in your stream if you desire complete blocking of an individual, including his/her conversations with your other friends.
An **archived contact** means that communication is not possible and will not be attempted.
(Perhaps the person moved to a new site and removed the old profile.)
However unlike blocking, existing posts this person made before being archived will be visible in your stream.
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?
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.
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?
Yes. Simply add the hash tag to your saved searches.
The posts will appear on your network page.
For technical reasons, your answers to such posts won't appear on the "personal" tab in the network page and the whole thread isn't accessible via the API.
<a name="rss"></a>
### How to create a RSS feed of the stream?
If you want to share your public page via rss you can use one of the following links:
#### RSS feed of your posts
basic-url.com//feed/[nickname]/posts
Example: Friendica Support
https://forum.friendi.ca/feed/helpers/posts
#### RSS feed of the conversations at your site
basic-url.com/feed/profilename/comments
Example: Friendica Support
https://forum.friendi.ca/feed/helpers/comments
<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 platform as long as you can change the API path in its settings.
Here is a list of known working clients:
* Android
* [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://fedilab.app/) (available in F-Droid and Google stores)
* [DiCa](https://dica.mixi.cool/)
* AndStatus
* Twidere
* Mustard and Mustard-Mod
* SailfishOS
* [Friendly](https://openrepos.net/content/fabrixxm/friendly#comment-form)
* Linux
* Hotot
* Choqok
* MacOS X
* Hotot
* Windows
* [Friendica Mobile](https://www.microsoft.com/de-DE/store/p/friendica-mobile/9nblggh0fhmn?rtc=1) for Windows 10
* Hotot
Depending on the features of the client you might encounter some glitches in usability, like being limited in the length of your postings to 140 characters and having no access to the [permission settings](help/Groups-and-Privacy).
<a name="help"></a>
### Where I can find help?
If you have problems with your Friendica page, you can ask the community at the [Friendica Support Group](https://forum.friendi.ca/profile/helpers).
If you can't use your default profile you can use an account at a public site [list](https://dir.friendica.social/servers).
In case you do not want to set up another account on Friendica, you can also use one of the following channels to reach out for help:
* [Friendica Support Forum](https://forum.friendi.ca/~helpers)
* [Mailing List Archive](http://mailman.friendi.ca/mailman/listinfo/support-friendi.ca) you can subscribe to the list by sending an email to ``support-request(at)friendi.ca?subject=subscribe``
* XMPP/Jabber MUC: support(at)forum.friendi.ca
* IRC: #friendica at irc.freenode.net
* Matrix: #friendi.ca or #friendica at matrix.org
Admin
--------
<a name="multiple"></a>
### Can I configure multiple domains with the same code instance?
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 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).
If you are searching for new themes, you can find them at [Friendica-Themes.com](http://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.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.config.php</tt> file.
The listed emails need to be separated by a comma.
<a name="dbupdate">
### The Database structure seems not to be updated. What can I do?
Please have a look at the Admin panel under [DB updates](/admin/dbsync/) and follow the link to *check database structure*.
This will start a background process to check if the structure is up to the current definition.
You can manually execute the structure update from the CLI in the base directory of your Friendica installation by running the following command:
bin/console dbstructure update
if there occur any errors, please contact the [support forum](https://forum.friendi.ca/profile/helpers).

View File

@ -0,0 +1,66 @@
Forums
=====
* [Home](help)
Friendica also lets you create community forums and other types of accounts that can function as discussion forums, celebrity accounts, announcement channels, news reflectors, or organization pages, depending on how you want to interact with others. Management of these pages can be delegated to other accounts, or a parent account can be designated to easily toggle multiple identities.
Every page in Friendica has a nickname and these must all be unique. This applies to all forums, whether they are normal profiles or forum profiles.
Managing Accounts
---
To create a new linked account that can be used as a forum, log in to your normal account and go to Settings > Manage Accounts.
Here you can register additional accounts with new nicknames that will be linked to your primary account.
You may appoint a delegate to manage your new account (e.g. forum page).
The Delegates section of Manage Accounts page will provide you with a list of contacts on this instance 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.
Please use this facility wisely.
Delegated managers will not be able to alter basic account settings, such as passwords or page types, or remove the account.
Additionally, this page is also where you can choose to designate an account as a parent user.
If your primary account is designated as the parent user, you will be able to easily toggle identities and manage your forums or other types of accounts.
Types of Accounts
---
On the new account, visit the Settings > Account page.
Towards the end of the page is a section for "Advanced account types".
Typically you would use "Personal Page - Standard" for a normal personal account with manual approval of “friends” and “followers.”
This is the default selection.
On this page you can change the type of account if desired.
The other subtypes of a Personal Page are “Soapbox” and “Love-all.”
A Soapbox account is an announcement channel that automatically approvals follower requests.
Everything posted by the account will go out to the followers, but there will be no opportunity for interaction.
This setting would typically be used for announcements or corporate communications.
“Love-all” automatically approves contacts as friends.
In addition to Personal Page, there are options for Organization Page, News Page, and Community Forum.
Organization and New Pages automatically approve contact requests as followers.
Community Forum provide the ability for people to become friends/fans of the forum without requiring approval.
This creates a forum page where all members can freely interact.
Posting to Community forums
---
If you are a member of a community forum, you may post to the forum by including an @-tag in the post mentioning the forum.
For example @bicycle would send my post to all members of the group "bicycle" in addition to the normal recipients.
If you mention a forum (you are a member of) in a new posting, the posting will be distributed to all members of the forum, regardless of your privacy settings for the posting.
Also, if the forum is a public forum, your posting will be public for the all internet users.
If your post is private you must also explicitly include the group in the post permissions (to allow the forum "contact" to see the post) **and** mention it in a tag (which redistributes the post to the forum members).
Posting privately to a public forum, will result in your posting being displayed on the forum wall, but not on yours.
Additionally it is possible to address a forum with the exclamation mark.
In the example above this means that you can address the bicycle forum via !bicycle.
The difference to the @ is that the post will only be sent to the addressed forum.
This also means that you shouldn't address multiple forums in a single post in that way since it will only be distributed by one the forums.
You may also post to a community forum by posting a "wall-to-wall" post using secure cross-site authentication.
Comments which are relayed to community forums will be relayed back to the original post creator.
Mentioning the forum with an @-tag in a comment does not relay the message, as distribution is controlled entirely by the original post creator.

View File

@ -0,0 +1,76 @@
Friendica on GitHub
===================
* [Home](help)
Here is how you can work on the code with us. If you have any questions please write to the Friendica developers' forum.
Introduction to the workflow with our GitHub repository
-------------------------------------------------------
1. Install git on the system you will be developing on.
2. Create your own [GitHub](https://github.com) account.
3. Fork the Friendica repository from [https://github.com/friendica/friendica.git](https://github.com/friendica/friendica.git).
4. Clone your fork from your GitHub account to your machine.
Follow the instructions provided here: [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/) to create and use your own tracking fork on GitHub
5. Run `bin/composer.phar install` in Friendica's folder.
6. Commit your changes to your fork.
Then go to your GitHub page and create a "Pull request" to notify us to merge your work.
Our Git Branches
----------------
There are two relevant branches in the main repo on GitHub:
1. stable: This branch contains stable releases only.
2. develop: This branch contains the latest code.
This is what you want to work with.
Fast-forwarding
---------------
Fast forwarding is enabled by default in git.
When you merge with fast-forwarding it does not add a new commit to mark when you've performed the merge and how.
This means in your commit history you can't know exactly what happened in terms of merges.
**It's best to turn off fast-forwarding.**
This is done by running "git merge --no-ff".
[Here](https://stackoverflow.com/questions/5519007/how-do-i-make-git-merges-default-be-no-ff-no-commit) is an explanation on how to configure git to turn off fast-forwarding by default.
You can find some more background reading [here](http://nvie.com/posts/a-successful-git-branching-model/).
Release branches
----------------
A release branch is created when the develop branch contains all features it should have.
A release branch is used for a few things.
1. It allows last-minute bug fixing before the release goes to stable branch.
2. It allows meta-data changes (README, CHANGELOG, etc.) for version bumps and documentation changes.
3. It makes sure the develop branch can receive new features that are **not** part of this release.
That last point is important because...
**The moment a release branch is created, develop is now intended for the version after this release**.
So please don't ever merge develop into a release!
An example: If a release branch "release-3.4" is created, "develop" becomes either 3.5 or 4.0.
If you were to merge develop into release-3.4 at this point, features and bug-fixes intended for 3.5 or 4.0 might leak into this release branch.
This might introduce new bugs, too.
Which defeats the purpose of the release branch.
Some important reminders
------------------------
1. Please pull in any changes from the project repository and merge them with your work **before** issuing a pull request.
We reserve the right to reject any patch which results in a large number of merge conflicts.
This is especially true in the case of language translations - where we may not be able to understand the subtle differences between conflicting versions.
2. **Test your changes**.
Don't assume that a simple fix won't break anything else.
If possible get an experienced Friendica developer to review the code.
Don't hesitate to ask us in case of doubt.
3. Check your code for typos.
There is a console command called *typo* for this.
$> php bin/console.php typo
Check out how to work with [our Vagrant](help/Vagrant) to save a lot of setup time!

View File

@ -0,0 +1,112 @@
Groups and Privacy
==================
* [Home](help)
Groups are merely collections of friends.
But Friendica uses these to unlock some very powerful features.
**Setting Up Groups**
To create a group, visit your Friendica "Contacts" page and select "Create a new group".
Give the group a name.
This brings you to a page where you can select the group members.
You will have two boxes on this page.
The top box is the roster of current group members.
Below that is another box containing all of your friends who are *not* members of the group.
If you click on a photo of a person who isn't in the group, they will be put into the group.
If you click on a photo of a person who is in the group, they will be removed from it.
**Access Control**
Once you have created a group, you may use it in any access control list.
This is the little lock icon beneath the status update box on your home page.
If you click this you can select who can see and who can *not* see the post you are about to make..
These can be individual people or groups.
On your "Network" page you will find posts and conversation from everybody in your network.
You may select an individual group on this page to show conversations pertaining only to members of that group.
But wait, there's more...
If you look carefully when visiting a group from your Network page, the lock icon under the status update box has an exclamation mark next to it.
This is meant to draw attention to that lock.
Click the lock.
You will see that since you are only viewing a certain group of people, your status updates while on that screen default to only being seen by that same group of people.
This is how you keep your future employers from seeing what you write to your drinking buddies.
You can over-ride this setting, but this makes it easy to separate your conversations into different friend circles.
**Default Post Privacy**
By default, Friendica assumes that you want all of your posts to be private.
Therefore, when you sign up, Friendica creates a group for you that it will automatically add all of your contacts to.
All of your posts are restricted to that group by default.
Note that this behaviour can be overridden by your site admin, in which case your posts will be "public" (i.e. visible to the entire Internet) by default.
If you want your posts to be "public" by default, you can change your default post permissions on your Settings page.
You also have the option there to change which groups you post to by default, or to change which group your new contacts get placed into by default.
**Privacy Concerns To Be Aware Of**
These private conversations work best when your friends are Friendica members.
We know who else can see the conversations - nobody, *unless* your friends cut and paste the messages and send them to others.
This is a trust issue you need to be aware of.
No software in the world can prevent your friends from leaking your confidential and trusted communications.
Only a wise choice of friends.
But it isn't as clear cut when dealing with GNU Social and other network providers.
If you look at the Contact Edit page for any person, we will tell you whether or not they are members of an insecure network where you should exercise caution.
Once you have created a post, you can not change the permissions assigned.
Within seconds it has been delivered to lots of people - and perhaps everybody it was addressed to.
If you mistakenly created a message and wish you could take it back, the best you can do is to delete it.
We will send out a delete notification to everybody who received the message - and this should wipe out the message with the same speed it was initially propagated.
In most cases it will be completely wiped from the Internet - in under a minute.
Again, this applies to Friendica networks.
Once a message spreads to other networks, it may not be removed quickly and in some cases it may not be removed at all.
In case you haven't yet figured this out, we are encouraging you to encourage your friends to use Friendica - because all these privacy features work much better within a privacy-aware network.
Many of the other social networks Friendica can connect to have no privacy controls.
Profiles, Photos, and Privacy
=============================
The decentralised nature of Friendica (many websites exchanging information rather than one website which controls everything) has some implications with privacy as it relates to people on other sites.
There are things you should be aware of, so you can decide best how to interact privately.
**Photos**
Sharing photos privately is a problem.
We can only share them __privately__ with Friendica members.
In order to share with other people, we need to prove who they are.
We can prove the identity of Friendica members, as we have a mechanism to do so.
Your friends on other networks will be blocked from viewing these private photos because we cannot prove that they should be allowed to see them.
Our developers are working on solutions to allow access to your friends - no matter what network they are on.
However we take privacy seriously and don't behave like some networks that __pretend__ your photos are private, but make them available to others without proof of identity.
**Profiles**
Your profile and "wall" may also be visited by your friends from other networks, and you can block access to these by web visitors that Friendica doesn't know.
Be aware that this could include some of your friends on other networks.
This may produce undesired results when posting a long status message to (for instance) Twitter.
When Friendica sends a post to these networks which exceeds the service length limit, we truncate it and provide a link to the original.
The original is a link back to your Friendica profile.
As Friendica cannot prove who they are, it may not be possible for these people to view your post in full.
For people in this situation we would recommend providing a "Twitter-length" summary, with more detail for friends that can see the post in full.
You can do so by including the BBCode tag *abstract* in your posting.
Blocking your profile or entire Friendica site from unknown web visitors also has serious implications for communicating with GNU Social members.
These networks communicate with others via public protocols that are not authenticated.
In order to view your posts, these networks have to access them as an "unknown web visitor".
If we allowed this, it would mean anybody could in fact see your posts, and you've instructed Friendica not to allow this.
So be aware that the act of blocking your profile to unknown visitors also has the effect of blocking outbound communication with public networks (such as GNU Social) and feed readers such as Google Reader.

View File

@ -0,0 +1,79 @@
Friendica Documentation and Resources
=====================================
**User Manual**
* General functions - first steps
* [Account Basics](help/Account-Basics)
* [New User Quick Start](help/Quick-Start-guide)
* [Creating posts](help/Text_editor)
* [BBCode tag reference](help/BBCode)
* [Comment, sort and delete posts](help/Text_comment)
* [Profiles](help/Profiles)
* [Accesskey reference](help/Accesskeys)
* [Events](help/events)
* You and other users
* [Connectors](help/Connectors)
* [Making Friends](help/Making-Friends)
* [Groups and Privacy](help/Groups-and-Privacy)
* [Tags and Mentions](help/Tags-and-Mentions)
* [Community Forums](help/Forums)
* [Chats](help/Chats)
* Further information
* [Move your account](help/Move-Account)
* [Export / Import of followed Contacts](help/Export-Import-Contacts)
* [Delete your account](help/Remove-Account)
* [Frequently asked questions (FAQ)](help/FAQ)
**Admin Manual**
* [Install](help/Install)
* [Update](help/Update)
* [Settings & Admin Panel](help/Settings)
* [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.config.php](help/Config)
* [Improve Performance](help/Improve-Performance)
* [Migrate](help/Migrate)
* [Administration Tools](help/tools)
**Developer Manual**
* [Get started](help/Developers-Intro)
* Set up development environment
* [Help on Github](help/Github)
* [Help on Vagrant](help/Vagrant)
* [Bugs and Issues](help/Bugs-and-Issues)
* Code structure
* [Domain-Driven-Design](help/Developer-Domain-Driven-Design)
* [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)
* [Move classes to `src`](help/Developer-How-To-Move-Classes-to-src)
* [Run tests](help/Tests)
* Reference
* [API endpoints](help/api)
* [Code (Doxygen generated - sets cookies)](doc/html/)
* [Protocol Documentation](help/Protocol)
* [Database schema documentation](help/database)
* [Class Autoloading](help/autoloader)
**External Resources**
* [Main Website](https://friendi.ca)
* Ways to get Support
* [Friendica Support Forum](https://forum.friendi.ca/~helpers)
* [Mailing List Archive](http://mailman.friendi.ca/mailman/listinfo/support-friendi.ca) you can subscribe to the list by sending an email to ``support-request(at)friendi.ca?subject=subscribe``
* XMPP/Jabber MUC: support(at)forum.friendi.ca
* IRC: #friendica at irc.freenode.net
* Matrix: #friendi.ca or #friendica at matrix.org
**About**
* [Site/Version Info](friendica)
* [Friendica Credits](credits)

View File

@ -0,0 +1,86 @@
How to improve the performance of a Friendica site
==============
* [Home](help)
Feel free to ask in the [Friendica support forum](https://forum.friendi.ca/profile/helpers) if you need some clarification about the following instructions or if you need help in any other way.
System configuration
--------
Please go to /admin/site/ on your system and change the following values:
Set "JPEG image quality" to 50.
This value reduces the data that is send from the server to the client. 50 is a value that doesn't influences image quality too much.
Set "OStatus conversation completion interval" to "never".
If you have many OStatus contacts then completing of conversations can take some time. Since you will miss several comments in OStatus threads, you maybe should consider the option "At post arrival" instead.
Enable "Use MySQL full text engine"
When using MyISAM (default) or InnoDB on MariaDB 10 this speeds up search.
Addons
--------
Active the following addons:
rendertime
### rendertime
This addon doesn't speed up your system.
It helps to analyze your bottlenecks.
When enabled you see some values at the bottom of every page.
They show your performance problems.
Performance: Database: 0.244, Network: 0.002, Rendering: 0.044, Parser: 0.001, I/O: 0.021, Other: 0.237, Total: 0.548
Database: This is the time for all database queries
Network: Time that is needed to fetch content from external sites
Rendering: Time for theme rendering
Parser: The time that the BBCode parser needed to create the output
I/O: Time for local file access
Others: Everything else :)
Total: The sum of all above values
Apache Webserver
--------
The following Apache modules are recommended:
### Cache-Control
This module tells the client to cache the content of static files so that they aren't fetched with every request.
Enable the module "mod_expires" by typing in "a2enmod expires" as root.
Please add the following lines to your site configuration in the "directory" context.
ExpiresActive on ExpiresDefault "access plus 1 week"
Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_expires.html) / [2.4](https://httpd.apache.org/docs/2.4/mod/mod_expires.html) documentation.
### Compress content
This module compresses the traffic between the web server and the client.
Enable the module "mod_deflate" by typing in "a2enmod deflate" as root.
Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_deflate.html) / [2.4](https://httpd.apache.org/docs/2.4/mod/mod_deflate.html) documentation.
PHP
--------
### FCGI
When using Apache think about using FCGI.
In a Debian-based distribution you will need to install the packages named "php5-cgi" and "libapache2-mod-fcgid".
Please refer to external documentation for a more detailed explanation how to set up a system based upon FCGI.
### Database
There are scripts like [tuning-primer.sh](http://www.day32.com/MySQL/) and [mysqltuner.pl](http://mysqltuner.pl) that analyze your database server and give hints on values that could be changed.
Please enable the slow query log. This helps to find performance problems.

View File

@ -0,0 +1,453 @@
# 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](#Requirements) 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.
## 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
* Apache with mod-rewrite enabled and "Options All" so you can use a local `.htaccess` file
* 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, mbstrings, 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.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.
**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.
## Installation procedure
### Alternative Installation Methods
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 to [install Friendica with YunoHost](https://github.com/YunoHost-Apps/friendica_ynh).
### Get Friendica
Download the full archive of the stable release of Friendica core and the addons from [the project homepage](https://friendi.ca/resources/download-files/).
Make sure that the version of the Friendica archive and the addons match.
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-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 stable mywebsite
cd mywebsite
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*
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 stable addon
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
**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
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 [troubleshooting](#Troubleshooting) section if running on MySQL 5.7.17 or newer.
### Option A: Run the installer
Before you point your web browser to the new site you need to copy `.htaccess-dist` to `.htaccess` for Apache installs.
Follow the instructions.
Please note any error messages and correct these before continuing.
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.
*If* the manual installation fails for any reason, check the following:
* 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.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.config.php`)
- using environment variables (f.e. `MYSQL_HOST`)
- using options (f.e. `--dbhost <host>`)
You can combine environment variables and options, but be aware that options are prioritized over environment variables.
For more information during the installation, you can use this command line option
bin/console autoinstall -v
If you wish to include all optional checks, use `-a` like this statement:
bin/console autoinstall -a
*If* the automatic installation fails for any reason, check the following:
* Does `config/local.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.config.php](/config/local-sample.config.php).
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall -f <prepared.config.php>
#### B.2: Environment variables
There are two types of environment variables.
- those you can use in normal mode too (Currently just **database credentials**)
- those you can only use during installation (because Friendica will normally ignore it)
You can use the options during installation too and skip some of the environment variables.
**Database credentials**
if you don't use the option `--savedb` during installation, the DB credentials will **not** be saved in the `config/local.config.php`.
- `MYSQL_HOST` The host of the mysql/mariadb database
- `MYSQL_PORT` The port of the mysql/mariadb database
- `MYSQL_USERNAME` The username of the mysql database login (used for mysql)
- `MYSQL_USER` The username of the mysql database login (used for mariadb)
- `MYSQL_PASSWORD` The password of the mysql/mariadb database login
- `MYSQL_DATABASE` The name of the mysql/mariadb database
**Friendica settings**
This variables wont be used at normal Friendica runtime.
Instead, they get saved into `config/local.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 language of Friendica
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall [--savedb]
#### B.3: Execution options
All options will be saved in the `config/local.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`)
- `-U|--dbuser <username>` The username of the mysql/mariadb database login (env `MYSQL_USER` or `MYSQL_USERNAME`)
- `-P|--dbpass <password>` The password of the mysql/mariadb database login (env `MYSQL_PASSWORD`)
- `-d|--dbdata <database>` The name of the mysql/mariadb database (env `MYSQL_DATABASE`)
- `-u|--urlpath <url_path>` The URL path of Friendica - f.e. '/friendica' (env `FRIENDICA_URL_PATH`)
- `-b|--phppath <php_path>` The path of the PHP binary (env `FRIENDICA_PHP_PATH`)
- `-A|--admin <mail>` The admin email address of Friendica (env `FRIENDICA_ADMIN_MAIL`)
- `-T|--tz <timezone>` The timezone of Friendica (env `FRIENDICA_TZ`)
- `-L|--lang <language>` The language of Friendica (env `FRIENDICA_LANG`)
Navigate to the main Friendica directory and execute the following command:
bin/console autoinstall [options]
### Prepare .htaccess file
Copy `.htaccess-dist` to `.htaccess` (be careful under Windows) to have working mod-rewrite again. If you have installed Friendica into a sub directory, like */friendica/* set this path in `RewriteBase` accordingly.
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.
### Verify the "host-meta" page is working
Friendica should respond automatically to important addresses under the */.well-known/* rewrite path.
One critical URL would look like, for example: https://example.com/.well-known/host-meta
It must be visible to the public and must respond with an XML file that is automatically customized to your site.
If that URL is not working, it is possible that some other software is using the /.well-known/ path.
Other symptoms may include an error message in the Admin settings that says "host-meta is not reachable on your system.
This is a severe configuration issue that prevents server to server communication."
Another common error related to host-meta is the "Invalid profile URL."
Check for a `.well-known` directory that did not come with Friendica.
The preferred configuration is to remove the directory, however this is not always possible.
If there is any /.well-known/.htaccess file, it could interfere with this Friendica core requirement.
You should remove any RewriteRules from that file, or remove that whole file if appropriate.
It may be necessary to chmod the /.well-known/.htaccess file if you were not given write permissions by default.
## 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:
cd /base/directory; /path/to/php bin/worker.php
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:
*/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 run into trouble with this section please contact your hosting provider for assistance.
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.
#### 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.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 blocklists.
### 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

@ -0,0 +1,89 @@
Installing Connectors (Twitter/GNU Social)
==================================================
* [Home](help)
Friendica uses addons to provide connectivity to some networks, such as Twitter.
There is also a addon to post through to an existing account on a GNU Social service.
You only need this to post to an already existing GNU Social account, but not to communicate with GNU Social members in general.
All three addons require an account on the target network.
In addition you (or typically the server administrator) will need to obtain an API key to provide authenticated access to your Friendica server.
Site Configuration
---
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.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.
The details of configuring each service follow (much of this information comes directly from the addon source files):
Twitter Addon for Friendica
---
* Author: Tobias Diekershoff
* tobias.diekershoff@gmx.net
* License: 3-clause BSD license
### Configuration
To use this addon you need a OAuth Consumer key pair (key & secret).
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.config.php:
[twitter]
consumerkey = your consumer_key here
consumersecret = your consumer_secret here
After this, your users can configure their Twitter account settings from "Settings -> Connector Settings".
### More documentation
Find the author's documentation here: [http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin](http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin)
GNU Social Addon for Friendica
---
* Author: Tobias Diekershoff
* tobias.diekershoff@gmx.net
* License: 3-clause BSD license
### Configuration
When the addon is activated the user has to acquire the following in order to connect to the GNU Social account of choice.
* The base URL for the GNU Social API, for quitter.se this is https://quitter.se/api/
* OAuth Consumer key & secret
To get the OAuth Consumer key pair the user has to
1 ask her Friendica admin if a pair already exists or
2 has to register the Friendica server as a client application on the GNU Social server.
This can be done from the account settings under "Settings -> Connections -> Register an OAuth client application -> Register a new application" on the GNU Social server.
During the registration of the OAuth client remember the following:
* Application names must be unique on the GNU Social site, so we recommend a Name of 'friendica-nnnn', replace 'nnnn' with a random number or your website name.
* there is no callback url
* register a desktop client
* with read & write access
* the Source URL should be the URL of your Friendica server
After the required credentials for the application are stored in the configuration you have to actually connect your Friendica account with GNU Social.
This is done from the Settings -> Connector Settings page.
Follow the Sign in with GNU Social button, allow access and then copy the security code into the box provided.
Friendica will then try to acquire the final OAuth credentials from the API.
If successful, the addon settings will allow you to select to post your public messages to your GNU Social account (have a look behind the little lock symbol beneath the status "editor" on your Home or Network pages).

View File

@ -0,0 +1,10 @@
Keyboard shortcuts in Friendica
=======================
* [Home](help)
General
-------
* j: Scroll to next thread
* k: Scroll to previous thread

View File

@ -0,0 +1,111 @@
Making Friends
==============
* [Home](help)
Friendship in Friendica can sometimes take on different meaning.
But let's keep it simple; you want to be friends with somebody.
How do you do it?
The Directories
---
Friendica has two different kinds of "address book".
The directory of the Friendica server you are registered on and a global directory to which your and other Friendica servers submit account information.
The first thing you can do is look at the **Directory**.
The directory is split up into two parts.
If you click the directory button, you will be presented with a list of all members (who chose to be listed) on your server.
You'll also see a link to a **Global Directory**.
There are several global directories across the globe that regularly exchange information with each other.
The specific global directory that you see usually depends on where your server is located.
If you click through to the global directory, you will be presented with a list of everybody who choses to be listed across all instances of Friendica.
You will also see a "Show Community Forums" link, which will direct you to Groups, Forums and Fanpages.
You connect to people, groups and forums in the same way, except groups and forums will automatically accept your introduction request, whereas a human will approve you manually.
Connect to other Friendica users
---
Visit their profile.
Just beneath their profile picture will be the word 'Connect' (we're assuming this is an English language profile).
Click that 'Connect' button and it will take you to a 'Connect' form.
The form is going to ask you for your Identity Address.
This is necessary so that this person's website can find yours.
If your Friendica site is called "demo.friendica.com" and your username/nickname on that site is "bob", you would enter "bob@demo.friendica.com" in this form.
Notice this looks just like an email address.
It's meant to be that way.
It's easy for people to remember.
You *could* also put in the URL of your "home" page, such as "http://demo.friendica.com/profile/bob" instead of the email-style address.
When you've submitted the connection page, it will take you back to your own site where you must then login (if necessary) and verify the connection request on *your* site.
Once you've done this, the two websites can communicate with each other to complete the process (after your new friend has approved the request).
If you already know somebody's Identity Address, you can enter it in the "connect" box on your "Contacts" page.
This will take you through a similar process.
Connect to users of alternate networks
---
### Across the Federation and Fedivese
You can also use your Identity Address or other people's Identity Addresses to become friends across the so-called Federation/Fedivese of open source social media.
Currently, Friendica supports connections with people on diaspora*, Red, Hubzilla, GNU Social, StatusNet, Mastodon, Pleroma, socialhome, and ganggo platforms.
If you know (for instance) "alice" on gnusocial.net (a GNU Social site) you could put alice@gnusocial.net into your Contact page and become friends across networks.
Likwise you can put in the URL to Alice's gnusocial.net page, if you wish.
Note: Some versions of GNU Social software may require the full URL to your profile and may not work with the identity address.
People on these networks can also initiate contact with you, if they know your contact details.
### Other social media
If you server provides this functionality, you can also connect with people one
Twitter or important feeds from Tumblr, Wordpress, and many more.
To connect, enter their contact details in the "connect" box on your "Contacts" page.
### Email
If you have supplied your mailbox connection information on your Settings page, you can enter the email address of anybody that has sent you a message recently and have their email messages show up in your social stream.
You can also reply to them from within Friendica.
Create an email contact with for example Alice on Gmail, enter her email in following format "mailto:alice@gmail.no".
In order to avoid abuse or spam, you must have an email from Alice with the correct email address in your email inbox.
Subscribing to mailing lists is done in the same way, but without the use of the "mailto:" prefix.
To subscribe to a mailing list, enter the email in following example format "mailling-list@list-server.net".
### Syndication feeds
You can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.).
If we can find an information stream and a name to attach to the contact, we'll try to connect with them.
Notification
---
When somebody requests friendship you will receive a notification.
You will usually need to approve this before the friendship is complete.
Approval
---
Some networks allow people to send you messages without being friends and without your approval.
Friendica does not allow this by default, as it would open a gateway for spam.
Unilateral or bilateral friendships
---
When you receive a friendship notification from another Friendica member, you will have the option of allowing them as a "Follower" or as a "Friend".
If they are a follower, they can see what you have to say, including private communications that you send to them, but not vice versa.
As a friend, you can both communicate with each other.
diaspora* uses a different terminology, and you are given the option of allowing them to "share with you", or being full friends.
Ignoring, blocking and deleting contacts
---
Once you have become friends, if you find the person constantly sends you spam or worthless information, you can "Ignore" them - without breaking off the friendship or even alerting them to the fact that you aren't interested in anything they are saying.
In many ways they are like a "follower" - but they don't know this.
They think they are a friend.
You can also "block" a person.
This completely blocks communications with that person.
They may still be able to see your public posts, as can anybody in the world, but they cannot communicate with you directly.
You can also delete a friend no matter what the friendship status - which completely removes everything relating to that person from your website.

View File

@ -0,0 +1,60 @@
Friendica Message Flow
===
This page documents some of the details of how messages get from one person to another in the Friendica network.
There are multiple paths, using multiple protocols and message formats.
Those attempting to understand these message flows should become familiar with (at the minimum) the [DFRN protocol document](https://github.com/friendica/friendica/blob/stable/spec/dfrn2.pdf) and the message passing elements of the OStatus stack (salmon and Pubsubhubbub).
When a message is posted, all immediate deliveries to all networks are made using include/notifier.php, which chooses how (and to whom) to deliver the message.
This file also invokes the local side of all deliveries including DFRN-notify.
mod/dfrn_notify.php handles the remote side of DFRN-notify.
Local feeds are generated by mod/dfrn_poll.php - which also handles the remote side of DFRN-poll protocol.
Salmon notifications arrive via mod/salmon.php.
Push (pubsubhubbub) feeds arrive via mod/pubsub.php
DFRN-poll feed imports arrive via src/Worker/OnePoll.php as a scheduled task, this implements the local side of the DFRN-poll protocol.
### Scenario #1. Bob posts a public status message
This is a public message with no conversation members so no private transport is used.
There are two paths it can take - as a bbcode path to DFRN clients, and converted to HTML with the server's PuSH (pubsubhubbub) hubs notified.
When a PuSH hub is operational, dfrn-poll clients prefer to receive their information through the PuSH channel.
They will fall back on a daily poll in case the hub has delivery issues (this is quite common when using the default Google reference hub).
If there is no specified hub or hubs, DFRN clients will poll at a configurable (per-contact) rate at up to 5-minute intervals.
Feeds retrieved via dfrn-poll are bbcode and may also contain private conversations which the worker has permissions to see.
### Scenario #2. Jack replies to Bob's public message. Jack is on the Friendica/DFRN network.
Jack uses dfrn-notify to send a direct reply to Bob.
Bob then creates a feed of the conversation and sends it to everybody involved in the conversation using dfrn-notify.
PuSH hubs are notified that new content is available.
The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
### Scenario #3. Mary replies to Bob's public message. Mary is on the Friendica/DFRN network.
Mary uses dfrn-notify to send a direct reply to Bob.
Bob then creates a feed of the conversation and sends it to everybody involved in the conversation (excluding himself, the conversation is now sent to both Jack and Mary).
Messages are sent using dfrn-notify.
Push hubs are also notified that new content is available.
The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
### Scenario #4. William replies to Bob's public message. William is on the OStatus network.
William uses salmon to notify Bob of the reply.
Content is html embedded in salmon magic envelope.
Bob then creates a feed of the conversation and sends it to all Friendica participants involved in the conversation using dfrn-notify (excluding himself, the conversation is sent to both Jack and Mary).
Push hubs are notified that new content is available.
The hub or hubs will then retrieve the latest feed and transmit it to all hub subscribers (which may be on different networks).
### Scenario #5. Bob posts a private message to Mary and Jack.
Message is delivered immediately to Mary and Jack using dfrn_notify.
Public hubs are not notified.
Requeueing is attempted in case of timeout.
Replies follow the same flow as the public replies except that hubs are not notified and message is never made available in the public feed.
The entire conversation is also made available to Mary and Jack (and nobody else) through their dfrn-poll personalised feed.

View File

@ -0,0 +1,92 @@
Migrating to a new server installation
===============
* [Home](help)
## Preparation
### New server
Set up your new server as described [here](Install); follow the installation procedure until you have created a database.
### Heads up to users
Inform your users of an upcoming interruption to your service.
To ensure data consistency, your server needs to be offline during some steps of the migration processes.
You may also find these addons useful for communicating with your users prior to the migration process:
* blackout
* notifyall
### Storage
Check your storage backend with ``bin/console storage list`` in the root folder.
The output should look like this:
````
Sel | Name
-----------------------
| Filesystem
* | Database
````
If you are *not* using ``Database`` run the following commands:
1. ``bin/console storage set Database`` to activate the database backend.
2. ``bin/console storage move`` to initiate moving the stored image files.
This process may take a long time depending on the size of your storage and your server's capacity.
Prior to initiating this process, you may want to check the number of files in the storage with the following command: ``tree -if -I index.html /path/to/storage/``.
### Cleaning up
Before transferring your database, you may want to clean it up; ensure the expiration of database items is set to a reasonable value and activated via the administrator panel.
*Admin* > *Site* > *Performance* > Enable "Clean up database"
After adjusting these settings, the database cleaning up processes will be initiated according to your configured daily cron job.
To review the size of your database, log into MySQL with ``mysql -p`` run the following query:
````
SELECT table_schema AS "Database", SUM(data_length + index_length) / 1024 / 1024 / 1024 AS "Size (GB)" FROM information_schema.TABLES GROUP BY table_schema;
````
You should see an output like this:
````
+--------------------+----------------+
| Database | Size (GB) |
+--------------------+----------------+
| friendica_db | 8.054092407227 |
| [..........] | [...........] |
+--------------------+----------------+
````
Finally, you may also want to optimise your database with the following command: ``mysqloptimize -p friendica-db``
### Going offline
Stop background tasks and put your server in maintenance mode.
1. If you had set up a worker cron job like this ``*/10 * * * * cd /var/www/friendica; /usr/bin/php bin/worker.php`` run ``crontab -e`` and comment out this line. Alternatively if you deploy a worker daemon, disable this instead.
2. Put your server into maintenance mode: ``bin/console maintenance 1 "We are currently upgrading our system and will be back soon."``
## Dumping DB
Export your database: ``mysqldump -p friendica_db > friendica_db-$(date +%Y%m%d).sql`` and possibly compress it.
## Transferring to new server
Transfer your database and a copy of your configuration file ``config/local.config.php.copy`` to your new server installation.
## Restoring your DB
Import your database on your new server: ``mysql -p friendica_db < your-friendica_db-file.sql``
## Completing migration
### Configuration file
Copy your old server's configuration file to ``config/local.config.php``.
Ensure the newly created database credentials are identical to the setting in the configuration file; otherwise update them accordingly.
### Cron job for worker
Set up the required daily cron job.
Run ``crontab -e`` and add the following line according to your system specification
``*/10 * * * * cd /var/www/friendica; /usr/bin/php bin/worker.php``
### DNS settings
Adjust your DNS records by pointing them to your new server.
## Troubleshooting
If you are unable to login to your newly migrated Friendica installation, check your web server's error and access logs and mysql logs for obvious issues.
If still unable to resolve the problem, it's likely an issue with your [installation](Install).
In this case, you may try to an entirely new Friendica installation on your new server, but use a different FQDN and DNS name.
Once you have this up and running, take it offline and purge the database and configuration file and try migrating to this installation.

View File

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

View File

@ -0,0 +1,42 @@
Used Protocols
===============
* [Home](help)
Friendicas DFRN Protocol
---
* [Document with the DFRN specification](spec/dfrn2.pdf)
* [Schema of the contact request process](spec/dfrn2_contact_request.png)
* [Schema of the contact request confirmation](spec/dfrn2_contact_confirmation.png)
* [Description of the message flow](help/Message-Flow)
ActivityStreams
---
Friendica is using ActivityStreams in version 1.0 for its activities and object types.
Additional types are used for non standard activities.
* [Link to the specification](http://activitystrea.ms/head/activity-schema.html)
* [List of used ActivityStreams verbs and object types.](https://github.com/friendica/friendica/wiki/ActivityStreams)
Salmon
---
Salmon is used as a message exchange protocol for replies and mentions.
* [Link to the protocol summary](http://www.salmon-protocol.org/salmon-protocol-summary)
Portable Contacts
---
Portable Contacts is used for friends lists.
* [Link to the specification](https://web.archive.org/web/20160426223008/http://portablecontacts.net/draft-spec.html) (Link to archive.org)
pubsubhubbub
---
pubsubhubbub is used for OStatus.
* [Link to the specification](https://pubsubhubbub.github.io/PubSubHubbub/pubsubhubbub-core-0.4.html)

View File

@ -0,0 +1,15 @@
And that brings the Quick Start to an end.
Here are some more things to help get you started:
**Groups**
- <a href="http://forum.friendi.ca/profile/helpers">Friendica Support</a> - problems? This is the place to ask.
**Documentation**
- <a href="help/Connectors">Connecting to more networks</a>
- <a href="help">Help Index</a>

View File

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

View File

@ -0,0 +1,25 @@
First things first, let's make sure you're logged in to your account.
If you're not already logged in, do so in the frame below.
Once you've logged in (or if you are already logged in), you'll now be looking at your profile page.
This is a bit like 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 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 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>
<iframe src="login" width="950" height="600"></iframe>

View File

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

View File

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

View File

@ -0,0 +1,21 @@
# About the docs of the Friendica Project
**Note**: It is expected that some of the links in these files wont work in the Friendica repository as they are supposed to work on an installed Friendica node.
## User and Admin documentation
Every Friendica node has the _current_ version of the user and admin documentation available in the `/help` location.
The documentation is mainly done in English, but the pages can be translated and some are already to German.
If you want to help expanding the documentation or the translation, please register an account at the [Friendica wiki](https://wiki.friendi.ca) where the [texts are maintained](https://wiki.friendi.ca/docs).
The documentation is periodically merged back from there to the _development_ branch of Friendica.
Images that you use in the documentation should be located in the `img` sub-directory of this directory.
Translations are located in sub-directories named after the language codes, e.g. `de`.
Depending on the selected interface language the different translations will be applied, or the `en` original will be used as a fall-back.
## Developers Documentation
We provide a configuration file for [Doxygen](https://www.doxygen.nl/index.html) in the root of the Friendica repository.
With that you should be able to extract some documentation from the source code.
In addition there are some documentation files about the database structure in `doc`db`.

View File

@ -0,0 +1,23 @@
Remove Account
==============
* [Home](help)
We don't like to see people leave Friendica, but if you need to remove your account, you should visit the URL
http://sitename/removeme
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 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 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

@ -0,0 +1,96 @@
Using SSL with Friendica
=====================================
* [Home](help)
## Disclaimer
**This document has been updated in November 2016.
SSL encryption is relevant for security.
This means that recommended settings change fast.
Keep your setup up to date and do not rely on this document being updated as fast as technologies change!**
## Intro
If you are running your own Friendica site, you may want to use SSL (https) to encrypt communication between servers and between yourself and your server.
There are basically two sorts of SSL certificates: Self-signed certificates and certificates signed by a certificate authority (CA).
Technically, both provide the same valid encryption.
There is a problem with self-signed certificates though:
They are neither installed in browsers nor on other servers.
That is why they provoke warnings about "mistrusted certificates".
This is confusing and disturbing.
For this reason, we recommend to get a certificate signed by a CA.
Normally, you have to pay for them - and they are valid for a limited period of time (e.g. a year or two).
There are ways to get a trusted certificate for free.
## Choose your domain name
Your SSL certificate will be valid for a domain or even only for a subdomain.
Make your final decision about your domain resp. subdomain *before* ordering the certificate.
Once you have it, changing the domain name means getting a new certificate.
### Shared hosts
If your Friendica instance is running on a shared hosting platform, you should first check with your hosting provider.
They have instructions for you on how to do it there.
You can always order a paid certificate with your provider.
They will either install it for you or provide an easy way to upload the certificate and the key via a web interface.
With some providers, you have to send them your certificate.
They need the certificate, the key and the CA's intermediate certificate.
To be sure, send those three files.
**You should send them to your provider via an encrypted channel!**
### Own server
If you run your own server, we recommend to check out the ["Let's Encrypt" initiative](https://letsencrypt.org/).
Not only do they offer free SSL certificates, but also a way to automate their renewal.
You need to install a client software on your server to use it.
Instructions for the official client are [here](https://certbot.eff.org/).
Depending on your needs, you might want to look at the [list of alternative letsencrypt clients](https://letsencrypt.org/docs/client-options/).
## Web server settings
Visit the [Mozilla's wiki](https://wiki.mozilla.org/Security/Server_Side_TLS) for instructions on how to configure a secure webserver.
They provide recommendations for [different web servers](https://mozilla.github.io/server-side-tls/ssl-config-generator/).
## Test your SSL settings
When you are done, visit the test site [SSL Labs](https://www.ssllabs.com/ssltest/) to have them check if you succeeded.
## Configure Friendica
If you can successfully access your Friendica instance through https, there are a number of steps you can take to ensure your users will use SSL to access your instance.
### Web server redirection
This is the simplest way to enforce site-wide secure access.
Every time a user tries to access any Friendica page by any mean (manual address bar entry or link), the web server issues a Permanent Redirect response with the secure protocol prepended to the requested URL.
With Apache, enable the modules rewrite and ssl (with a shared hosting provider, this should be enabled already):
sudo a2enmod rewrite ssl
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
RewriteRule ^(.*)$ https://your.friendica.domain/$1 [R=301,L]
With nginx, configure your server directive this way ([documentation](https://www.nginx.com/blog/creating-nginx-rewrite-rules/)):
server {
listen 80;
server_name your.friendica.domain;
return 301 https://$server_name$request_uri;
}
### SSL Settings
In the Admin Settings, there are three SSL-related settings:
1. **SSL link policy**: this affects how Friendica generates internal links. If your SSL installation was successful, we recommend "Force all links to SSL" just in case your web server configuration can't be altered like described above.
2. **Force SSL**: This forces all external links to HTTPS, which may solve Mixed-Content issues, but not all websites support HTTPS yet. Use at your own risk.
3. **Verify SSL**: Enabling this will prevent Friendica to interact with self-signed SSL sites. We recommend you leave it on as a self-signed SSL certificate can be a vectorfor a man-in-the-middle attack.

View File

@ -0,0 +1,434 @@
# Settings
* [Home](help)
If you are the admin of a Friendica node, you have access to the **Admin Panel** where you can configure your Friendica node.
## 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.
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 developers with a bug or problem, please also mention the version of your node.
The admin panel is separated into subsections accessible from the side bar of the panel.
## Site
This section of the admin panel contains the main configuration of your Friendica node.
It is separated into several sub-section beginning with the basic settings at the top, advancing towards the bottom of the page.
Most configuration options have a help text in the admin panel.
Therefore this document does not yet cover all the options
### Basic Settings
#### Banner/Logo
Set the content for the site banner.
The default logo is the Friendica logo and name.
You may wish to provide HTML/CSS to style and/or position this content, as it may not be themed by default.
#### Language
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 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 `vier` at the moment.
You may also want to set a special theme for mobile interfaces.
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
#### Register policy
With this drop down selector you can set the nodes registration policy.
You can chose between the following modes:
* **open**: Everybody can register a new account and start using it right away.
* **requires approval**: Everybody can register a new account, but the admin has to approve it before it can be used.
* **closed**: No new registrations are possible.
##### Invitation based registry
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 to `true` in the `system` section of 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
You may find a lot of spammers trying to register on your site.
During testing we discovered that since these registrations were automatic, the "Full Name" field was often set to just an account name with no space between first and last name.
If you would like to support people with only one name as their full name, you may change this setting to true.
Default is false.
#### OpenID
By default, OpenID may be used for both registration and logins.
If you do not wish to make OpenID facilities available on your system (at all), set 'no_openid' to true.
Default is false.
#### Multiple Registrations
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 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.
The default is set to 0, which means no limits.
### Policies
#### Global Directory
This configures the URL to update the global directory, and is supplied in the default configuration.
The undocumented part is that if this is not set, the global directory is completely unavailable to the application.
This allows a private community to be completely isolated from the global network.
#### Force Publish
By default, each user can choose on their Settings page whether or not to have their profile published in the site directory.
This setting forces all profiles on this site to be listed in the site directory and there is no option provided to the user to change it.
Default is false.
#### Block Public
Set to true to block public access to all otherwise public personal pages on this site unless you are currently logged in.
This blocks the viewing of profiles, friends, photos, the site directory and search pages to unauthorised persons.
A side effect is that entries from this site will not appear in the global directory.
We recommend specifically disabling that also (setting is described elsewhere on this page).
Note: this is specifically for sites that desire to be "standalone" and do not wish to be connected to any other Friendica sites.
Unauthorised persons will also not be able to request friendship with site members.
Default is false.
Available in version 2.2 or greater.
#### Community pages for Visitors
The community pages show all public postings, separated by their origin being local or the entire network.
With this setting you can select which community pages will be shown to visitors of your Friendica node.
Your local users will always have access to both pages.
**Note**: Several settings, like users hiding their contacts from the public will prevent the postings to show up on the global community page.
#### Allowed Friend Domains
Comma separated list of domains which are allowed to establish friendships with this site.
Wildcards are accepted.
By default, any (valid) domain may establish friendships with this site.
This is useful if you want to setup a closed network for educational groups, cooperatives and similar communities that don't want to communicate with the rest of the network.
#### 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.
By default, any (valid) email address is allowed in registrations.
#### Allow Users to set remote_self
If you enable the `Allow Users to set remote_self` users can select Atom feeds from their contact list being their *remote self* in the contact settings.
Which means that postings by the remote self are automatically reposted by Friendica in their names.
This feature can be used to let the user mirror e.g. blog postings into their Friendica postings.
It is disabled by default, as it causes additional load on the server and may be misused to distribute SPAM.
As admin of the node you can also set this flag directly in the database.
Before doing so, you should be sure you know what you do and have a backup of the database.
#### Explicit Content
If you are running a node with explicit content, you can announce this with this option.
When checked an information flag will be set in the published information about your node.
(Should *Publish Server Information* be enabled.)
Additionally a note will be displayed on the registration page for new users.
### Advanced
#### Proxy Configuration Settings
If your site uses a proxy to connect to the internet, you may use these settings to communicate with the outside world.
The outside world still needs to be able to see your website, or this will not be very useful.
#### Network Timeout
How long to wait on a network communication before timing out.
Value is in seconds.
Default is 60 seconds.
Set to 0 for unlimited (not recommended).
#### 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.
SSL encrypts all the data transmitted between sites (and to your browser).
This allows you to have completely encrypted communications, and also protect your login session from hijacking.
Self-signed certificates can be generated for free, without paying top-dollar for a website SSL certificate.
However these aren't looked upon favourably in the security community because they can be subject to so-called "man-in-the-middle" attacks.
If you wish, you can turn on strict certificate checking.
This will mean you cannot connect (at all) to self-signed SSL sites.
#### Check upstream version
If this option is enabled your Friendica node will check the upstream version once per day from the github repository.
You can select if the stable version or the development version should be checked out.
If there is a new version published, you will get notified in the admin panel summary page.
### Auto Discovered Contact Directory
### Performance
### Worker
This section allows you to configure the background process that is triggered by the `cron` job that was created during the installation.
The process does check the available system resources before creating a new worker for a task.
Because of this, it may happen that the maximum number of worker processes you allow will not be reached.
If your server setup does not allow you to use the `proc_open` function of PHP, please disable it in this section.
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 service.
This will then trigger the execution of the background process.
### Relocate
## Users
This section of the panel let the admin control the users registered on the node.
If you have selected "Requires approval" for the *Register policy* in the general nodes configuration, new registrations will be listed at the top of the page.
There the admin can then approve or disapprove the request.
Below the new registration block the current accounts on the Friendica node are listed.
You can sort the user list by name, email, registration date, date of last login, date of last posting and the account type.
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 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 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.
To simplify this process there is a button at the top of the page to reload all active Addons.
## Themes
The Themes section of the admin panel works similar to the Addons section but let you control the themes on your Friendica node.
Each theme has a dedicated subpage showing the current status, some information about the theme and a screen-shot of the Friendica interface using the theme.
Should the theme offer special settings, admins can set a global default value here.
You can activate and deactivate themes on their dedicated sub-pages thus making them available for the users of the node.
To select a default theme for the Friendica node, see the *Site* section of the admin panel.
## Additional Features
There are several optional features in Friendica like the *dislike* button.
In this section of the admin panel you can select a default setting for your node and eventually fix it, so users cannot change the setting anymore.
## DB Updates
Should the database structure of Friendica change, it will apply the changes automatically.
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 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 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.
Don't panic!
Friendica will not queue messages for all time but will sort out *dead* nodes automatically after a while and remove messages from the queue then.
## Server Blocklist
This page allows to block all communications (inbound and outbound) with a specific domain name.
Each blocked domain entry requires a reason that will be displayed on the [friendica](/friendica) page.
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 complete and only contain nodes from networks Friendica federates directly with.
## Delete Item
Using this page an admin can delete postings and eventually associated discussion threads from their Friendica node.
To do so, they need to know the GUID of the posting.
This can be found on the `/display` page of the posting, it is the last part of the URL displayed in the browsers navigation bar.
You can get to the `/display` page by following the *Link to source*.
## Addon Features
Some of the addons you can install for your Friendica node have settings which have to be set by the admin.
All those addons will be listed in this area of the admin panels side bar with their names.
## Logs
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 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 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.
But due to the volume of information we recommend only enabling this when you are tracking down a specific problem.
**The amount of data can grow the filesize of the logfile quickly**.
You should set up some kind of [log rotation](https://en.wikipedia.org/wiki/Log_rotation) to keep the log file from growing too big.
**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 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:
error_reporting(E_ERROR | E_WARNING | E_PARSE );
ini_set('error_log','php.out');
ini_set('log_errors','1');
ini_set('display_errors', '0');
This will put all PHP errors in the file php.out (which must be writeable by the webserver).
Undeclared variables are occasionally referenced in the program and therefore we do not recommend using `E_NOTICE` or `E_ALL`.
The vast majority of issues reported at these levels are completely harmless.
Please report to the developers any errors you encounter in the logs using the recommended settings above.
They generally indicate issues which need to be resolved.
If you encounter a blank (white) page when using the application, view the PHP logs - as this almost always indicates an error has occurred.
## Diagnostics
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.
With the second tool *check webfinger* you can request information about the thing identified by a webfinger (`someone@example.com`).
# Exceptions to the rule
There are four exceptions to the rule, that all the config will be read from the data base.
These are the data base settings, the admin account settings, the path of PHP and information about an eventual installation of the node in a sub-directory of the (sub)domain.
## DB Settings
With the following settings, you specify the data base server, the username and password for Friendica and the database to use.
'database' => [
'hostname' => 'localhost',
'username' => 'mysqlusername',
'password' => 'mysqlpassword',
'database' => 'mysqldatabasename',
'charset' => 'utf8mb4',
],
## Admin users
You can set one, or more, accounts to be *Admin*.
By default this will be the one account you create during the installation process.
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',
],
## PHP Path
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' => '/usr/bin/php',
],
## Subdirectory configuration
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',
],
## Other exceptions
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

@ -0,0 +1,56 @@
Tags and Mentions
=================
* [Home](help)
Like many other modern social networks, Friendica uses a special notation inside messages to indicate "tags" or contextual links to other entities.
**Mentions**
People are tagged by preceding their name with the @ character.
You can tag **persons who are in your social circle** by adding the "@"-sign in front of the name.
* @mike - indicates a known contact in your social circle whose nickname is "mike"
* @mike_macgirvin - indicates a known contact in your social circle whose full name is "Mike Macgirvin". Note that spaces cannot be used inside tags.
* @mike+151 - this form is used by the drop-down tag completion tool. It indicates the contact whose nickname is mike and whose contact identifier number is 151. The drop-down tool may be used to resolve people with duplicate nicknames.
You can tag a person on a different network or one that is **not in your social circle** by using the following notation:
* @mike@macgirvin.com - This is called a "remote mention" and can only be an email-style locator, not a web URL.
Unless their system blocks unsolicited "mentions", the person tagged will likely receive a "Mention" post/activity or become a direct participant in the conversation in the case of public posts.
Friendica blocks incoming “mentions” from people with no relationship to you.
The exception is an ongoing conversation started from a contact of both you and the 3rd person or a conversation in a forum where you are a member of.
This is a spam prevention measure.
Remote mentions are delivered using the OStatus protocol.
This protocol is used by Friendica and GNU Social and several other systems like Mastodon, but is not currently implemented in Diaspora.
As the OStatus protocol allows this Friendica user can be @-mentioned by users from platforms using this protocol in conversations if the "Enable OStatus support" is activated on the Friendica node.
These @-mentions wont be blocked, even if there is no relationship between the sender and the receiver of the message.
Friendica makes no distinction between people and forums for the purpose of tagging.
You can use @-mentions for forums like for other accounts to tag the forum.
If you want to post something exclusively to a forum (e.g. the support forum) please use the bang-notation instead of the @tag.
So !helpers will be an exclusive posting to the support forum if you are connected with the forum.
If you select a forum from the ACL a !-mention will be added automatically to your posting.
If you sort your contacts into groups, you cannot @-mention these groups.
But you can select the group in the access control when creating a new posting, to allow (or disallow) a certain group of people to see the posting.
See [Groups and Privacy](help/Groups-and-Privacy) for more details about grouping your contacts.
**Topical Tags**
Topical tags are indicated by preceding the tag name with the # character.
This will create a link in the post to a generalised site search for the term provided.
For example, #cars will provide a search link for all posts mentioning 'cars' on your site.
Topical tags are generally a minimum of three characters in length.
Shorter search terms are not likely to yield any search results, although this depends on the database configuration.
The same rules apply as with names that spaces within tags are represented by the underscore character.
It is therefore not possible to create a tag whose target contains an underscore.
Topical tags are also not linked if they are purely numeric, e.g. #1.
If you wish to use a numerica hashtag, please add some descriptive text such as #2012-elections.

View File

@ -0,0 +1,18 @@
# Themes
* [Home](help)
You can run unit tests with [PHPUnit](https://phpunit.de/):
```bash
phpunit
```
Some tests require access to a MySQL database.
You can specify the database credentials in environment variables:
```bash
USER=database_user PASS=database_password DB=database_name phpunit
```
**Warning**: This will empty all the tables! Never use this on a production database.

View File

@ -0,0 +1,44 @@
Comment, sort and delete posts
==============
* [Home](help)
Here you can find an overview of the different ways to comment and sort existing posts. <span style="color: red;">Attention: we've used the <b>"diabook"</b> theme. If you're using another theme, some of the icons may be different.</span>
<img src="doc/img/diabook.png" width="308" height="42" alt="diabook" >
<i>The different icons</i>
<img src="doc/img/post_thumbs_up.png" width="27" height="32" alt="post_thumbs_up.png" align="left" style="padding-bottom: 10px;"> This symbol is used to indicate that you like the post. Click it twice to undo your choice.<p style="clear:both;"></p>
<img src="doc/img/post_thumbs_down.png" width="27" height="32" alt="post_thumbs_down.png" align="left" style="padding-bottom: 10px;"> This symbol is used to indicate that you <b>dislike</b> the post. Click it twice to undo your choice.
<p style="clear:both;"></p>
<img src="doc/img/post_share.png" width="27" height="32" alt="post_share.png" align="left" style="padding-bottom: 10px;"> This symbol is used to share a post. A copy of this post will automatically appear in your status editor and add a link to the original post.
<p style="clear:both;"></p>
<img src="doc/img/post_mark.png" width="27" height="32" alt="post_mark.png" align="left" style="padding-bottom: 10px;"> This symbol is used to mark a post. Marked posts will appear on your network page at the "starred" tab (from "star"). Click it twice to undo your choice.
<p style="clear:both;"></p>
<img src="doc/img/post_tag.png" width="27" height="41" alt="post_tag.png" align="left" style="padding-bottom: 10px;"> This symbol is used to tag a post with a self-chosen keyword. When you click at the word, you'll get a list of all posts with this tag. Attention: you can't delete the tag once you've set one.
<p style="clear:both;"></p>
<img src="doc/img/post_categorize.png" width="27" height="32" alt="post_categorize.png" align="left" style="padding-bottom: 20px;"> This symbol is used to categorize posts. Choose an existing folder or create a new one. You'll find the created folder on your network page under the "saved folders" tab.
<p style="clear:both;"></p>
<img src="doc/img/post_delete.png" width="27" height="32" alt="post_delete.png" align="left"> This symbol is used to delete your own post or to remove a post of another person from your stream.
<P style="clear: both;"></p>
<img src="doc/img/post_choose.png" width="27" height="32" alt="post_choose.png" align="left"> This symbol is used to choose more than one post to delete in a single step. After selecting all posts, go to the end of the page and click "Delete Selected Items".<P style="clear: both;"></p>
**Symbols of other themes**
Darkbubble <img src="doc/img/darkbubble.png" alt="darkbubble.png" style="padding-left: 20px; vertical-align:middle;">
Darkzero <img src="doc/img/darkzero.png" alt="darkzero.png" style="padding-left: 35px; vertical-align:middle;">
<span style="padding-left: 10px; font-style:italic;">(incl. more "zero"-themes, slackr, comix, easterbunny, facepark)</span>
Dispy <img src="doc/img/dispy.png" alt="dispy.png" style="padding-left: 57px; vertical-align:middle;"> <i>(incl. smoothly, testbubble)</i>
Frost Mobile <img src="doc/img/frost.png" alt="frost.png" style="padding-left: 16px; vertical-align:middle;">

View File

@ -0,0 +1,112 @@
<style>
figure { border: 4px #eeeeee solid; }
figure img { padding: 2px; }
figure figcaption { background: #eeeeee; color: #444444; padding: 2px; font-style: italic;}
</style>
Creating posts
===========
* [Home](help)
Here you can find an overview of the different ways to create and edit your post.
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/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 by clicking on "Set title".
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 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, but vary depending on the theme:
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"> 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 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. (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"> 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"> <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>
These icons can change depending on the theme. Some examples:
<table>
<tr>
<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>&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>
</table>
<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 / Permissions**
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.
<figure>
<img src="doc/img/acl_win.png" alt="Permission settings window">
<figcaption>Permission settings window with some contact selected</figcaption>
</figure>
Click on "show" under contact name to hide the post to everyone but selected.
Click on "Visible to everybody" to make the post public again.
If you have defined some groups, you can check "show" for groups also. All contact in that group will see the post.
If you want to hide the post to one contact of a group selected for "show", click "don't show" under contact name.
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)

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

@ -0,0 +1,79 @@
Updating Friendica
===============
* [Home](help)
## 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 the following items from ``path/to/friendica`` to ``path/to/friendica_new``:
* ``config/local.config.php``
* ``proxy/``
The following items only need to be copied if they are located inside your friendica path:
* your storage folder as set in **Admin -> Site -> File Upload -> Storage base path**
* your item cache as set in **Admin -> Site -> Performance -> Path to item cache**
* your temp folder as set in **Admin -> Site -> Advanced -> Temp path**
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.
6. If everything works, just delete the ``path/to/friendica_old`` folder.
To update Addons from an archive, simply delete the ``path/to/friendica/addon`` and replace it with the provided archive.
## Using Git
You can get the latest changes at any time with
cd path/to/friendica
git pull
bin/composer.phar install --no-dev
The addon tree has to be updated separately like so:
cd path/to/friendica/addon
git pull
For both repositories:
The default branch to use is the ``stable`` branch, which is the stable version of Friendica.
It is updated about four times a year on a fixed schedule.
If you want to use and test bleeding edge code please checkout the ``develop`` branch.
The new features and fixes will be merged from ``develop`` into ``stable`` after a release candidate period before each release.
Warning: The ``develop`` branch is unstable, and breaks on average once a month for at most 24 hours until a patch is submitted and merged.
Be sure to pull frequently if you choose the ``develop`` branch.
### Considerations before upgrading Friendica
#### MySQL >= 5.7.4
Starting from MySQL version 5.7.4, the IGNORE keyword in ALTER TABLE statements is ignored.
This prevents automatic table deduplication if a UNIQUE index is added to a Friendica table's structure.
If a DB update fails for you while creating a UNIQUE index, make sure to manually deduplicate the table before trying the update again.
#### Manual deduplication
There are two main ways of doing it, either by manually removing the duplicates or by recreating the table.
Manually removing the duplicates is usually faster if they're not too numerous.
To manually remove the duplicates, you need to know the UNIQUE index columns available in `database.sql`.
```SQL
SELECT GROUP_CONCAT(id), <index columns>, count(*) as count FROM users
GROUP BY <index columns> HAVING count >= 2;
/* delete or merge duplicate from above query */;
```
If there are too many rows to handle manually, you can create a new table with the same structure as the table with duplicates and insert the existing content with INSERT IGNORE.
To recreate the table you need to know the table structure available in `database.sql`.
```SQL
CREATE TABLE <table_name>_new <rest of the CREATE TABLE>;
INSERT IGNORE INTO <table_name>_new SELECT * FROM <table_name>;
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.

View File

@ -0,0 +1,58 @@
Vagrant for Friendica Developers
===================
* [Home](help)
Getting started
---------------
[Vagrant](https://www.vagrantup.com/) is a virtualization solution for developers.
No need to setup up a webserver, database etc. before actually starting.
Vagrant creates a virtual machine for you that you can just run inside VirtualBox and start to work directly on Friendica.
It brings an Ubuntu Xenial (16.04) with PHP 7.0 and MySQL 5.7.16
What you need to do:
1. Install VirtualBox and vagrant.
Please use an up-to-date vagrant version from https://www.vagrantup.com/downloads.html.
2. Git clone your Friendica repository.
Inside, you'll find a "Vagrantfile" and some scripts in the utils folder.
3. Run "vagrant up" from inside the friendica clone:
$> vagrant up
Be patient: When it runs for the first time, it downloads an Ubuntu Server image.
4. Run "vagrant ssh" to log into the virtual machine to log in to the VM:
$> vagrant ssh
5. Open you test installation in a browser.
Go to 192.168.22.10.
The mysql database is called "friendica", the mysql user and password both are "friendica".
6. Work on Friendica's code in your git clone on your machine (not in the VM).
Your local working directory is set up as a shared directory with the VM (/vagrant).
7. Check the changes in your browser in the VM.
Debug via the "vagrant ssh" login.
Find the Friendica log file /vagrant/logfile.out.
8. Commit and push your changes directly back to Github.
If you want to stop vagrant after finishing your work, run the following command
$> vagrant halt
in the development directory.
This will not delete the virtual machine.
9. To ultimately delete the virtual machine run
$> vagrant destroy
$> rm /vagrant/config/local.config.php
to make sure that you can start from scratch with another "vagrant up".
The vagrant Friendica instance contains a test database.
You will then have the following accounts to login:
* admin, password admin
* 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 connected. friendica4 and friendica5 are connected.
For further documentation of vagrant, please see [the vagrant*docs*](https://docs.vagrantup.com/v2/).

View File

@ -0,0 +1,77 @@
# Using the APIs
<!-- markdownlint-disable MD010 MD013 MD024 -->
* [Home](help)
Friendica offers multiple API endpoints to interface with third-party applications:
- [Twitter](help/API-Twitter)
- [Mastodon](help/API-Mastodon)
- [Friendica-specific](help/API-Friendica)
- [GNU Social](help/API-GNU-Social)
## Usage
### HTTP Method
API endpoints can restrict the HTTP method used to request them.
Using an invalid method results in HTTP error 405 "Method Not Allowed".
### Authentication
Friendica supports basic HTTP Auth and OAuth 1 to authenticate the user to the APIs.
OAuth settings can be added by the user in web UI under [/settings/oauth/](/settings/oauth/).
### Errors
When an error occurs in API call, an HTTP error code is returned, with an error message
Usually:
* 400 Bad Request: if parameters are missing or items can't be found
* 403 Forbidden: if the authenticated user is missing
* 405 Method Not Allowed: if API was called with an invalid method, eg. GET when API require POST
* 501 Not Implemented: if the requested API doesn't exist
* 500 Internal Server Error: on other error conditions
Error body is
json:
```json
{
"error": "Specific error message",
"request": "API path requested",
"code": "HTTP error code"
}
```
xml:
```xml
<status>
<error>Specific error message</error>
<request>API path requested</request>
<code>HTTP error code</code>
</status>
```
## Usage Examples
### BASH / cURL
```bash
/usr/bin/curl -u USER:PASS https://YOUR.FRIENDICA.TLD/api/statuses/update.xml -d source="some source id" -d status="the status you want to post"
```
### Python
The [RSStoFriendika](https://github.com/pafcu/RSStoFriendika) code can be used as an example of how to use the API with python.
The lines for posting are located at [line 21](https://github.com/pafcu/RSStoFriendika/blob/master/RSStoFriendika.py#L21) and following.
def tweet(server, message, group_allow=None):
url = server + '/api/statuses/update'
urllib2.urlopen(url, urllib.urlencode({'status': message,'group_allow[]':group_allow}, doseq=True))
There is also a [module for python 3](https://bitbucket.org/tobiasd/python-friendica) for using the API.

View File

@ -0,0 +1,203 @@
Autoloader with Composer
==========
* [Home](help)
* [Developer Intro](help/Developers-Intro)
Friendica uses [Composer](https://getcomposer.org) to manage dependencies libraries and the class autoloader both for libraries and namespaced Friendica classes.
It's a command-line tool that downloads required libraries into the `vendor` folder and makes any namespaced class in `src` available through the whole application through `boot.php`.
* [Using Composer](help/Composer)
## A quick introduction to class autoloading
The autoloader dynamically includes the file defining a class when it is first referenced, either by instantiating an object or simply making sure that it is available, without the need to explicitly use "require_once".
Once it is set up you don't have to directly use it, you can directly use any class that is covered by the autoloader (currently `vendor` and `src`)
Under the hood, Composer registers a callback with [`spl_autoload_register()`](http://php.net/manual/en/function.spl-autoload-register.php) that receives a class name as an argument and includes the corresponding class definition file.
For more info about PHP autoloading, please refer to the [official PHP documentation](http://php.net/manual/en/language.oop5.autoload.php).
### Example
Let's say you have a PHP file in `src/` that define a very useful class:
```php
// src/ItemsManager.php
<?php
namespace Friendica;
class ItemsManager {
public function getAll() { ... }
public function getByID($id) { ... }
}
```
The class `ItemsManager` has been declared in the `Friendica` namespace.
Namespaces are useful to keep classes separated and avoid names conflicts (could be that a library you want to use also defines a class named `ItemsManager`, but as long as it is in another namespace, you don't have any problem)
Let's say now that you need to load some items in a view, maybe in a fictional `mod/network.php`.
In order for the Composer autoloader to work, it must first be included.
In Friendica this is already done at the top of `boot.php`, with `require_once('vendor/autoload.php');`.
The code will be something like:
```php
// mod/network.php
<?php
use Friendica\App;
function network_content(App $a) {
$itemsmanager = new \Friendica\ItemsManager();
$items = $itemsmanager->getAll();
// pass $items to template
// return result
}
```
That's a quite simple example, but look: no `require()`!
If you need to use a class, you can simply use it and you don't need to do anything else.
Going further: now we have a bunch of `*Manager` classes that cause some code duplication.
Let's define a `BaseManager` class, where we move all common code between all managers:
```php
// src/BaseManager.php
<?php
namespace Friendica;
class BaseManager {
public function thatFunctionEveryManagerUses() { ... }
}
```
and then let's change the ItemsManager class to use this code
```php
// src/ItemsManager.php
<?php
namespace Friendica;
class ItemsManager extends BaseManager {
public function getAll() { ... }
public function getByID($id) { ... }
}
```
Even though we didn't explicitly include the `src/BaseManager.php` file, the autoloader will when this class is first defined, because it is referenced as a parent class.
It works with the "BaseManager" example here and it works when we need to call static methods:
```php
// src/Dfrn.php
<?php
namespace Friendica;
class Dfrn {
public static function mail($item, $owner) { ... }
}
```
```php
// mod/mail.php
<?php
mail_post($a){
...
Friendica\Protocol\DFRN::mail($item, $owner);
...
}
```
If your code is in same namespace as the class you need, you don't need to prepend it:
```php
// include/delivery.php
<?php
namespace Friendica;
use Friendica\Protocol\DFRN;
// this is the same content of current include/delivery.php,
// but has been declared to be in "Friendica" namespace
[...]
switch($contact['network']) {
case NETWORK_DFRN:
if ($mail) {
$item['body'] = ...
$atom = DFRN::mail($item, $owner);
} elseif ($fsuggest) {
$atom = DFRN::fsuggest($item, $owner);
q("DELETE FROM `fsuggest` WHERE `id` = %d LIMIT 1", intval($item['id']));
} elseif ($relocate)
$atom = DFRN::relocate($owner, $uid);
[...]
```
This is the current code of `include/delivery.php`, and since the code is declared to be in the "Friendica" namespace, you don't need to write it when you need to use the "Dfrn" class.
But if you want to use classes from another library, you need to use the full namespace, e.g.
```php
// src/Diaspora.php
<?php
namespace Friendica;
class Diaspora {
public function md2bbcode() {
$html = \Michelf\MarkdownExtra::defaultTransform($text);
}
}
```
if you use that class in many places of the code and you don't want to write the full path to the class every time, you can use the "use" PHP keyword
```php
// src/Diaspora.php
<?php
namespace Friendica;
use \Michelf\MarkdownExtra;
class Diaspora {
public function md2bbcode() {
$html = MarkdownExtra::defaultTransform($text);
}
}
```
Note that namespaces are like paths in filesystem, separated by "\", with the first "\" being the global scope.
You can go deeper if you want to, like:
```
// src/Network/Dfrn.php
<?php
namespace Friendica\Network;
class Dfrn {
}
```
Please note that the location of the file defining the class must be placed in the appropriate sub-folders of `src` if the namespace isn't plain `Friendica`.
or
```
// src/Dba/Mysql
<?php
namespace Friendica\Dba;
class Mysql {
}
```
So you can think of namespaces as folders in a Unix file system, with global scope as the root ("\").
## Related
* [Using Composer](help/Composer)
* [How To Move Classes to `src`](help/Developer-How-To-Move-Classes-to-src)

View File

@ -0,0 +1,53 @@
Database Tables
===============
* [Home](help)
| Table | Description |
|------------------------------------------------------|--------------------------------------------------|
| [addon](help/database/db_addon) | registered addons |
| [attach](help/database/db_attach) | file attachments |
| [auth_codes](help/database/db_auth_codes) | OAuth usage |
| [cache](help/database/db_cache) | OEmbed cache |
| [challenge](help/database/db_challenge) | |
| [clients](help/database/db_clients) | OAuth usage |
| [config](help/database/db_config) | main configuration storage |
| [contact](help/database/db_contact) | contact table |
| [conv](help/database/db_conv) | private messages |
| [conversation](help/database/db_conversation) | Raw data and structure information for messages |
| [event](help/database/db_event) | Events |
| [fcontact](help/database/db_fcontact) | friend suggestion stuff |
| [fsuggest](help/database/db_fsuggest) | friend suggestion stuff |
| [group](help/database/db_group) | privacy groups, group info |
| [group_member](help/database/db_group_member) | privacy groups, member info |
| [gserver](help/database/db_gserver) | |
| [hook](help/database/db_hook) | addon hook registry |
| [intro](help/database/db_intro) | |
| [item](help/database/db_item) | all posts |
| [locks](help/database/db_locks) | |
| [mail](help/database/db_mail) | private messages |
| [mailacct](help/database/db_mailacct) | |
| [manage](help/database/db_manage) | table of accounts that can "su" each other |
| [notify](help/database/db_notify) | notifications |
| [notify-threads](help/database/db_notify-threads) | |
| [oembed](help/database/db_oembed) | cache for OEmbed queries |
| [parsed_url](help/database/db_parsed_url) | cache for "parse_url" queries |
| [participation](help/database/db_participation) | Storage for participation messages from Diaspora |
| [pconfig](help/database/db_pconfig) | personal (per user) configuration storage |
| [photo](help/database/db_photo) | photo storage |
| [poll](help/database/db_poll) | data for polls |
| [poll_result](help/database/db_poll_result) | data for poll elements |
| [profile](help/database/db_profile) | user profiles data |
| [profile_check](help/database/db_profile_check) | DFRN remote auth use |
| [push_subscriber](help/database/db_push_subscriber) | |
| [queue](help/database/db_queue) | |
| [register](help/database/db_register) | registrations requiring admin approval |
| [search](help/database/db_search) | |
| [session](help/database/db_session) | web session storage |
| [sign](help/database/db_sign) | Diaspora signatures |
| [term](help/database/db_term) | item taxonomy (categories, tags, etc.) table |
| [thread](help/database/db_thread) | |
| [tokens](help/database/db_tokens) | OAuth usage |
| [user](help/database/db_user) | local user table |
| [userd](help/database/db_userd) | |
| [workerqueue](help/database/db_workerqueue) | |

View File

@ -0,0 +1,17 @@
Table addon
===========
| Field | Description | Type | Null | Key | Default | Extra |
| ------------- | --------------------------------------------- | ---------- | ---- | --- | ------- | --------------- |
| id | | int(11) | NO | PRI | NULL | auto_increment |
| name | addon base (file)name | char(255) | NO | | | |
| version | currently unused | char(255) | NO | | | |
| installed | currently always 1 | tinyint(1) | NO | | 0 | |
| hidden | currently unused | tinyint(1) | NO | | 0 | |
| timestamp | file timestamp to check for reloads | bigint(20) | NO | | 0 | |
| plugin_admin | 1 = has admin config, 0 = has no admin config | tinyint(1) | NO | | 0 | |
Notes:
These are addons which have been enabled by the site administrator on the addon page
Return to [database documentation](help/database)

View File

@ -0,0 +1,22 @@
Table attach
============
| Field | Description | Type | Null | Key | Default | Extra |
| ---------- | ------------------------------------------------------| ------------ | ---- | --- | ------------------- | --------------- |
| id | generated index | int(11) | NO | PRI | NULL | auto_increment |
| uid | user_id of owner | int(11) | NO | | 0 | |
| hash | hash | varchar(64) | NO | | | |
| filename | filename of original | varchar(255) | NO | | | |
| filetype | mimetype | varchar(64) | NO | | | |
| filesize | size in bytes | int(11) | NO | | 0 | |
| data | file data | longblob | NO | | NULL | |
| created | creation time | datetime | NO | | 0001-01-01 00:00:00 | |
| edited | last edit time | datetime | NO | | 0001-01-01 00:00:00 | |
| allow_cid | Access Control - list of allowed contact.id '<19><78> | mediumtext | NO | | NULL | |
| allow_gid | Access Control - list of allowed groups | mediumtext | NO | | NULL | |
| deny_cid | Access Control - list of denied contact.id | mediumtext | NO | | NULL | |
| deny_gid | Access Control - list of denied groups | mediumtext | NO | | NULL | |
Notes: Permissions are surrounded by angle chars. e.g. <4>
Return to [database documentation](help/database)

View File

@ -0,0 +1,14 @@
Table auth_codes
================
OAuth2 authorisation register - currently implemented but unused
| Field | Description | Type | Null | Key | Default | Extra |
| ------------- | ----------- | ------------ | ---- | --- | ------- | ----- |
| id | | varchar(40) | NO | PRI | NULL | |
| client_id | | varchar(20) | NO | | | |
| redirect_uri | | varchar(200) | NO | | | |
| expires | | int(11) | NO | | 0 | |
| scope | | varchar(250) | NO | | | |
Return to [database documentation](help/database)

View File

@ -0,0 +1,13 @@
Table cache
===========
Stores temporary data
| Field | Description | Type | Null | Key | Default | Extra |
| ------------ | ---------------------------------- | ------------ | ---- | --- | ------------------- | ----- |
| k | cache key | varchar(255) | NO | PRI | NULL | |
| v | cached serialized value | text | NO | | NULL | |
| expires | datetime of cache expiration | datetime | NO | MUL | 0001-01-01 00:00:00 | |
| updated | datetime of cache insertion | datetime | NO | MUL | 0001-01-01 00:00:00 | |
Return to [database documentation](help/database)

View File

@ -0,0 +1,13 @@
Table challenge
===============
| Field | Description | Type | Null | Key | Default | Extra |
|-------------|------------------|------------------|------|-----|---------|----------------|
| id | sequential ID | int(10) unsigned | NO | PRI | NULL | auto_increment |
| challenge | | varchar(255) | NO | | | |
| dfrn-id | | varchar(255) | NO | | | |
| expire | | int(11) | NO | | 0 | |
| type | | varchar(255) | NO | | | |
| last_update | | varchar(255) | NO | | | |
Return to [database documentation](help/database)

View File

@ -0,0 +1,13 @@
Table clients
=============
| Field | Description | Type | Null | Key | Default | Extra |
| ------------- | ----------- | ------------ | ---- | --- | ------- | ----- |
| client_id | | varchar(20) | NO | PRI | NULL | |
| pw | | varchar(20) | NO | | | |
| redirect_uri | | varchar(200) | NO | | | |
| name | | text | YES | | NULL | |
| icon | | text | YES | | NULL | |
| uid | | int(11) | NO | | 0 | |
Return to [database documentation](help/database)

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