Merge branch '2023.03-rc' into stable

This commit is contained in:
Tobias Diekershoff 2023-04-23 15:12:51 +02:00
commit 4eec2804de
1438 changed files with 141572 additions and 118170 deletions

View file

@ -1,7 +1,7 @@
codecov:
branch: develop
ci:
- drone.friendi.ca
- ci.friendi.ca
coverage:
precision: 2

View file

@ -6,9 +6,27 @@ root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespaces = true
indent_style = tab
trim_trailing_whitespace = true
insert_final_newline = true
quote_type = single
max_line_length = off
[*.js]
quote_type = double
ij_javascript_use_double_quotes = true
[*.yml]
indent_style = space
indent_size = 2
[*.xml]
indent_style = space
indent_size = 2
[*.json]
indent_style = space
indent_size = 2
[composer.json]
indent_style = tab

View file

@ -13,7 +13,7 @@ assignees: ''
### Describe the feature you'd like
<!-- A clear and concise description of waht you want to happen. -->
<!-- A clear and concise description of what you want to happen. -->
### Describe alternatives you've considered

View file

@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
host = https://api.transifex.com
[friendica.messagespo]
[o:Friendica:p:friendica:r:messagespo]
file_filter = view/lang/<lang>/messages.po
source_file = view/lang/C/messages.po
source_lang = en

View file

@ -71,20 +71,19 @@ pipeline:
else
phpunit --configuration tests/phpunit.xml;
fi
codecov:
image: plugins/codecov
image: friendicaci/codecov
when:
matrix:
PHP_MAJOR_VERSION: 7.4
PHP_VERSION: 7.4.18
PHP_VERSION: 7.4.33
repo:
- friendica/friendica
settings:
token:
from_secret: codecov-token
files:
- clover.xml
commands:
- codecov -R '.' -Z -f 'clover.xml'
secrets:
- source: codecov-token
target: codecov_token
services:
mariadb:

143
CHANGELOG
View file

@ -1,3 +1,72 @@
Version 2023.04 (2023-04-23)
Friendica Core
Updates to the translations AR, BG, CA, CS, DA, DE, EO, ES, ET, FR, GD, HU, IS, IT, JA, NL, PL, RU, SV
Updates to the themes (frio, vier) [damianwajer, haheute, MrPetovan, xundeenergie]
Updates to the documentation [haheute, HankG, MarekBenjamin, MrPetovan]
General code cleanup [annando, MarekBenjamin, MrPetovan, nupplaphil]
Fixed display of blocked contacts [annando]
Fixed usage of environment variables [nupplaphil]
Fixed paging on the Mastodon compatible API endpoints for timelines and statuses [HankG]
Fixed updating of attached links via the API [HankG]
Fixed federation issues with Diaspora*, gup.pe, Hubzilla and Peertube servers [annando]
Fixed a bug with PubSubHubBub subscription [annando]
Fixed a XSS vulnerability in Justified-Gallery JavaScript dependency (frio theme) [MrPetovan]
Improved the translate ability of activities (singular/plural forms) [nupplaphil]
Improved activity update handling [xundeenergie]
Improved BBCode + Markdown parsing [annando]
Improved known Fediverse statistics [annando]
Improved automatic table optimization [HankG]
Improved the performance of local JsonLD requests [MrPetovan]
Improved the performance of local requests [annando]
Improved the performance of the delivery of postings [annando]
Improved the performance of homepage rel-me checks [annando]
Improved supported characters for passwords [MrPetovan]
Improved the ARIA support [MrPetovan]
Improved PHP 8.2 compatibility [MrPetovan]
Added emoticon reaction handling [annando]
Added drag and drop image upload in frio themes [xundeenergie]
Added scope change for comments to the API [annando]
Added posting visibility to the API [HankG]
Added delivery information to the Mastodon compatible API [HankG]
Added notification summary option to the Mastodon compatible API [HankG]
Added option to display activities as emoticons [annando]
Added trending API updates [HankG]
Added blocked/ignored filters to the Mastodon compatible API [HankG]
Added ActivityPub C2S postings to the API [annando]
Added dislike information for postings to the Mastodon compatible API [HankG, mkljczk]
Added the possibility to deletion blocked servers [annando]
Removed the GNUsocial import [annando]
Friendica Addons
Updates to the translations AR, CS, DE, ES, HU, IS, IT, NL, PL, RU, SV
mailstream
Various modernization [mexon]
Include post media [mexon]
securemail
Updated the phpseclib dependency [MrPetovan]
twitter
Improve remote-self handling [annando]
impressum
Avoide obfuscation on un-set email addresses [MrPestovan]
notifyall
Fixed a bug selecting the email addresses [nupplaphil]
tumblr
Fixed a bug addressing the tumblr blog via UUID [annando]
Added support for NPF [annando]
Improved the tumblr blog URI detection [annando]
Improved the handling of multible images [annando]
marked as UNSUPPORTED addons
blockem, tictactoe, twitter
Closed Issues
7037, 10974, 11513, 11535, 11825, 11986, 12489, 12490, 12507, 12515,
12522, 12537, 12545, 12550, 12552, 12559, 12582, 12601, 12602, 12603,
12607, 12608, 12616, 12617, 12620, 12624, 12625, 12629, 12654, 12658,
12661, 12665, 12672, 12677, 12682, 12705, 12713, 12721, 12753, 12764,
12779, 12792, 12793, 12803, 12809, 12828, 12835, 12842, 12846, 12847,
12858, 12859, 12871, 12888, 12924, 12944, 12970, 12974, 12983, 12993,
12995, 13002, 19996
Version 2023.01 (2023-01-15)
Friendica Core
Improved the global server updating if domains are blocked [MrPetovan]
@ -30,7 +99,7 @@ Version 2022.12 (2022-12-20)
Added a moderation section to the admin panel [annando]
Added an option to make the calendar public [matthiasmoritz]
Fixed a bug in the federation with Diaspora* [annando]
Fixec a problem in the federation with GoTo Social and Owncast [annando]
Fixed a problem in the federation with GoTo Social and Owncast [annando]
Deprecated old themes (duepuntozero, quattro, smoothy)
NOTE: The Apache2 rewrite rule in the .htaccess-dist has been changed.
@ -718,13 +787,13 @@ Version 2020.07 (2020-07-12)
blockbot:
The list of accepted user agents was enhanced [annando]
Diaspora*:
Enhanced conntector settings [MrPetovan]
Enhanced connector settings [MrPetovan]
PHP Mailer SMTP:
Updated phpmailer version [dependabot]
showmore_dyn:
New addon to collapse long post depending on their actual height [wiwie]
twitter:
Enhaceed the handling of mobile twitter URLs [annando]
Enhanced the handling of mobile twitter URLs [annando]
Enhanced the handling of quoted tweets [MrPetovan]
added HTML error code handling [MrPetovan]
various:
@ -962,7 +1031,7 @@ Version 2019.09 (2019-09-29)
Version 2019.06 (2019-06-23)
Friendica Core:
Update to the tranlation (CS, DE, EN-GB, EN-US, ET, FR, IT, PL, PT-BR, SV) [translation teams]
Update to the translation (CS, DE, EN-GB, EN-US, ET, FR, IT, PL, PT-BR, SV) [translation teams]
Update to the documentation [nupplaphil, realkinetix, MrPetovan]
Update to the themes (frio, vier) [BinkaDroid, MrPetovan, tobiasd]
Enhancements to the API [annando, MrPetovan]
@ -982,7 +1051,7 @@ Version 2019.06 (2019-06-23)
Fixed an issue with the File to Folder feature [MrPetovan]
Fixed an issue with the legacy storage engine [fabrixxm]
Fixed an issue with the theme and addon path items [MrPetovan]
Fixed an issue occuring when the BasePath was not set [tobiasd]
Fixed an issue occurring when the BasePath was not set [tobiasd]
Fixed an issue with additionally opened Sessions [MrPetovan]
Fixed an issue with legacy loglevel mapping [nupplaphil]
Fixed contact suggestions [annando]
@ -1008,7 +1077,7 @@ Version 2019.06 (2019-06-23)
Remove support for defunct F-Droid Friendica app [MrPetovan]
Friendica Addons:
Update to the tranlation (ET, SV, ZH_CN) [translation teams]
Update to the translation (ET, SV, ZH_CN) [translation teams]
botdetection:
Added a new addon for preventing access by bots [nupplaphil, annando]
buffer:
@ -1046,7 +1115,7 @@ Version 2019.03 (2019-03-22)
Update to the themes (duepuntozero, frio, smoothy, quattro, vier) [lxiter, MrPetovan, nupplaphil, rabuzarus, tobiasd]
Enhancements to the API [jasonscheng]
Enhancements to the Vagrant development VM [JeroenED]
Enhancements to the storage of gender, sexual preferences and maritial status [JeroenED]
Enhancements to the storage of gender, sexual preferences and marital status [JeroenED]
Enhancements to the wording of notifications [MrPetovan]
Enhancements to the display of contacts in the profile [MrPetovan]
Enhancements to the handling of local links [lxiter]
@ -1075,7 +1144,7 @@ Version 2019.03 (2019-03-22)
Fixed an issue with sending out notification mails to the admin [nupplaphil]
Fixed an the issue, that the API was ignoring the globalsilence setting [nupplaphil]
Fixed issues with the autolinker of URLs in postings [MrPetovan]
Fixed an issue resulting in multible emails after successful updates of the database [nupplaphil]
Fixed an issue resulting in multiple emails after successful updates of the database [nupplaphil]
Fixed a timeout issue during detection process of the remote profile [annando]
Fixed an issue with postings from blocked servers [annando, MrPetovan]
Fixed an issue with the paging of stored folders [MrPetovan]
@ -1107,7 +1176,7 @@ Version 2019.03 (2019-03-22)
forumdirectory:
Fixed a theming issue with frio [rabuzarus]
js_upload:
Fixed a missing extionsion index [nupplaphil]
Fixed a missing extension index [nupplaphil]
mailstream:
Fixed a curl issue [MrPetovan]
piwik:
@ -1327,7 +1396,7 @@ Version 2018.09 (2018-09-23)
added addons:
mastodoncustomemojis [MrPetovan]
deprecated addons:
notimeline, retriver, remote_permissions, widgets
notimeline, retriever, remote_permissions, widgets
Directory:
Enhancements of the health summary [andyhee]
@ -1353,7 +1422,7 @@ Version 2018.05 (2018-06-01)
Enhancements to the relay system [annando]
Enhancements to the handling of URL that contain unicode characters [annando]
Enhancements to the Vagrant VM configuration [fabrixxm, tobiasd]
Enhancementa to the Babel module [MrPetovan]
Enhancements to the Babel module [MrPetovan]
Enhancements to the display of the [code] elements [MrPetovan]
Enhancements to the federation (OStatus, diaspora) [annando]
Enhancements to the PHP7.2 compatibility [Alkarex, MrPetovan, Quix0r]
@ -1382,7 +1451,7 @@ Version 2018.05 (2018-06-01)
Fixed a bug that made edited mentions and hashtags plaintext [annando]
Fixed a bug that caused the /display page to receive constandly new updates [annando]
Fixed wrong version of a dependency preventing the usage of PHP 5.6 [MrPetovan]
Fixed a bug in OpenID authentification [Quix0r]
Fixed a bug in OpenID authentication [Quix0r]
Fixed a bug in the item deletion [annando]
Fixed a bug that prevented public comments from being distributed [annando]
Fixed a bug that caused empty profile pictures for public contacts [annando]
@ -1481,7 +1550,7 @@ Version 3.6 (2018-03-23)
Enhancements to the probing of pump.io profiles [annando]
Enhancements to the handling of BBCode tags [MrPetovan]
Enhancements to the OEmbed handling [MrPetovan]
Fixed a bug that triggered the display of activities on the cummunity page [annando]
Fixed a bug that triggered the display of activities on the community page [annando]
Fixed a bug with personal notes [annando]
Fixed a display issue of long postings when using the showmore option [annando]
Fixed a bug that caused Twidere to crash on reload [annando]
@ -1489,7 +1558,7 @@ Version 3.6 (2018-03-23)
Fixed a bug in URL completion for feed fragments [annando]
Fixed a bug in the notification system about new registrations [annando]
Fixed the display of dislikes [annando]
Fixed the display of orphans childs in threads [MrPetovan]
Fixed the display of orphan children in threads [MrPetovan]
Fixed some SQL problems [annando]
Fixed the CLI config script [tobiasd]
Fixed the forum selection on the network display [annando]
@ -1543,7 +1612,7 @@ Version 3.6 (2018-03-23)
all bridges don't relay postings anymore that are posted to a public forum [annando]
DAV addon marked unsupported [tobiasd]
communityhome addon marked unsupported [MrPetovan]
yourls addon makrked unsupported [MrPetovan]
yourls addon marked unsupported [MrPetovan]
Current Weather: fixing a problem with the weathermap link [zeroadam]
NSFW added config examples, reworked the description, now ignores the CW from Mastodon [andyhee, annando, rebeka-catalina]
Twitter support 280 chars limit [annando]
@ -1738,7 +1807,7 @@ Version 3.5.1 (2017-03-12)
Improvements to the documentation [Hypolite, tobiasd, rabuzarus, beardyunixer, eelcomaljaars]
Improvements to the BBCode / Markdown conversation [Hypolite]
Improvements to the OStatus protocol implementation [annando]
Improvements to the installation wizzard [tobiasd]
Improvements to the installation wizard [tobiasd]
Improvements to the Diaspora connectivity [annando, Hypolite]
Work on PHP7 compatibility [ddorian1]
Code cleanup [Hypolite, Quix0r]
@ -1800,11 +1869,11 @@ Version 3.5 (2016-09-13)
Improvements on the themes (quattro, vier, frost) [rabuzarus, fabrixxm, stieben, annando, Quix0r, tobiasd]
Improvements to the ACL dialog [fabrixxm, rabuzarus]
Improvements to the database structure and optimization of queries [annando]
Improvements to the UI (contacts, hotkeys, remember me, ARIA, code hightlighting) [rabuzarus, annando, tobiasd]
Improvements to the UI (contacts, hotkeys, remember me, ARIA, code highlighting) [rabuzarus, annando, tobiasd]
Improvements to the background process (poller, worker) [annando]
Improvements to the admin panel [tobiasd, annando, fabrixxm]
Improvements to the performance [annando]
Improvements to the installation wizzard (language selection, RINO version, check required PHP modules, default theme is now vier) [tobiasd]
Improvements to the installation wizard (language selection, RINO version, check required PHP modules, default theme is now vier) [tobiasd]
Improvements to the relocation of nodes and accounts [annando]
Improvements to the DDoS detection [annando]
Improvements to the calendar/events module [annando, rabuzarus]
@ -1829,7 +1898,7 @@ Version 3.5 (2016-09-13)
GNU Social Connector [annando]
LDAP [Olivier Mehani]
smileybutton [rabuzarus]
retriver [mexon]
retriever [mexon]
mailstream [mexon]
forumdirectory [tobiasd]
NEW notifyall (port from Hubzilla) [rabuzarus, tobiasd]
@ -1884,7 +1953,7 @@ Version 3.4.3 (2015-12-22)
'Reload active themes' in theme admin page (fabrixxm)
Install routine checks for ImageMagick and GIF support (fabrixxm)
Install routine checks for availability of "mcrypt_create_iv()" function, needed for RINO2 (fabrixxm)
Only suported themes are shown in admin page (annando)
Only supported themes are shown in admin page (annando)
Optimized SQL queries (annando)
System perform an optimize pass on tables in cron, with maximum table size and minimum fragmentation level settings (annando)
New access keys in profile and contact pages (rabuzarus, annando)
@ -1899,9 +1968,9 @@ Version 3.4.3 (2015-12-22)
New hook 'template_vars' (fabrixxm)
$baseurl variable is passed to all templates by default (fabrixxm)
OStatus delivery code is moved in new function (annando)
Doxygen config file and initial documetation of code (rabuzarus)
Doxygen config file and initial documentation of code (rabuzarus)
Full rewrite of util/php2po.php (fabrixxm)
Bugfixs:
Bugfixes:
Remote self works again (annando)
Fix feeds mistakenly recognized as OStatus (issue #1914) (annando)
Report invalid feeds to user (issue #1913) (annando)
@ -1916,8 +1985,8 @@ Version 3.4.3 (2015-12-22)
Fix rapid repeated requests to GNUSocial instance (issue #2038) (annando)
Fix install routine css when mod_rewrite doesn't works (issue #2071) (fabrixxm)
Fix code to be compliant with minimum required PHP version (issue #2066) (fabrixxm, rabuzarus)
Fix feedback after succesfull registration (issue #2060) (annando)
Fix mention completition popup with TinyMCE (issue #1920) (fabrixxm)
Fix feedback after successful registration (issue #2060) (annando)
Fix mention completion popup with TinyMCE (issue #1920) (fabrixxm)
Fix photo cache and proxy when installed in subfolder (ddorian1)
Fix bbcode conversion of the about text for the profile (issue #1607) (annando)
@ -1927,7 +1996,7 @@ Version 3.4.2 (2015-09-29)
Updates to the documentation (tobiasd, silke, annando)
Updates to the translations (tobiasd & translation teams)
Updates to themes frost-mobile, vier, duepuntozero, quattro (annando, tobiasd)
Enancements of the communications via OStatus and Diaspora protocols (annando)
Enhancements of the communications via OStatus and Diaspora protocols (annando)
Option to automatically follow OStatus contacts was moved from addon to the core (annando)
Add tool to import OStatus contacts from an old account (annando)
SALMON slaps with OStatus were reworked (annando)
@ -1944,7 +2013,7 @@ Version 3.4.2 (2015-09-29)
The global directory is queried in the background to update local DB and improve similar searches in the future. (annando)
By communication over the Diaspora protocol, red#matrix sources are now correctly identified, hubzilla is detected (annando)
Adopt limitation of usage of "-" in username to avoid conflicts with GNU Social and Diaspora (annando)
The [url] tag now also suppots ftp, mailto, gopher links (annando)
The [url] tag now also supports ftp, mailto, gopher links (annando)
An "inspect queue" module was added to the admin panel (tobiasd)
Fix some missing SQL data escapes (fabrixxm)
Improved the accessibility of the web UI for better screen reader compatibility (annando)
@ -1972,7 +2041,7 @@ Version 3.4.1 (2015-07-06)
Implement server-to-server encryption (RINO) using php-encryption library as "RINO 2", deprecate "RINO 1" (issue #1655) (fabrixxm)
Fix connection with Diaspora "freelove" account (issue #1572) (annando)
Various SQL speedups (annando)
Port of Javascript DatePicker input from RedMatrix (rabuzarus)
Port of JavaScript DatePicker input from RedMatrix (rabuzarus)
Port of RedMatrix archive widget (rabuzarus)
Load profile owner settings for theme on profile page (rabuzarus)
Move HTML code from php into templates (rabuzarus)
@ -1985,7 +2054,7 @@ Version 3.4.1 (2015-07-06)
use correct contact when automatically add @-replies
add attachment links as enclosures
send salmon notifications to every mentioned person
better thread completition
better thread completion
support for bookmarks
support for events and questions
link to items using GUID
@ -1996,7 +2065,7 @@ Version 3.4.1 (2015-07-06)
Add fake fields to API response for better Twitter API compatibility (annando)
Fix search in local directory (issue #1657) (annando)
Improve OEmbed (issue #1640) (annando)
Fix double html encodig in site administration page for sitename and register text (issue #1628) (annando)
Fix double html encoding in site administration page for sitename and register text (issue #1628) (annando)
Fix remote subscription from GNU Social (annando)
Fix "{0}" in notifications (issue #1642) (annando)
Fix desktop notification (fabrixxm)
@ -2005,7 +2074,7 @@ Version 3.4.1 (2015-07-06)
Fix emoticons alt text (tobias)
Improve threaded display in Vier theme (annando)
Use field templates in photo edit form (fabrixxm)
Alllow deletion of any user but yourself (issue #1625) (fabrixxm)
Allow deletion of any user but yourself (issue #1625) (fabrixxm)
Install wizard load htconfig template from template/ folder, remove localized htconfig templates (fabrixxm)
Add contact detail to non-js contact drop confirm dialog (issue #1629) (fabrixxm)
Return geo coord in API (annando)
@ -2024,7 +2093,7 @@ Version 3.4 (2015-04-05)
Optionally, "like" and "dislike" activities don't update thread timestamp (annando)
Updated markdown libraries (annando)
Updated jQuery (StefOfficiel)
Cache zrl verification requests to prevent DSoS (issue #1453) (annando)
Cache zrl verification requests to prevent DDoS (issue #1453) (annando)
"Verify SSL" options affects also VERIFYHOST (annando)
Better handling of hashtags (annando)
Updated translations (translation teams, tobias)
@ -2062,7 +2131,7 @@ Version 3.3.3 (2015-02-24)
Share-it button support (annando)
More reliable reshare from Diaspora (annando)
Load more images via proxy (annando)
util/typo.php uses "php -l" insead of "eval()" to validate code (fabrixxm)
util/typo.php uses "php -l" instead of "eval()" to validate code (fabrixxm)
Use $_SERVER array in cli script instead of $argv/$argc (issue #1218) (annando)
Updated vagrant setup script (silke)
API: support to star/unstar items (fabrixxm)
@ -2083,7 +2152,7 @@ Version 3.3.3 (2015-02-24)
Version 3.3.2 (2014-12-26)
Set default value for all not-null fields (fixes SQL warinigs) (annando)
Set default value for all not-null fields (fixes SQL warnings) (annando)
Fix item filters in network page (issue #1222) (fabrixxm)
Remove reference to an ex Friendica hub from documentation (beardyunixer, tobiasd)
API throttling (annando)
@ -2129,7 +2198,7 @@ Version 3.3 (2014-10-06)
Interaction
ignoring of threads
for selected contects one can now get notifications when they post something, useful e.g. for forums
for selected contacts one can now get notifications when they post something, useful e.g. for forums
After a new friendica contact is added, the user is directed to the contact page of the new contact. (Instead of the remote profile)
many improvement on all connectors, new app.net connector
the algorithm for shortening postings when posting to limited platforms was improved
@ -2141,7 +2210,7 @@ Version 3.3 (2014-10-06)
updated the following libraries: smarty 3.1.19, fullcalendar 1.6.4, jquery 1.11, jgrowl 1.3.0
added modernizer 2.8.3, better browser support
updates to the DB structure for better performance
preperations to use PDO in a later release
preparations to use PDO in a later release
new notification system
web interface translations updated, addon translations now also possible separately from the main UI and done for CS, IT, RO, DE
vagrant support added for developers
@ -2179,7 +2248,7 @@ Version 3.2
small fixed
edit profile photo link
better caching of pictures
threadening for outgoing emails
threading for outgoing emails
mail import
oembed thumbnails
SN subscriptions & more SN like behaviour if snautofollow addon is used
@ -2199,7 +2268,7 @@ Version 3.2
improving the install.php script
addons now can be members only
item object now contains the "edited" information left for the theme designers to show this info in a pretty way
improvments to the user-import from exported account files
improvements to the user-import from exported account files
It's now possible to authenticate an ejabberd server against friendica.
bugtracker moved to github
improvements to MySQL queries

View file

@ -74,8 +74,11 @@ CrystalStiletto
Cyboulette
Cyryl Sochacki
czarnystokrotek
daingewuvzeevisiddfddd
Damian Wajer
Damien Goutte-Gattat
Daniel Dupriest
Daniel Siepmann
Daria Początek
David
David Martín Miranda
@ -101,6 +104,7 @@ erik
Erkan Yilmaz
Eugene Veresk
Extarys
F1per 3y
Fabian Dost
Fabio Comuni
Farida Khalaf
@ -126,6 +130,7 @@ GunChleoc
guzzisti
Haakon Meland Eriksen
Hank Grabowski
Hannes Heute
Hans Meine
Hauke
Hauke Altmann
@ -138,7 +143,7 @@ Ilmari
ImgBotApp
irhen
Jakob
Jakobus Schürz (admin)
Jakob Schürz
Jens Tautenhahn
jensp
Jeroen De Meerleer
@ -153,6 +158,7 @@ John Mortensen
Jonatan Nyberg
Jonny Tischbein
Josef Moravek
Josh Soref
juanman
julia.domagalska
Julio Cova
@ -185,6 +191,7 @@ Marcin Klessa
Marcin Mikołajczak
Marcus Müller
Marek Bachmann
MarekBenjamin
Marie Olive
Mariusz Pisz
marmor
@ -209,6 +216,7 @@ mytbk
nathilia-peirce
Nicola Spanti
Nicolas Derive
nnsrymni
nobody
nupplaPhil
Olaf Conradi
@ -227,6 +235,7 @@ Pavel Morozov
PerigGouanvic
peter
Peter Liebetrau
Petr Kučera
peturisfeld
Phigger Phigger
Philipp
@ -244,7 +253,7 @@ Rafael Kalachev
Rain Hawk
Rainulf Pineda
Ralf Thees
Ralph
ralph van der honing
Ratten
rcmaniac
RealKinetix
@ -257,6 +266,7 @@ Rik 4
RJ Madsen
Roger Meyer
Roland Häder
Ruud Schilders
rwa
Ryan Voots
S.Krumbholz
@ -338,6 +348,7 @@ Wil Tur
Wouter Broers
Xiaofei Xu
XMPPはいいぞ
xundeenergie
Yasen Pramatarov
Yasmine A
ylms

View file

@ -17,18 +17,18 @@ Have a look at the [installation documentation](doc/Install.md) for further info
### Friendica Screenshots
| ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profle-1.png?raw=true "Frio theme in mobile browser") ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profle-2.png?raw=true "Frio theme in mobile browser")
| ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profile-1.png?raw=true "Frio theme in mobile browser") ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profile-2.png?raw=true "Frio theme in mobile browser")
|:--:|
|*Frio theme, mobile browser. Timeline and composer view.*|
|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profle-1.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profile-1.png?raw=true "Frio theme in desktop browser")
|*Frio theme, desktop browser. Timeline view, contact info popped up, control menu open.*|
|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profle-2.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profile-2.png?raw=true "Frio theme in desktop browser")
|*Frio theme, desktop browser. Menu open for controlling individual posts.*|
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profle-3.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-3.png?raw=true "Frio theme in desktop browser")
|*Frio theme, desktop browser. Profile view, notification menu open.*|
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profle-2.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-2.png?raw=true "Frio theme in desktop browser")
|*Number of new posts, in total and by group.*|
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profle-1.png?raw=true "Frio theme in desktop browser")
|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-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.*|

View file

@ -1 +1 @@
2023.01
2023.03-rc

View file

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -82,6 +82,10 @@ $dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabb
\Friendica\DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
// Check the database structure and possibly fixes it
\Friendica\Core\Update::check(\Friendica\DI::basePath(), true);
$appMode = $dice->create(Mode::class);
if ($appMode->isNormal()) {

View file

@ -3,7 +3,7 @@
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
# We are in Cygwin using Windows php, so the path must be translated
dir=$(cygpath -m "$dir");
fi

View file

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*

View file

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -33,6 +33,7 @@ if (php_sapi_name() !== 'cli') {
use Dice\Dice;
use Friendica\App\Mode;
use Friendica\Core\Logger;
use Friendica\Core\Update;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\DI;
@ -63,7 +64,6 @@ $dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']])
DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
$a = DI::app();
if (DI::mode()->isInstall()) {
die("Friendica isn't properly installed yet.\n");
@ -71,7 +71,7 @@ if (DI::mode()->isInstall()) {
DI::mode()->setExecutor(Mode::DAEMON);
DI::config()->load();
DI::config()->reload();
if (empty(DI::config()->get('system', 'pidfile'))) {
die(<<<TXT
@ -115,7 +115,7 @@ if (is_readable($pidfile)) {
}
if (empty($pid) && in_array($mode, ['stop', 'status'])) {
DI::config()->set('system', 'worker_daemon_mode', false);
DI::keyValue()->set('worker_daemon_mode', false);
die("Pidfile wasn't found. Is the daemon running?\n");
}
@ -126,7 +126,7 @@ if ($mode == 'status') {
unlink($pidfile);
DI::config()->set('system', 'worker_daemon_mode', false);
DI::keyValue()->set('worker_daemon_mode', false);
die("Daemon process $pid isn't running.\n");
}
@ -137,7 +137,7 @@ if ($mode == 'stop') {
Logger::notice('Worker daemon process was killed', ['pid' => $pid]);
DI::config()->set('system', 'worker_daemon_mode', false);
DI::keyValue()->set('worker_daemon_mode', false);
die("Worker daemon process $pid was killed.\n");
}
@ -181,7 +181,7 @@ if (!$foreground) {
DBA::connect();
}
DI::config()->set('system', 'worker_daemon_mode', true);
DI::keyValue()->set('worker_daemon_mode', true);
// Just to be sure that this script really runs endlessly
set_time_limit(0);
@ -193,6 +193,9 @@ $last_cron = 0;
// Now running as a daemon.
while (true) {
// Check the database structure and possibly fixes it
Update::check(DI::basePath(), true);
if (!$do_cron && ($last_cron + $wait_interval) < time()) {
Logger::info('Forcing cron worker call.', ['pid' => $pid]);
$do_cron = true;
@ -244,5 +247,6 @@ while (true) {
}
function shutdown() {
posix_kill(posix_getpid(), SIGTERM);
posix_kill(posix_getpid(), SIGHUP);
}

View file

@ -46,7 +46,7 @@ function show_syntax() {
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_USERNAME\" 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
@ -65,7 +65,7 @@ else
exit 3
fi
echo "Installing depdendencies"
echo "Installing dependencies"
${PHP} "$COMPOSER" install
PHPUNIT="${BASEDIR}/vendor/bin/phpunit"

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*

View file

@ -1,7 +1,7 @@
#!/usr/bin/php
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*

View file

@ -1,7 +1,7 @@
#!/usr/bin/env php
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -58,20 +58,17 @@ $dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']])
DI::init($dice);
\Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class));
$a = DI::app();
DI::mode()->setExecutor(Mode::WORKER);
// Check the database structure and possibly fixes it
Update::check($a->getBasePath(), true, DI::mode());
Update::check(DI::basePath(), true);
// 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) {

View file

@ -24,15 +24,19 @@
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-posix": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"asika/simple-console": "^1.0",
"bacon/bacon-qr-code": "^2.0.0",
"divineomega/password_exposed": "^2.8",
"enyo/dropzone": "^5.9",
"ezyang/htmlpurifier": "^4.7",
"friendica/json-ld": "^1.0",
"geekwright/po": "^2.0",
"guzzlehttp/guzzle": "^6.5",
"guzzlehttp/oauth-subscriber": "^0.6",
"kornrunner/blurhash": "^1.2",
"league/html-to-markdown": "^4.8",
"level-2/dice": "^4",
"lightopenid/lightopenid": "dev-master",
@ -48,6 +52,7 @@
"phpseclib/phpseclib": "^3.0",
"pragmarx/google2fa": "^5.0",
"pragmarx/recovery": "^0.2",
"psr/clock": "^1.0",
"psr/container": "^1.0",
"psr/log": "^1.1",
"seld/cli-prompt": "^1.0",
@ -70,9 +75,7 @@
"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",
"kornrunner/blurhash": "^1.2",
"psr/clock": "^1.0"
"npm-asset/typeahead.js": "^0.11.1"
},
"repositories": [
{
@ -132,7 +135,13 @@
"test": "phpunit",
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l",
"cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer",
"cs:check": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run --diff"],
"cs:fix": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"]
"cs:check": [
"@cs:install",
"bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run --diff"
],
"cs:fix": [
"@cs:install",
"bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"
]
}
}

468
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -40,5 +40,6 @@ return [
'system' => [
'default_timezone' => 'UTC',
'language' => 'en',
'url' => 'https://friendica.local',
],
];

View file

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2022.12 (Giant Rhubarb)
-- DB_UPDATE_VERSION 1502
-- Friendica 2023.03-rc (Giant Rhubarb)
-- DB_UPDATE_VERSION 1518
-- ------------------------------------------
@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS `gserver` (
`last_poco_query` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Last successful connection request',
`last_failure` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Last failed connection request',
`blocked` boolean COMMENT 'Server is blocked',
`failed` boolean COMMENT 'Connection failed',
`next_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT 'Next connection request',
PRIMARY KEY(`id`),
@ -70,7 +71,7 @@ CREATE TABLE IF NOT EXISTS `user` (
`verified` boolean NOT NULL DEFAULT '0' COMMENT 'user is verified through email',
`blocked` boolean NOT NULL DEFAULT '0' COMMENT '1 for user is blocked',
`blockwall` boolean NOT NULL DEFAULT '0' COMMENT 'Prohibit contacts to post to the profile page of the user',
`hidewall` boolean NOT NULL DEFAULT '0' COMMENT 'Hide profile details from unkown viewers',
`hidewall` boolean NOT NULL DEFAULT '0' COMMENT 'Hide profile details from unknown viewers',
`blocktags` boolean NOT NULL DEFAULT '0' COMMENT 'Prohibit contacts to tag the post of this user',
`unkmail` boolean NOT NULL DEFAULT '0' COMMENT 'Permit unknown people to send private mails to this user',
`cntunkmail` int unsigned NOT NULL DEFAULT 10 COMMENT '',
@ -339,22 +340,6 @@ CREATE TABLE IF NOT EXISTS `account-user` (
FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Remote and local accounts';
--
-- TABLE addon
--
CREATE TABLE IF NOT EXISTS `addon` (
`id` int unsigned NOT NULL auto_increment COMMENT '',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT 'addon base (file)name',
`version` varchar(50) NOT NULL DEFAULT '' COMMENT 'currently unused',
`installed` boolean NOT NULL DEFAULT '0' COMMENT 'currently always 1',
`hidden` boolean NOT NULL DEFAULT '0' COMMENT 'currently unused',
`timestamp` int unsigned NOT NULL DEFAULT 0 COMMENT 'file timestamp to check for reloads',
`plugin_admin` boolean NOT NULL DEFAULT '0' COMMENT '1 = has admin config, 0 = has no admin config',
PRIMARY KEY(`id`),
INDEX `installed_name` (`installed`,`name`),
UNIQUE INDEX `name` (`name`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='registered addons';
--
-- TABLE apcontact
--
@ -499,8 +484,8 @@ CREATE TABLE IF NOT EXISTS `cache` (
--
CREATE TABLE IF NOT EXISTS `config` (
`id` int unsigned NOT NULL auto_increment COMMENT '',
`cat` varbinary(50) NOT NULL DEFAULT '' COMMENT '',
`k` varbinary(50) NOT NULL DEFAULT '' COMMENT '',
`cat` varbinary(50) NOT NULL DEFAULT '' COMMENT 'The category of the entry',
`k` varbinary(50) NOT NULL DEFAULT '' COMMENT 'The key of the entry',
`v` mediumtext COMMENT '',
PRIMARY KEY(`id`),
UNIQUE INDEX `cat_k` (`cat`,`k`)
@ -579,6 +564,27 @@ CREATE TABLE IF NOT EXISTS `delayed-post` (
FOREIGN KEY (`wid`) REFERENCES `workerqueue` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Posts that are about to be distributed at a later time';
--
-- TABLE delivery-queue
--
CREATE TABLE IF NOT EXISTS `delivery-queue` (
`gsid` int unsigned NOT NULL COMMENT 'Target server',
`uri-id` int unsigned NOT NULL COMMENT 'Delivered post',
`created` datetime COMMENT '',
`command` varbinary(32) COMMENT '',
`cid` int unsigned COMMENT 'Target contact',
`uid` mediumint unsigned COMMENT 'Delivering user',
`failed` tinyint DEFAULT 0 COMMENT 'Number of times the delivery has failed',
PRIMARY KEY(`uri-id`,`gsid`),
INDEX `gsid_created` (`gsid`,`created`),
INDEX `uid` (`uid`),
INDEX `cid` (`cid`),
FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT,
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Delivery data for posts for the batch processing';
--
-- TABLE diaspora-contact
--
@ -602,7 +608,7 @@ CREATE TABLE IF NOT EXISTS `diaspora-contact` (
`gsid` int unsigned COMMENT 'Global Server ID',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`interacting_count` int unsigned DEFAULT 0 COMMENT 'Number of contacts this contact interactes with',
`interacting_count` int unsigned DEFAULT 0 COMMENT 'Number of contacts this contact interacts with',
`interacted_count` int unsigned DEFAULT 0 COMMENT 'Number of contacts that interacted with this contact',
`post_count` int unsigned DEFAULT 0 COMMENT 'Number of posts and comments',
PRIMARY KEY(`uri-id`),
@ -803,6 +809,7 @@ CREATE TABLE IF NOT EXISTS `inbox-entry-receiver` (
CREATE TABLE IF NOT EXISTS `inbox-status` (
`url` varbinary(383) NOT NULL COMMENT 'URL of the inbox',
`uri-id` int unsigned COMMENT 'Item-uri id of inbox url',
`gsid` int unsigned COMMENT 'ID of the related server',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Creation date of this entry',
`success` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last successful delivery',
`failure` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last failed delivery',
@ -811,7 +818,9 @@ CREATE TABLE IF NOT EXISTS `inbox-status` (
`shared` boolean NOT NULL DEFAULT '0' COMMENT 'Is it a shared inbox?',
PRIMARY KEY(`url`),
INDEX `uri-id` (`uri-id`),
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
INDEX `gsid` (`gsid`),
FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Status of ActivityPub inboxes';
--
@ -839,6 +848,16 @@ CREATE TABLE IF NOT EXISTS `intro` (
FOREIGN KEY (`suggest-cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='';
--
-- TABLE key-value
--
CREATE TABLE IF NOT EXISTS `key-value` (
`k` varbinary(50) NOT NULL COMMENT '',
`v` mediumtext COMMENT '',
`updated_at` int unsigned NOT NULL COMMENT 'timestamp of the last update',
PRIMARY KEY(`k`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='A key value storage';
--
-- TABLE locks
--
@ -861,7 +880,7 @@ CREATE TABLE IF NOT EXISTS `mail` (
`guid` varbinary(255) NOT NULL DEFAULT '' COMMENT 'A unique identifier for this private message',
`from-name` varchar(255) NOT NULL DEFAULT '' COMMENT 'name of the sender',
`from-photo` varbinary(383) NOT NULL DEFAULT '' COMMENT 'contact photo link of the sender',
`from-url` varbinary(383) NOT NULL DEFAULT '' COMMENT 'profile linke of the sender',
`from-url` varbinary(383) NOT NULL DEFAULT '' COMMENT 'profile link of the sender',
`contact-id` varbinary(255) COMMENT 'contact.id',
`author-id` int unsigned COMMENT 'Link to the contact table with uid=0 of the author of the mail',
`convid` int unsigned COMMENT 'conv.id',
@ -1439,7 +1458,7 @@ CREATE TABLE IF NOT EXISTS `post-user` (
`event-id` int unsigned COMMENT 'Used to link to the event.id',
`unseen` boolean NOT NULL DEFAULT '1' COMMENT 'post has not been seen',
`hidden` boolean NOT NULL DEFAULT '0' COMMENT 'Marker to hide the post from the user',
`notification-type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
`notification-type` smallint unsigned NOT NULL DEFAULT 0 COMMENT '',
`wall` boolean NOT NULL DEFAULT '0' COMMENT 'This item was posted to the wall of uid',
`origin` boolean NOT NULL DEFAULT '0' COMMENT 'item originated at this site',
`psid` int unsigned COMMENT 'ID of the permission set of this post',
@ -1551,7 +1570,7 @@ CREATE TABLE IF NOT EXISTS `post-user-notification` (
--
CREATE TABLE IF NOT EXISTS `process` (
`pid` int unsigned NOT NULL COMMENT 'The ID of the process',
`hostname` varchar(32) NOT NULL COMMENT 'The name of the host the process is ran on',
`hostname` varchar(255) NOT NULL COMMENT 'The name of the host the process is ran on',
`command` varbinary(32) NOT NULL DEFAULT '' COMMENT '',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
PRIMARY KEY(`pid`,`hostname`),
@ -1674,15 +1693,20 @@ CREATE TABLE IF NOT EXISTS `register` (
CREATE TABLE IF NOT EXISTS `report` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`uid` mediumint unsigned COMMENT 'Reporting user',
`reporter-id` int unsigned COMMENT 'Reporting contact',
`cid` int unsigned NOT NULL COMMENT 'Reported contact',
`comment` text COMMENT 'Report',
`category` varchar(20) COMMENT 'Category of the report (spam, violation, other)',
`rules` text COMMENT 'Violated rules',
`forward` boolean COMMENT 'Forward the report to the remote server',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`status` tinyint unsigned COMMENT 'Status of the report',
PRIMARY KEY(`id`),
INDEX `uid` (`uid`),
INDEX `cid` (`cid`),
INDEX `reporter-id` (`reporter-id`),
FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (`reporter-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='';
@ -2825,7 +2849,9 @@ CREATE VIEW `account-view` AS SELECT
`apcontact`.`statuses_count` AS `ap-statuses_count`,
`gserver`.`site_name` AS `site_name`,
`gserver`.`platform` AS `platform`,
`gserver`.`version` AS `version`
`gserver`.`version` AS `version`,
`gserver`.`blocked` AS `server-blocked`,
`gserver`.`failed` AS `server-failed`
FROM `contact`
LEFT JOIN `item-uri` ON `item-uri`.`id` = `contact`.`uri-id`
LEFT JOIN `apcontact` ON `apcontact`.`uri-id` = `contact`.`uri-id`
@ -2929,7 +2955,9 @@ CREATE VIEW `account-user-view` AS SELECT
`apcontact`.`statuses_count` AS `ap-statuses_count`,
`gserver`.`site_name` AS `site_name`,
`gserver`.`platform` AS `platform`,
`gserver`.`version` AS `version`
`gserver`.`version` AS `version`,
`gserver`.`blocked` AS `server-blocked`,
`gserver`.`failed` AS `server-failed`
FROM `contact` AS `ucontact`
INNER JOIN `contact` ON `contact`.`uri-id` = `ucontact`.`uri-id` AND `contact`.`uid` = 0
LEFT JOIN `item-uri` ON `item-uri`.`id` = `ucontact`.`uri-id`

View file

@ -908,6 +908,13 @@ Identical to [the Twitter Media Object](https://developer.twitter.com/en/docs/tw
<td>Resource ID (32 hex chars)</td>
</tr>
<tr>
<td><code>media-id</code></td>
<td>String (Integer) </td>
<td>ID used for attaching images to a Mastodon Post Status</td>
</tr>
<tr>
<td><code>created</code></td>
<td>String (Date)</td>
@ -1001,6 +1008,14 @@ Mutually exclusive with <code>data</code> <code>datasize</code>.
</td>
</tr>
<tr>
<td><code>scales</code></td>
<td>Array of Photo Scales</td>
<td>
List of the various resized versions of the Photo
</td>
</tr>
<tr>
<td><code>datasize</code></td>
<td>Integer</td>
@ -1040,6 +1055,58 @@ Mutually exclusive with <code>link</code>.
</tbody>
</table>
## Photo Scale
<table class="table table-condensed table-striped table-bordered">
<thead>
<tr>
<th>Attribute</th>
<th>Type</th>
<th align="center">Nullable</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>id</code></td>
<td>String (Integer)</td>
<td>Row ID of this photo scale</td>
</tr>
<tr>
<td><code>scale</code></td>
<td>Integer</td>
<td>Scale number</td>
</tr>
<tr>
<td><code>link</code></td>
<td>String (URL)</td>
<td>URL to this scale's image</td>
</tr>
<tr>
<td><code>height</code></td>
<td>Integer</td>
<td>Image height in pixels</td>
</tr>
<tr>
<td><code>width</code></td>
<td>Integer</td>
<td>Image width in pixels</td>
</tr>
<tr>
<td><code>size</code></td>
<td>Integer</td>
<td>Image size in bytes</td>
</tr>
</tbody>
</table>
## Photo List Item
<table class="table table-condensed table-striped table-bordered">
@ -1103,6 +1170,40 @@ Mutually exclusive with <code>link</code>.
</tbody>
</table>
## Photo Album
<table class="table table-condensed table-striped table-bordered">
<thead>
<tr>
<th>Attribute</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>name</code></td>
<td>String</td>
<td>The name of the photo album</td>
</tr>
<tr>
<td><code>created</code></td>
<td>String (Date)</td>
<td>The creation date of the album. Format <code>YYYY-MM-DD HH:MM:SS</code></td>
</tr>
<tr>
<td><code>count</code></td>
<td>Integer</td>
<td>The number of images in the album</td>
</tr>
</tbody>
</table>
## Private message
<table class="table table-condensed table-striped table-bordered">

View file

@ -305,7 +305,7 @@ Returns [Private Messages](help/API-Entities#Private+message) matching the provi
#### 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.
* `getText` (optional): `plain`|`html` If omitted, 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
@ -646,7 +646,7 @@ 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"
* 500 INTERNALSERVERERROR: "problem with deleting item occurred", "unknown error - deleting from database failed"
### POST api/friendica/photoalbum/update
@ -676,8 +676,92 @@ On error:
* 400 BADREQUEST: "no albumname specified", "no new albumname specified", "album not available"
* 500 INTERNALSERVERERROR: "unknown error - updating in database failed"
### GET api/friendica/photoalbums
Get a list of photo albums for the user
#### Parameters
None
#### Return values
On success a list of photo album objects:
```json
[
{
"name": "Wall Photos",
"created": "2023-01-22 02:03:19",
"count": 4
},
{
"name": "Profile photos",
"created": "2022-11-20 14:40:06",
"count": 1
}
]
```
### GET api/friendica/photoalbum
Get a list of images in a photo album
#### Parameters
* `album` (Required): name of the album to be deleted
* `limit` (Optional): Maximum number of items to get, defaults to 50, max 500
* `offset`(Optional): Offset in results to page through total items, defaults to 0
* `latest_first` (Optional): Reverse the order so the most recent images are first, defaults to false
#### Return values
On success:
* JSON return with the list of Photo items
**Example:**
`https://<server>/api/friendica/photoalbum?album=Wall Photos&limit=10&offset=2`
```json
[
{
"created": "2023-02-14 14:31:06",
"edited": "2023-02-14 14:31:14",
"title": "",
"desc": "",
"album": "Wall Photos",
"filename": "image.png",
"type": "image/png",
"height": 835,
"width": 693,
"datasize": 119523,
"profile": 0,
"allow_cid": "",
"deny_cid": "",
"allow_gid": "",
"deny_gid": "",
"id": "899184972463eb9b2ae3dc2580502826",
"scale": 0,
"media-id": 52,
"scales": [
{
"id": 52,
"scale": 0,
"link": "https://<server>/photo/899184972463eb9b2ae3dc2580502826-0.png",
"width": 693,
"height": 835,
"size": 119523
},
...
],
"thumb": "https://<server>/photo/899184972463eb9b2ae3dc2580502826-2.png"
},
...
]
```
---
### GET api/friendica/profile/show
Returns the [Profile](help/API-Entities#Profile) data of the authenticated user.
@ -715,6 +799,129 @@ General description of profile data in API returns:
---
### POST api/friendica/statuses/:id/dislike
Marks the given status as disliked by this user
#### Path Parameter
* `id`: the status ID that is being marked
#### Return values
A Mastodon [Status Entity](https://docs.joinmastodon.org/entities/Status/)
#### Example:
`https://<server_name>/api/friendica/statuses/341/dislike`
```json
{
"id": "341",
"created_at": "2023-02-23T01:50:00.000Z",
"in_reply_to_id": null,
"in_reply_to_status": null,
"in_reply_to_account_id": null,
"sensitive": false,
"spoiler_text": "",
"visibility": "public",
"language": "en",
...
"account": {
"id": "8",
"username": "testuser2",
...
},
"media_attachments": [],
"mentions": [],
"tags": [],
"emojis": [],
"card": null,
"poll": null,
"friendica": {
"title": "",
"dislikes_count": 1,
"disliked": true
}
}
```
### GET api/friendica/statuses/:id/disliked_by
Returns the list of accounts that have disliked the status as known by the current server
#### Path Parameter
* `id`: the status ID that is being marked
#### Return values
A list of [Mastodon Account](https://docs.joinmastodon.org/entities/Account/) objects
in the body and next/previous link headers in the header
#### Example:
`https://<server_name>/api/friendica/statuses/341/disliked_by`
```json
[
{
"id": "6",
"username": "testuser1",
...
}
]
```
### POST api/friendica/statuses/:id/undislike
Removes the dislike mark (if it exists) on this status for this user
#### Path Parameter
* `id`: the status ID that is being marked
#### Return values
A Mastodon [Status Entity](https://docs.joinmastodon.org/entities/Status/)
#### Example:
`https://<server_name>/api/friendica/statuses/341/undislike`
```json
{
"id": "341",
"created_at": "2023-02-23T01:50:00.000Z",
"in_reply_to_id": null,
"in_reply_to_status": null,
"in_reply_to_account_id": null,
"sensitive": false,
"spoiler_text": "",
"visibility": "public",
"language": "en",
...
"account": {
"id": "8",
"username": "testuser2",
...
},
"media_attachments": [],
"mentions": [],
"tags": [],
"emojis": [],
"card": null,
"poll": null,
"friendica": {
"title": "",
"dislikes_count": 0,
"disliked": false
}
}
```
---
## Deprecated endpoints
- POST api/statuses/mediap

View file

@ -30,6 +30,101 @@ For supported apps please have a look at the [FAQ](help/FAQ#clients)
## Entities
These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/entities/).
With some additional extensions listed below.
### Instance (Version 2) Entities
Extensions to the [Mastodon Instance::V2 Entities](https://docs.joinmastodon.org/entities/Instance/)
* `friendica`: Friendica specific properties of the V2 Instance including:
* `version`: The Friendica version string
* `codename`: The Friendica version code name
* `db_version`: The database schema version number
Example:
```json
{
"domain": "friendicadevtest1.myportal.social",
"title": "Friendica Social Network",
"version": "2.8.0 (compatible; Friendica 2023.03-dev)",
...
"friendica": {
"version": "2023.03-dev",
"codename": "Giant Rhubarb",
"db_version": 1516
}
}
```
### Notification Entities
Extensions to the [Mastodon Notification Entities](https://docs.joinmastodon.org/entities/Notification/)
* `dismissed`: whether the object has been dismissed or not
### Status Entities
Extensions to the [Mastodon Status Entities](https://docs.joinmastodon.org/entities/Status/)
* `in_reply_to_status`: A fully populated Mastodon Status entity for the replied to status or null it is a post rather than a response
* `friendica`: Friendica specific properties of a status including:
* `title`: The Friendica title for a post, or empty if the status is a comment
* `delivery_data`: Information about the state of federating a message from the server
* `delivery_queue_count`: Total number of remote servers that the status needs to be federated to.
* `delivery_queue_done`: Total number of remote servers that have successfully been federated to so far.
* `delivery_queue_failed`: Total number of remote servers that have we failed to federate to so far.
* `dislikes_count`: The number of dislikes that a status has accumulated according to the server.
* `disliked`: Whether the API user disliked the status.
Example:
```json
{
"id": "358",
"created_at": "2023-02-23T02:45:46.000Z",
"in_reply_to_id": "356",
"in_reply_to_status": {
"id": "356",
"created_at": "2023-02-23T02:45:35.000Z",
"in_reply_to_id": null,
"in_reply_to_status": null,
"in_reply_to_account_id": null,
...
"content": "A post from testuser1",
...
"account": {
"id": "6",
"username": "testuser1",
"acct": "testuser1",
"display_name": "testuser1",
...
},
...
"friendica": {
"title": "",
"dislikes_count": 0
}
},
"in_reply_to_account_id": "6",
...
"replies_count": 0,
"reblogs_count": 0,
"favourites_count": 0,
...
"content": "A reply from testuser2",
...
"account": {
"id": "8",
"username": "testuser2",
"acct": "testuser2",
"display_name": "testuser2",
...
},
...
"friendica": {
"title": "",
"delivery_data": {
"delivery_queue_count": 10,
"delivery_queue_done": 3,
"delivery_queue_failed": 0
},
"dislikes_count": 0
}
}
```
## Implemented endpoints
@ -73,8 +168,8 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
- `:id` is a follow request ID, not a regular account id
- Returns a [Relationship](https://docs.joinmastodon.org/entities/relationship) object.
- [`GET /api/v1/followed_tags'](https://docs.joinmastodon.org/methods/followed_tags/)
- [`GET /api/v1/instance`](https://docs.joinmastodon.org/methods/instance#fetch-instance)
- [`GET /api/v1/followed_tags`](https://docs.joinmastodon.org/methods/followed_tags/)
- [`GET /api/v1/instance`](https://docs.joinmastodon.org/methods/instance/#v1)
- `GET /api/v1/instance/rules` Undocumented, returns Terms of Service
- [`GET /api/v1/instance/peers`](https://docs.joinmastodon.org/methods/instance#list-of-connected-domains)
- [`GET /api/v1/lists`](https://docs.joinmastodon.org/methods/timelines/lists/)
@ -92,6 +187,10 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
- [`PUT /api/v1/media/:id`](https://docs.joinmastodon.org/methods/statuses/media/)
- [`GET /api/v1/mutes`](https://docs.joinmastodon.org/methods/accounts/mutes/)
- [`GET /api/v1/notifications`](https://docs.joinmastodon.org/methods/notifications/)
- Additional field `include_all` to return read and unread statuses, defaults to `false`
- Additional field `summary` returns a count of all of the statuses that match the type filter
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
- Does not support the `type` field, which is the mirror image of the supported `exclude_types` field
- [`GET /api/v1/notifications/:id`](https://docs.joinmastodon.org/methods/notifications/)
- [`POST /api/v1/notifications/clear`](https://docs.joinmastodon.org/methods/notifications/)
- [`POST /api/v1/notifications/:id/dismiss`](https://docs.joinmastodon.org/methods/notifications/)
@ -106,11 +205,22 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
- [`DELETE /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/)
- [`GET /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/)
- [`GET /api/v1/search`](https://docs.joinmastodon.org/methods/search/)
- [`PUT /api/v1/statuses`](https://docs.joinmastodon.org/methods/statuses/#edit)
- Does not support `polls` argument as Friendica does not have polls
- Additional fields `friendica` for Friendica specific parameters:
- `title`: Explicitly sets the title for a post status, ignored if used on a comment status. For post statuses the legacy behavior is to use any "spoiler text" as the title if it is provided. If both the title and spoiler text are provided for a post status then they will each be used for their respective roles. If no title is provided then the legacy behavior will persist. If you want to create a post with no title but spoiler text then explicitly set the title but set it to an empty string `""`.
- [`POST /api/v1/statuses`](https://docs.joinmastodon.org/methods/statuses/#create)
- Does not support `polls` argument as Friendica does not have polls
- Additionally to the static values `public`, `unlisted` and `private`, the `visibility` parameter can contain a numeric value with a group id.
- Additional field `quote_id` for the post that is being quote reshared
- Additional fields `friendica` for Friendica specific parameters:
- `title`: Explicitly sets the title for a post status, ignored if used on a comment status. For post statuses the legacy behavior is to use any "spoiler text" as the title if it is provided. If both the title and spoiler text are provided for a post status then they will each be used for their respective roles. If no title is provided then the legacy behavior will persist. If you want to create a post with no title but spoiler text then explicitly set the title but set it to an empty string `""`.
- [`GET /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/#get)
- [`DELETE /api/v1/statuses/:id`](https://docs.joinmastodon.org/methods/statuses/#delete)
- [`GET /api/v1/statuses/:id/context`](https://docs.joinmastodon.org/methods/statuses/#context)
- Additional support for paging using `min_id`, `max_id`, `since_id` parameters
- Additional support for previous/next Link Headers to support paging
- Additional flag `show_all` to allow including posts from blocked and ignored/muted users, defaults to `false`
- [`GET /api/v1/statuses/:id/reblogged_by`](https://docs.joinmastodon.org/methods/statuses/#reblogged_by)
- [`GET /api/v1/statuses/:id/favourited_by`](https://docs.joinmastodon.org/methods/statuses/#favourited_by)
- [`POST /api/v1/statuses/:id/favourite`](https://docs.joinmastodon.org/methods/statuses/#favourite)
@ -132,19 +242,30 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en
- [`GET /api/v1/tags/:id/unfollow`](https://docs.joinmastodon.org/methods/tags/#unfollow)
- [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/)
- [`GET /api/v1/timelines/home`](https://docs.joinmastodon.org/methods/timelines/)
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
- [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/)
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
- [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/)
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
- [`GET /api/v1/timelines/tag/:hashtag`](https://docs.joinmastodon.org/methods/timelines/)
- Additional field `with_muted` Pleroma extension to return notifications from muted users, defaults to `false`
- Additional field `exclude_replies` to only return post statuses not replies/comments, defaults to `false`
- Does not support the `any[]`, `all[]`, or `none[]` query parameters
- [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/)
- [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917)
- [`GET /api/v1/trends/statuses`](https://docs.joinmastodon.org/methods/trends/#statuses)
- [`GET /api/v1/trends/tags`](https://docs.joinmastodon.org/methods/trends/#tags)
- Additional field `friendica_local` to return local trending tags instead of global tags, defaults to `false`
- [`GET /api/v2/instance`](https://docs.joinmastodon.org/methods/instance/#v2)
- [`GET /api/v2/search`](https://docs.joinmastodon.org/methods/search/)
## Currently unimplemented endpoints
These emdpoints are planned to be implemented somewhere in the future.
These endpoints are planned to be implemented somewhere in the future.
- [`POST /api/v1/accounts/:id/remove_from_followers`](https://github.com/mastodon/mastodon/pull/16864)
- [`GET /api/v1/accounts/familiar_followers`](https://github.com/mastodon/mastodon/pull/17700)

View file

@ -10,7 +10,7 @@ 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 the site you're visiting 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.

View file

@ -100,7 +100,7 @@ See doxygen documentation of `IWritableStorage` interface for details about each
## Register a storage backend class
Each backend must be registered in the system when the plugin is installed, to be aviable.
Each backend must be registered in the system when the plugin is installed, to be available.
`DI::facStorage()->register(string $class)` is used to register the backend class.
@ -140,18 +140,18 @@ abstract class StorageTest
There are two intended types of exceptions for storages
### `ReferenceStorageExecption`
### `ReferenceStorageException`
This storage exception should be used in case the caller tries to use an invalid references.
This could happen in case the caller tries to delete or update an unknown reference.
The implementation of the storage backend must not ignore invalid references.
Avoid throwing the common `StorageExecption` instead of the `ReferenceStorageException` at this particular situation!
Avoid throwing the common `StorageException` instead of the `ReferenceStorageException` at this particular situation!
### `StorageException`
This is the common exception in case unexpected errors happen using the storage backend.
If there's a predecessor to this exception (e.g. you caught an exception and are throwing this execption), you should add the predecessor for transparency reasons.
If there's a predecessor to this exception (e.g. you caught an exception and are throwing this exception), you should add the predecessor for transparency reasons.
Example:
@ -320,7 +320,7 @@ The file is `addon/samplestorage/samplestorage.php`
<?php
/**
* Name: Sample Storage Addon
* Description: A sample addon which implements an unusefull storage backend
* Description: A sample addon which implements a very limited storage backend
* Version: 1.0.0
* Author: Alice <https://alice.social/~alice>
*/

View file

@ -44,7 +44,7 @@ Uninstalling an addon automatically unregisters any hook it registered, but if y
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".
Future extensions may provide for "setup" and "remove".
## PHP addon hooks
@ -60,25 +60,14 @@ This *should* be 'addon/*addon_name*/*addon_name*.php' in most cases and can be
`$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
Your hook callback functions will be called with at most one argument
function <addon>_<hookname>(App $a, &$b) {
function <addon>_<hookname>(&$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.
@ -88,7 +77,7 @@ Remember to declare it with `&` if you wish to alter it.
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.
Simply declare a `<addon>_addon_admin()` function to display the form and a `<addon>_addon_admin_post()` function to process the data from the form.0
## Global stylesheets
@ -102,7 +91,7 @@ function <addon>_install()
}
function <addon>_head(App $a)
function <addon>_head()
{
\Friendica\DI::page()->registerStylesheet(__DIR__ . '/relative/path/to/addon/stylesheet.css');
}
@ -124,7 +113,7 @@ function <addon>_install()
...
}
function <addon>_footer(App $a)
function <addon>_footer()
{
\Friendica\DI::page()->registerFooterScript(__DIR__ . '/relative/path/to/addon/script.js');
}
@ -135,7 +124,7 @@ function <addon>_footer(App $a)
### 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:
In your JavaScript file included as described above, add your event listener like this:
```js
document.addEventListener(name, callback);
@ -144,7 +133,7 @@ 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
More info about JavaScript event listeners: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
#### Current JavaScript hooks
@ -167,9 +156,9 @@ DI::args()->get(1); // = 'arg1'
DI::args()->get(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.
To display a module page, you need to declare the function `<addon>_content()`, which defines and returns the page body content.
They may also contain `<addon>_post()` which is called before the `<addon>_content` function and typically handles the results of POST forms.
You may also have `<addon>_init()` which is called before `<addon>_content` and should include common logic to your module.
## Templates
@ -209,7 +198,7 @@ Called when a user attempts to login.
### logged_in
Called after a user has successfully logged in.
`$b` contains the `$a->user` array.
`$b` contains the `App->user` array.
### display_item
Called when formatting a post for display.
@ -275,7 +264,7 @@ $data = [
##### With multiple submit buttons
```php
$data = [
'addon' => 'catavar',
'addon' => 'catavatar',
'title' => DI::l10n()->t('Cat Avatar Settings'),
'html' => $html,
'submit' => [
@ -360,7 +349,7 @@ Called prior to output of profile edit page.
### 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`.
The profile array details are in `App->profile`.
### directory_item
Called from the Directory page when formatting an item for display.
@ -413,7 +402,7 @@ Called prior to output of personal XRD file.
### home_content
Called prior to output home page content, shown to unlogged users.
`$b` is the HTML sring of section region.
`$b` is the HTML string of section region.
### contact_edit
Called when editing contact details on an individual from the Contacts page.
@ -436,7 +425,7 @@ Called after HTML content functions have completed.
### footer
Called after HTML content functions have completed.
Deferred Javascript files should be registered using this hook.
Deferred JavaScript files should be registered using this hook.
`$b` is (string) HTML of footer div/element.
### avatar_lookup

View file

@ -653,7 +653,7 @@ On Mastodon this field is used for the content warning.
<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>You can change all <span style="text-shadow: 0 0 4px #cc0000;;">the CSS properties of this inline text.</span></td>
You can change all the [style=text-shadow: 0 0 4px #CC0000;]CSS properties[/style] of this inline text.</td>
<td>You can change all the <span style="text-shadow: 0 0 4px #cc0000;;">CSS properties</span> of this inline text.</td>
</tr>
</table>

View file

@ -39,7 +39,7 @@ You can use several servers to create an account:
### 1. Basics
At first you have to get the current version. You can either pull it from [Github](https://github.com) like so:
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

View file

@ -20,7 +20,7 @@ Composer requires PHP CLI and the following examples assume it's available syste
#### 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.
If you just unpacked a Friendica release archive, you don't have to use Composer at all, all the required libraries are already bundled in the archive.
#### Installing with Git

View file

@ -250,7 +250,7 @@ key = value
<tr>
<td><pre>
[config]
register_policty = REGISTER_CLOSED
register_policy = REGISTER_CLOSED
</pre></td>
<td><pre>
'config' => [

View file

@ -47,7 +47,7 @@ function doSomething(\Friendica\Contact\Introductions\Collection\Introductions $
}
/** @var $intros \Friendica\Contact\Introductions\Collection\Introductions */
$intros = \Friendica\DI::intro()->selecForUser(Session::getLocalUser());
$intros = \Friendica\DI::intro()->selectForUser(Session::getLocalUser());
doSomething($intros);
```

View file

@ -95,7 +95,7 @@ Please remove all the `require_once` mentions of the former file, as they will p
## 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.
However, 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.

View file

@ -92,7 +92,7 @@ For documentation we use the standard of *one sentence per line* for the `md` fi
#### 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.
This tool checks your files against a variety of coding standards, including PSR-2, and outputs 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:
@ -109,7 +109,7 @@ 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.
If the command-line tools `diff` and `patch` are unavailable for you, `phpcbf` can use slightly slower PHP equivalents by using the `--no-patch` argument.
### Code documentation

View file

@ -42,7 +42,7 @@ Friendica Documentation and Resources
* [Get started](help/Developers-Intro)
* Set up development environment
* [Help on Github](help/Github)
* [Help on GitHub](help/GitHub)
* [Help on Vagrant](help/Vagrant)
* [Bugs and Issues](help/Bugs-and-Issues)
* Code structure
@ -69,7 +69,7 @@ Friendica Documentation and Resources
* Ways to get Support
* Friendica Support Forum: [@helpers@forum.friendi.ca](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``
* Community chat rooms (the IRC, Matrix and XMPP rooms are bridget) these public chats are logged [from IRC](https://gnusociarg.nsupdate.info/2021/%23friendica/) and [Matrix](https://view.matrix.org/alias/%23friendi.ca:matrix.org/)
* Community chat rooms (the IRC, Matrix and XMPP rooms are bridged) these public chats are logged [from IRC](https://gnusociarg.nsupdate.info/2021/%23friendica/) and [Matrix](https://view.matrix.org/alias/%23friendi.ca:matrix.org/)
* XMPP/Jabber MUC: support(at)forum.friendi.ca
* IRC: #friendica at [libera.chat](https://web.libera.chat/?channels=#friendica)
* Matrix: [#friendi.ca](https://matrix.to/#/#friendi.ca:matrix.org) or [#friendica-en](https://matrix.to/#/#friendica-en:matrix.org) at matrix.org

View file

@ -81,6 +81,6 @@ Please refer to external documentation for a more detailed explanation how to se
### 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.
There are scripts like [tuning-primer.sh](https://github.com/BMDan/tuning-primer.sh) and [mysqltuner.pl](https://github.com/major/MySQLTuner-perl/blob/master/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

@ -51,10 +51,13 @@ For alternative server configurations (such as Nginx server and MariaDB database
### 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
If this is nothing for you, you might be interested in the following:
* the [Friendica Docker image](https://github.com/friendica/docker) or
* how to [install Friendica with YunoHost](https://github.com/YunoHost-Apps/friendica_ynh).
* the [Friendica Docker image](https://github.com/friendica/docker)
* how to [install Friendica with YunoHost](https://github.com/YunoHost-Apps/friendica_ynh)
* [Tutorial: Creating a Friendica Server with Ubuntu 22.04](https://nequalsonelifestyle.com/2022/07/30/creating-friendica-server-ubuntu/)
* [Setting Up Friendica Daemon as a Systemd Service Tutorial](https://nequalsonelifestyle.com/2022/08/04/setting-up-friendica-daemon-systemd-service/)
* [Setting up Friendica on Unraid](https://www.jenovarain.com/2023/03/setting-up-friendica-on-unraid/) (NAS)
### Get Friendica
@ -228,7 +231,7 @@ Copy `.htaccess-dist` to `.htaccess` (be careful under Windows) to have working
Example:
cp .htacces-dist .htaccess
cp .htaccess-dist .htaccess
*Note*: Do **not** rename the `.htaccess-dist` file as it is tracked by GIT and renaming will cause a dirty working directory.
@ -350,7 +353,7 @@ Often this will need to be resolved with your hosting provider or (if self-hoste
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
Ensure that mod-rewrite 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
@ -463,9 +466,11 @@ After that, restart mysql and try again.
### Your worker never or rarely runs
Friendica is coded to always play nice. It checks whether the host machine is idle enough and if it _seems_ to be overloaded, it intermittently refuses to process the worker queue.
Friendica is coded to always play nice.
It checks whether the host machine is idle enough and if it _seems_ to be overloaded, it intermittently refuses to process the worker queue.
Such checks originate from the days of single-user single-core machines and involves thresholds that you should adjust based on the number of exclusive CPU cores you have. See this issue for more information:
Such checks originate from the days of single-user single-core machines and involves thresholds that you should adjust based on the number of exclusive CPU cores you have.
See this issue for more information:
* https://github.com/friendica/friendica/issues/10131
@ -482,28 +487,40 @@ You tried to upload an image up to 100kB and it failed.
You may not have the ownership or file mode set correctly if you are using the file system storage backend.
Change the backend to database. If this solves it, that is what needs to be fixed.
Change the backend to database.
If this solves it, that is what needs to be fixed.
Verify in your PHP ini:
* `file_uploads`: should be `1`
* `upload_tmp_dir`: should be writable (falls back to system default temp) and not blocked by `open_basedir`
### Error uploading large files
You may find `413 Request Entity Too Large` or `500 Internal Error` in the network inspector of the browser if the file is too large, for example if it is a video.
First try to upload a very small file, up to 100kB. If that succeeds, you will need to increase limits at multiple places, including on any web proxy that you are using.
First try to upload a very small file, up to 100kB.
If that succeeds, you will need to increase limits at multiple places, including on any web proxy that you are using.
Which one applies to you depends on your installation.
In your PHP ini:
* `upload_max_filesize`: defaults to 2MB
* `post_max_size`: defaults to 8MB, must be greater than `upload_max_filesize`
* `memory_limit`: defaults to 128MB, must be greater than `post_max_size`
* `max_input_time`: time limit of an upload, defaults to -1, meaning it uses `max_execution_time` instead
* `max_execution_time`: defaults to 30 seconds, should be enough if you also set `max_input_time`
You should verify whether you changed them in the _right file_ by checking the web interface at the end of the overview on the `Admin` panel.
For Apache2:
In your Apache2 config:
* `LimitRequestBody`: defaults to unlimited
* `FcgidMaxRequestLen`: defaults to 128kB
* `SSLRenegBufferSize`: defaults to 128kB, only if your site uses TLS and perhaps only when using `SSLVerifyClient` or `SSLVerifyDepth`
* Remove `LoadModule reqtimeout_module modules / mod_reqtimeout.so` or adjust `RequestReadTimeout`: defaults to 20 seconds and >= 500 byte/second
For nginx:
In your nginx config:
* `client_max_body_size`: defaults to 1MB
@ -511,7 +528,28 @@ If you are using the database backend for storage, increase this in your SQL con
* `max_allowed_packet`: defaults to 32MB
If you use the ModSecurity WAF:
In your ModSecurity WAF config:
* `SecRequestBodyLimit`: defaults to 12MB
* `SecRequestBodyNoFilesLimit`: defaults to 128kB, should not apply to Friendica
In the end, you will need to restart all services that you have changed configuration for.
If you don't know which ones these are, just reboot.
### Diaspora support is not activated
You get this error when you try to add a Diaspora contact.
You can enable it from the web interface in `Admin -> Site -> Policies -> Enable diaspora* support`.
You may also set it manually in the config file or in the database within the `diaspora_enabled` key of the `system` category.
### Upgrade failed due to DB migration timeout
Altering of a table may fail if it contains a large number of rows.
First verify the existing timeout (50s by default):
`show global variables like "innodb_lock_wait_timeout";`
Then increase it:
`set global innodb_lock_wait_timeout=600;`

View file

@ -50,12 +50,12 @@ 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.
### Across the Federation and Fediverse
You can also use your Identity Address or other people's Identity Addresses to become friends across the so-called Federation/Fediverse 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.
Likewise 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.
@ -74,7 +74,7 @@ Create an email contact with for example Alice on Gmail, enter her email in foll
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".
To subscribe to a mailing list, enter the email in following example format "mailing-list@list-server.net".
### Syndication feeds
You can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.).

View file

@ -19,7 +19,7 @@ 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.
If your contacts are running on an updated server, your details on their side will be automatically updated.
GNU Social contacts
---

View file

@ -4,7 +4,7 @@ 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.
It's where all your status messages 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.

View file

@ -104,12 +104,12 @@ Default is false.
#### File storage backend
Set the backend used by Friendica to store uploaded file data.
Two storage backends are avaiable with Friendica:
Two storage backends are available 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.
More storage backends can be available 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.

View file

@ -52,5 +52,5 @@ The same rules apply as with names that spaces within tags are represented by th
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.
If you wish to use a numeric hashtag, please add some descriptive text such as #2012-elections.

View file

@ -13,7 +13,7 @@ If 2FA is already enabled and you want to add another device, you must re-config
### 1. Download an authenticator app
Any authenticator app should work with Friendica.
Notheless, we recommend:
Nonetheless, we recommend:
- For iOS, [Matt Rubin's MIT-licensed Authenticator app](https://mattrubin.me/authenticator).
- For Android, [andOTP](https://github.com/andOTP/andOTP).
@ -68,7 +68,7 @@ Instead, if you enabled two-factor authentication, you have to generate app-spec
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").
We recommend generating a single app-specific password for each separate third-party app you are using, using a meaningful 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

@ -31,7 +31,7 @@ The mysql database is called "friendica", the mysql user and password both are "
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.
Find the Friendica log file `/vagrant/logfile.out` on the VM or in the `logfile.out` in you local Friendica directory.
8. Commit and push your changes directly back to Github.
8. Commit and push your changes directly back to GitHub.
If you want to stop vagrant after finishing your work, run the following command

View file

@ -10,7 +10,6 @@ Database Tables
| [2fa_trusted_browser](help/database/db_2fa_trusted_browser) | Two-factor authentication trusted browsers |
| [account-suggestion](help/database/db_account-suggestion) | Account suggestion |
| [account-user](help/database/db_account-user) | Remote and local accounts |
| [addon](help/database/db_addon) | registered addons |
| [apcontact](help/database/db_apcontact) | ActivityPub compatible contacts - used in the ActivityPub implementation |
| [application](help/database/db_application) | OAuth application |
| [application-marker](help/database/db_application-marker) | Timeline marker |
@ -23,6 +22,7 @@ Database Tables
| [contact-relation](help/database/db_contact-relation) | Contact relations |
| [conv](help/database/db_conv) | private messages |
| [delayed-post](help/database/db_delayed-post) | Posts that are about to be distributed at a later time |
| [delivery-queue](help/database/db_delivery-queue) | Delivery data for posts for the batch processing |
| [diaspora-contact](help/database/db_diaspora-contact) | Diaspora compatible contacts - used in the Diaspora implementation |
| [diaspora-interaction](help/database/db_diaspora-interaction) | Signed Diaspora Interaction |
| [endpoint](help/database/db_endpoint) | ActivityPub endpoints - used in the ActivityPub implementation |
@ -40,6 +40,7 @@ Database Tables
| [inbox-status](help/database/db_inbox-status) | Status of ActivityPub inboxes |
| [intro](help/database/db_intro) | |
| [item-uri](help/database/db_item-uri) | URI and GUID for items |
| [key-value](help/database/db_key-value) | A key value storage |
| [locks](help/database/db_locks) | |
| [mail](help/database/db_mail) | private messages |
| [mailacct](help/database/db_mailacct) | Mail account data for fetching mails |

View file

@ -1,29 +0,0 @@
Table addon
===========
registered addons
Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| ------------ | --------------------------------------------- | ------------ | ---- | --- | ------- | -------------- |
| id | | int unsigned | NO | PRI | NULL | auto_increment |
| name | addon base (file)name | varchar(50) | NO | | | |
| version | currently unused | varchar(50) | NO | | | |
| installed | currently always 1 | boolean | NO | | 0 | |
| hidden | currently unused | boolean | NO | | 0 | |
| timestamp | file timestamp to check for reloads | int unsigned | NO | | 0 | |
| plugin_admin | 1 = has admin config, 0 = has no admin config | boolean | NO | | 0 | |
Indexes
------------
| Name | Fields |
| -------------- | --------------- |
| PRIMARY | id |
| installed_name | installed, name |
| name | UNIQUE, name |
Return to [database documentation](help/database)

View file

@ -7,10 +7,10 @@ Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| ----- | ----------- | ------------- | ---- | --- | ------- | -------------- |
| ----- | ------------------------- | ------------- | ---- | --- | ------- | -------------- |
| id | | int unsigned | NO | PRI | NULL | auto_increment |
| cat | | varbinary(50) | NO | | | |
| k | | varbinary(50) | NO | | | |
| cat | The category of the entry | varbinary(50) | NO | | | |
| k | The key of the entry | varbinary(50) | NO | | | |
| v | | mediumtext | YES | | NULL | |
Indexes

View file

@ -0,0 +1,39 @@
Table delivery-queue
===========
Delivery data for posts for the batch processing
Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| ------- | --------------------------------------- | ------------------ | ---- | --- | ------- | ----- |
| gsid | Target server | int unsigned | NO | PRI | NULL | |
| uri-id | Delivered post | int unsigned | NO | PRI | NULL | |
| created | | datetime | YES | | NULL | |
| command | | varbinary(32) | YES | | NULL | |
| cid | Target contact | int unsigned | YES | | NULL | |
| uid | Delivering user | mediumint unsigned | YES | | NULL | |
| failed | Number of times the delivery has failed | tinyint | YES | | 0 | |
Indexes
------------
| Name | Fields |
| ------------ | ------------- |
| PRIMARY | uri-id, gsid |
| gsid_created | gsid, created |
| uid | uid |
| cid | cid |
Foreign Keys
------------
| Field | Target Table | Target Field |
|-------|--------------|--------------|
| gsid | [gserver](help/database/db_gserver) | id |
| uri-id | [item-uri](help/database/db_item-uri) | id |
| cid | [contact](help/database/db_contact) | id |
| uid | [user](help/database/db_user) | uid |
Return to [database documentation](help/database)

View file

@ -27,7 +27,7 @@ Fields
| gsid | Global Server ID | int unsigned | YES | | NULL | |
| created | | datetime | NO | | 0001-01-01 00:00:00 | |
| updated | | datetime | NO | | 0001-01-01 00:00:00 | |
| interacting_count | Number of contacts this contact interactes with | int unsigned | YES | | 0 | |
| interacting_count | Number of contacts this contact interacts with | int unsigned | YES | | 0 | |
| interacted_count | Number of contacts that interacted with this contact | int unsigned | YES | | 0 | |
| post_count | Number of posts and comments | int unsigned | YES | | 0 | |

View file

@ -34,6 +34,7 @@ Fields
| last_poco_query | | datetime | YES | | 0001-01-01 00:00:00 | |
| last_contact | Last successful connection request | datetime | YES | | 0001-01-01 00:00:00 | |
| last_failure | Last failed connection request | datetime | YES | | 0001-01-01 00:00:00 | |
| blocked | Server is blocked | boolean | YES | | NULL | |
| failed | Connection failed | boolean | YES | | NULL | |
| next_contact | Next connection request | datetime | YES | | 0001-01-01 00:00:00 | |

View file

@ -10,6 +10,7 @@ Fields
| -------- | ------------------------------------ | -------------- | ---- | --- | ------------------- | ----- |
| url | URL of the inbox | varbinary(383) | NO | PRI | NULL | |
| uri-id | Item-uri id of inbox url | int unsigned | YES | | NULL | |
| gsid | ID of the related server | int unsigned | YES | | NULL | |
| created | Creation date of this entry | datetime | NO | | 0001-01-01 00:00:00 | |
| success | Date of the last successful delivery | datetime | NO | | 0001-01-01 00:00:00 | |
| failure | Date of the last failed delivery | datetime | NO | | 0001-01-01 00:00:00 | |
@ -24,6 +25,7 @@ Indexes
| ------- | ------ |
| PRIMARY | url |
| uri-id | uri-id |
| gsid | gsid |
Foreign Keys
------------
@ -31,5 +33,6 @@ Foreign Keys
| Field | Target Table | Target Field |
|-------|--------------|--------------|
| uri-id | [item-uri](help/database/db_item-uri) | id |
| gsid | [gserver](help/database/db_gserver) | id |
Return to [database documentation](help/database)

View file

@ -0,0 +1,23 @@
Table key-value
===========
A key value storage
Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| ---------- | ---------------------------- | ------------- | ---- | --- | ------- | ----- |
| k | | varbinary(50) | NO | PRI | NULL | |
| v | | mediumtext | YES | | NULL | |
| updated_at | timestamp of the last update | int unsigned | NO | | NULL | |
Indexes
------------
| Name | Fields |
| ------- | ------ |
| PRIMARY | k |
Return to [database documentation](help/database)

View file

@ -13,7 +13,7 @@ Fields
| guid | A unique identifier for this private message | varbinary(255) | NO | | | |
| from-name | name of the sender | varchar(255) | NO | | | |
| from-photo | contact photo link of the sender | varbinary(383) | NO | | | |
| from-url | profile linke of the sender | varbinary(383) | NO | | | |
| from-url | profile link of the sender | varbinary(383) | NO | | | |
| contact-id | contact.id | varbinary(255) | YES | | NULL | |
| author-id | Link to the contact table with uid=0 of the author of the mail | int unsigned | YES | | NULL | |
| convid | conv.id | int unsigned | YES | | NULL | |

View file

@ -34,7 +34,7 @@ Fields
| event-id | Used to link to the event.id | int unsigned | YES | | NULL | |
| unseen | post has not been seen | boolean | NO | | 1 | |
| hidden | Marker to hide the post from the user | boolean | NO | | 0 | |
| notification-type | | tinyint unsigned | NO | | 0 | |
| notification-type | | smallint unsigned | NO | | 0 | |
| wall | This item was posted to the wall of uid | boolean | NO | | 0 | |
| origin | item originated at this site | boolean | NO | | 0 | |
| psid | ID of the permission set of this post | int unsigned | YES | | NULL | |

View file

@ -9,7 +9,7 @@ Fields
| Field | Description | Type | Null | Key | Default | Extra |
| -------- | ------------------------------------------ | ------------- | ---- | --- | ------------------- | ----- |
| pid | The ID of the process | int unsigned | NO | PRI | NULL | |
| hostname | The name of the host the process is ran on | varchar(32) | NO | PRI | NULL | |
| hostname | The name of the host the process is ran on | varchar(255) | NO | PRI | NULL | |
| command | | varbinary(32) | NO | | | |
| created | | datetime | NO | | 0001-01-01 00:00:00 | |

View file

@ -7,11 +7,14 @@ Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| ------- | --------------------------------------- | ------------------ | ---- | --- | ------------------- | -------------- |
| ----------- | ----------------------------------------------- | ------------------ | ---- | --- | ------------------- | -------------- |
| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment |
| uid | Reporting user | mediumint unsigned | YES | | NULL | |
| reporter-id | Reporting contact | int unsigned | YES | | NULL | |
| cid | Reported contact | int unsigned | NO | | NULL | |
| comment | Report | text | YES | | NULL | |
| category | Category of the report (spam, violation, other) | varchar(20) | YES | | NULL | |
| rules | Violated rules | text | YES | | NULL | |
| forward | Forward the report to the remote server | boolean | YES | | NULL | |
| created | | datetime | NO | | 0001-01-01 00:00:00 | |
| status | Status of the report | tinyint unsigned | YES | | NULL | |
@ -20,10 +23,11 @@ Indexes
------------
| Name | Fields |
| ------- | ------ |
| ----------- | ----------- |
| PRIMARY | id |
| uid | uid |
| cid | cid |
| reporter-id | reporter-id |
Foreign Keys
------------
@ -31,6 +35,7 @@ Foreign Keys
| Field | Target Table | Target Field |
|-------|--------------|--------------|
| uid | [user](help/database/db_user) | uid |
| reporter-id | [contact](help/database/db_contact) | id |
| cid | [contact](help/database/db_contact) | id |
Return to [database documentation](help/database)

View file

@ -32,7 +32,7 @@ Fields
| verified | user is verified through email | boolean | NO | | 0 | |
| blocked | 1 for user is blocked | boolean | NO | | 0 | |
| blockwall | Prohibit contacts to post to the profile page of the user | boolean | NO | | 0 | |
| hidewall | Hide profile details from unkown viewers | boolean | NO | | 0 | |
| hidewall | Hide profile details from unknown viewers | boolean | NO | | 0 | |
| blocktags | Prohibit contacts to tag the post of this user | boolean | NO | | 0 | |
| unkmail | Permit unknown people to send private mails to this user | boolean | NO | | 0 | |
| cntunkmail | | int unsigned | NO | | 10 | |

View file

@ -38,17 +38,14 @@ $function ist ein String und der Name der Funktion, die ausgeführt wird, wenn d
Argumente
---
Deine Hook-Callback-Funktion wird mit mindestens einem und bis zu zwei Argumenten aufgerufen
Deine Hook-Callback-Funktion wird mit höchstens einem Argumenten aufgerufen
function myhook_function(App $a, &$b) {
function myhook_function(&$b) {
}
Wenn du Änderungen an den aufgerufenen Daten vornehmen willst, musst du diese als Referenzvariable (mit "&") während der Funktionsdeklaration deklarieren.
$a ist die Friendica "App"-Klasse, die eine Menge an Informationen über den aktuellen Friendica-Status beinhaltet, u.a. welche Module genutzt werden, Konfigurationsinformationen, Inhalte der Seite zum Zeitpunkt des Hook-Aufrufs.
Es ist empfohlen, diese Funktion "$a" zu nennen, um seine Nutzung an den Gebrauch an anderer Stelle anzugleichen.
$b kann frei benannt werden.
Diese Information ist speziell auf den Hook bezogen, der aktuell bearbeitet wird, und beinhaltet normalerweise Daten, die du sofort nutzen, anzeigen oder bearbeiten kannst.
Achte darauf, diese mit "&" zu deklarieren, wenn du sie bearbeiten willst.
@ -70,9 +67,9 @@ DI::args()->get(1); // = 'arg1'
DI::args()->get(2); // = 'arg2'
```
Deine Modulfunktionen umfassen oft die Funktion addon_name_content(App $a), welche den Seiteninhalt definiert und zurückgibt.
Sie können auch addon_name_post(App $a) umfassen, welches vor der content-Funktion aufgerufen wird und normalerweise die Resultate der POST-Formulare handhabt.
Du kannst ebenso addon_name_init(App $a) nutzen, was oft frühzeitig aufgerufen wird und das Modul initialisert.
Deine Modulfunktionen umfassen oft die Funktion `addon_name_content()`, welche den Seiteninhalt definiert und zurückgibt.
Sie können auch `addon_name_post()` umfassen, welches vor der content-Funktion aufgerufen wird und normalerweise die Resultate der POST-Formulare handhabt.
Du kannst ebenso `addon_name_init()` nutzen, was oft frühzeitig aufgerufen wird und das Modul initialisert.
Derzeitige Hooks
@ -86,7 +83,7 @@ Derzeitige Hooks
'user_record' => die erfolgreiche Authentifizierung muss auch einen gültigen Nutzereintrag aus der Datenbank zurückgeben
**'logged_in'** - wird aufgerufen, sobald ein Nutzer sich erfolgreich angemeldet hat.
$b beinhaltet den $a->Nutzer-Array
$b beinhaltet den `App->user`
**'display_item'** - wird aufgerufen, wenn ein Beitrag für die Anzeige formatiert wird.
@ -122,7 +119,7 @@ Derzeitige Hooks
**'profile_advanced'** - wird aufgerufen, wenn die HTML-Ausgabe für das "Advanced profile" generiert wird; stimmt mit dem "Profil"-Tab auf der Profilseite der Nutzer überein.
$b ist die HTML-Ausgabe (String) des erstellten Profils
(Die Details des Profil-Arrays sind in $a->profile)
(Die Details des Profil-Arrays sind in `App->profile`)
**'directory_item'** - wird von der Verzeichnisseite aufgerufen, wenn ein Item für die Anzeige formatiert wird.
$b ist ein Array

View file

@ -612,8 +612,8 @@ Dieses Feld wird von Mastodon f&uuml;r die Inhaltswarnung (content warning) verw
<tr>
<td>Benutzerdefinierte Inline-Styles<br>
<br>
[style=text-shadow: 0 0 4px #CC0000;]Du kannst alle CSS-Eigenschaften eines Blocks &auml;ndern-[/style]</td>
<td>Du kannst alle <span style="text-shadow: 0 0 4px #cc0000;;">CSS-Eigenschaften dieses Inline-Textes &auml;ndern-</span></td>
Du kannst alle [style=text-shadow: 0 0 4px #CC0000;]CSS-Eigenschaften[/style] dieses Inline-Textes &auml;ndern-</td>
<td>Du kannst alle <span style="text-shadow: 0 0 4px #cc0000;;">CSS-Eigenschaften</span> dieses Inline-Textes &auml;ndern-</td>
</tr>
</table>

View file

@ -27,7 +27,7 @@ Der Quellcode von Friendica Red ist [hier](https://github.com/friendica/red) zu
Addons findest Du auf [dieser Seite](https://github.com/friendica/friendica-addons).
Wenn Du neue Themen suchst, findest Du sie auf [Friendica-Themes.com](http://friendica-themes.com/).
Wenn Du neue Themen suchst, findest Du sie auf [github.com/bkil/friendica-themes](https://github.com/bkil/friendica-themes).
<a name="adminaccount1"></a>
### Ich habe meine E-Mail Adresse geändern und jetzt ist das Admin Panel verschwunden?

View file

@ -95,6 +95,6 @@ Nutze externe Dokumente, um eine detailiertere Erklärung für die Einrichtung e
### Database
Es gibt Skripte wie [tuning-primer.sh](http://www.day32.com/MySQL/) und [mysqltuner.pl](http://mysqltuner.pl), die den Datenbankserver analysieren und Hinweise darauf geben, welche Werte verändert werden könnten.
Es gibt Skripte wie [tuning-primer.sh](https://github.com/BMDan/tuning-primer.sh) und [mysqltuner.pl](https://github.com/major/MySQLTuner-perl/blob/master/mysqltuner.pl), die den Datenbankserver analysieren und Hinweise darauf geben, welche Werte verändert werden könnten.
Aktivere hierfür die "Slow query" Log-Datei, um Performanceprobleme zu erkennen.

View file

@ -9,7 +9,7 @@ Depending on the theme you are using, there might be an additional link from the
## Event Overview
The overview page shows the calendar of the current month, plus a few days days at the beginning and the end.
The overview page shows the calendar of the current month, plus a few days at the beginning and the end.
Listed are all events for this month, created by you, or shared with you by your contacts,
This includes birthday reminders for contacts who share their birthday with you.

View file

@ -37,7 +37,7 @@ Form Templates
To guarantee a consistent look and feel for input forms, i.e. in the settings sections, there are templates for the basic form fields.
They are initialized with an array of data, depending on the tyle of the field.
All of these take an array holding the values, e.g. for a one line text input field, which is required and should be used to type email addesses use something along the lines of:
All of these take an array holding the values, e.g. for a one line text input field, which is required and should be used to type email addresses use something along the lines of:
'$adminmail' => array('adminmail', DI::l10n()->t('Site administrator email address'), $adminmail, DI::l10n()->t('Your account email address must match this in order to use the web admin panel.'), 'required', '', 'email'),
@ -70,7 +70,7 @@ Field parameter:
### field_custom.tpl
A customizeable template to include a custom element in the form with the usual surroundings,
A customizable template to include a custom element in the form with the usual surroundings,
Field parameter:
0. Name of the field,
@ -88,7 +88,7 @@ Field parameter:
2. Current value of the variable,
3. Help text for the input box,
4. Should be set to the translation of "Required" to mark this field as required,
5. if set to "autofocus" modern browser will put the cursur into this box once the page is loaded,
5. if set to "autofocus" modern browser will put the cursor into this box once the page is loaded,
6. if set, it will be used for the input type, default is `text` (possible types: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#%3Cinput%3E_types).
### field_intcheckbox.tpl

View file

@ -12,7 +12,7 @@ So, how to work on the UI of friendica.
You can either directly edit an existing theme.
But you might loose your changes when the theme is updated by the friendica team.
If you are almost happy with an existing theme, the easiest way to cover your needs is to create a new theme, inheritating most of the properties of the parent theme and change just minor stuff.
If you are almost happy with an existing theme, the easiest way to cover your needs is to create a new theme, inheriting most of the properties of the parent theme and change just minor stuff.
The below for a more detailed description of theme heritage.
Some themes also allow users to select *variants* of the theme.
@ -33,7 +33,7 @@ In most cases, you can found these in
/view/theme/**your-theme-name**/style.css
sometimes, there is also a file called style.php in the theme directory.
This is only needed if the theme allowes the user to change certain things of the theme dynamically.
This is only needed if the theme allows the user to change certain things of the theme dynamically.
Say the font size or set a background image.
### Templates
@ -50,7 +50,7 @@ if you want to override any template within your theme create your version of th
any template that exists there will be used instead of the default one.
### Javascript
### JavaScript
The same rule applies to the JavaScript files found in

View file

@ -51,7 +51,7 @@ In */etc/fail2ban/jail.local* create a section for Friendica:
bantime = 900
filter = friendica
port = http,https
logpath = /var/log/friend.log
logpath = /var/log/friendica.log
logencoding = utf-8
And create a filter definition in */etc/fail2ban/filter.d/friendica.conf*:

View file

@ -7,7 +7,7 @@ Friendica translations
The Friendica translation process is based on `gettext` PO files.
Basic worflow:
Basic workflow:
1. `xgettext` is used to collect translation strings across the project in the authoritative PO file located in `view/lang/C/messages.po`.
2. This file makes translations strings available at [the Transifex Friendica page](https://www.transifex.com/Friendica/friendica/dashboard/).
3. The translation itself is done at Transifex by volunteers.
@ -24,6 +24,16 @@ For addons, we add support for a language when if we already support the languag
## Add new translation strings
### Supported gettext version
We currently support the gettext version 0.19.8.1 and actively check new translation strings with this version.
If you don't use this version, it's possible that our checks fail (f.e. because of tiny differences at linebreaks).
In case you do have a Docker environment, you can easily update the translations with the following command:
```shell
docker run --rm -v $PWD:/data -w /data friendicaci/transifex bin/run_xgettext.sh
```
### Core
Once you have added new translation strings in your code changes, please run `bin/run_xgettext.sh` from the base Friendica directory and commit the updated `view/lang/C/messages.po` to your branch.

View file

@ -10,4 +10,3 @@
<directory>.</directory>
</files>
</docblox>

View file

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

View file

Before

Width:  |  Height:  |  Size: 408 KiB

After

Width:  |  Height:  |  Size: 408 KiB

View file

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View file

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View file

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View file

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

View file

Before

Width:  |  Height:  |  Size: 498 KiB

After

Width:  |  Height:  |  Size: 498 KiB

View file

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -45,6 +45,9 @@ $a->runFrontend(
$dice->create(\Friendica\Core\PConfig\Capability\IManagePersonalConfigValues::class),
$dice->create(\Friendica\Security\Authentication::class),
$dice->create(\Friendica\App\Page::class),
$dice->create(\Friendica\Content\Nav::class),
$dice->create(Friendica\Module\Special\HTTPException::class),
new \Friendica\Util\HTTPInputData($_SERVER),
$start_time
$start_time,
$_SERVER
);

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -19,7 +19,7 @@
*
* This is the POST destination for most all locally posted
* text stuff. This function handles status, wall-to-wall status,
* local comments, and remote coments that are posted on this site
* local comments, and remote comments that are posted on this site
* (as opposed to being delivered in a feed).
* Also processed here are posts and comments coming through the
* statusnet/twitter API.
@ -29,7 +29,7 @@
*/
use Friendica\App;
use Friendica\Content\PageInfo;
use Friendica\Content\Conversation;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
@ -38,45 +38,26 @@ use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Attach;
use Friendica\Model\Contact;
use Friendica\Model\Conversation;
use Friendica\Model\FileTag;
use Friendica\Model\Item;
use Friendica\Model\ItemURI;
use Friendica\Model\Notification;
use Friendica\Model\Photo;
use Friendica\Model\Post;
use Friendica\Model\Tag;
use Friendica\Model\User;
use Friendica\Network\HTTPException;
use Friendica\Object\EMail\ItemCCEMail;
use Friendica\Protocol\Activity;
use Friendica\Security\Security;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\ParseUrl;
function item_post(App $a) {
if (!DI::userSession()->isAuthenticated()) {
$uid = DI::userSession()->getLocalUserId();
if (!$uid) {
throw new HTTPException\ForbiddenException();
}
$uid = DI::userSession()->getLocalUserId();
if (!empty($_REQUEST['dropitems'])) {
$arr_drop = explode(',', $_REQUEST['dropitems']);
foreach ($arr_drop as $item) {
Item::deleteForUser(['id' => $item], $uid);
}
$json = ['success' => 1];
System::jsonExit($json);
item_drop($uid, $_REQUEST['dropitems']);
}
Hook::callAll('post_local_start', $_REQUEST);
Logger::debug('postvars', ['_REQUEST' => $_REQUEST]);
$return_path = $_REQUEST['return'] ?? '';
$preview = intval($_REQUEST['preview'] ?? 0);
@ -86,585 +67,69 @@ function item_post(App $a) {
* after it's been previewed
*/
if (!$preview && !empty($_REQUEST['post_id_random'])) {
if (!empty($_SESSION['post-random']) && $_SESSION['post-random'] == $_REQUEST['post_id_random']) {
if (DI::session()->get('post-random') == $_REQUEST['post_id_random']) {
Logger::warning('duplicate post');
item_post_return(DI::baseUrl(), $return_path);
} else {
$_SESSION['post-random'] = $_REQUEST['post_id_random'];
DI::session()->set('post-random', $_REQUEST['post_id_random']);
}
}
// Is this a reply to something?
$parent_item_id = intval($_REQUEST['parent'] ?? 0);
$thr_parent_uri = trim($_REQUEST['parent_uri'] ?? '');
$parent_item = null;
$toplevel_item = null;
$toplevel_item_id = 0;
$toplevel_user_id = null;
$objecttype = null;
$profile_uid = DI::userSession()->getLocalUserId();
$posttype = ($_REQUEST['post_type'] ?? '') ?: Item::PT_ARTICLE;
if ($parent_item_id || $thr_parent_uri) {
if ($parent_item_id) {
$parent_item = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $parent_item_id]);
} elseif ($thr_parent_uri) {
$parent_item = Post::selectFirst(Item::ITEM_FIELDLIST, ['uri' => $thr_parent_uri, 'uid' => $profile_uid]);
}
// if this isn't the top-level parent of the conversation, find it
if (DBA::isResult($parent_item)) {
// The URI and the contact is taken from the direct parent which needn't to be the top parent
$thr_parent_uri = $parent_item['uri'];
$toplevel_item = $parent_item;
if ($parent_item['gravity'] != Item::GRAVITY_PARENT) {
$toplevel_item = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $toplevel_item['parent']]);
if (empty($_REQUEST['post_id'])) {
item_insert($uid, $_REQUEST, $preview, $return_path);
} else {
item_edit($uid, $_REQUEST, $preview, $return_path);
}
}
if (!DBA::isResult($toplevel_item)) {
DI::sysmsg()->addNotice(DI::l10n()->t('Unable to locate original post.'));
function item_drop(int $uid, string $dropitems)
{
$arr_drop = explode(',', $dropitems);
foreach ($arr_drop as $item) {
Item::deleteForUser(['id' => $item], $uid);
}
System::jsonExit(['success' => 1]);
}
function item_edit(int $uid, array $request, bool $preview, string $return_path)
{
$post = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $request['post_id'], 'uid' => $uid]);
if (!DBA::isResult($post)) {
if ($return_path) {
DI::sysmsg()->addNotice(DI::l10n()->t('Unable to locate original post.'));
DI::baseUrl()->redirect($return_path);
}
throw new HTTPException\NotFoundException(DI::l10n()->t('Unable to locate original post.'));
}
// When commenting on a public post then store the post for the current user
// This enables interaction like starring and saving into folders
if ($toplevel_item['uid'] == 0) {
$stored = Item::storeForUserByUriId($toplevel_item['uri-id'], DI::userSession()->getLocalUserId(), ['post-reason' => Item::PR_ACTIVITY]);
Logger::info('Public item stored for user', ['uri-id' => $toplevel_item['uri-id'], 'uid' => $uid, 'stored' => $stored]);
if ($stored) {
$toplevel_item = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $stored]);
}
}
$post['edit'] = $post;
$post['file'] = Post\Category::getTextByURIId($post['uri-id'], $post['uid']);
$toplevel_item_id = $toplevel_item['id'];
$toplevel_user_id = $toplevel_item['uid'];
Post\Media::deleteByURIId($post['uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE, Post\Media::HTML]);
$post = item_process($post, $request, $preview, $return_path);
$objecttype = Activity\ObjectType::COMMENT;
}
if ($toplevel_item_id) {
Logger::info('mod_item: item_post', ['parent' => $toplevel_item_id]);
}
$post_id = intval($_REQUEST['post_id'] ?? 0);
$app = strip_tags($_REQUEST['source'] ?? '');
$extid = strip_tags($_REQUEST['extid'] ?? '');
$object = $_REQUEST['object'] ?? '';
// Don't use "defaults" here. It would turn 0 to 1
if (!isset($_REQUEST['wall'])) {
$wall = 1;
} else {
$wall = $_REQUEST['wall'];
}
// Ensure that the user id in a thread always stay the same
if (!is_null($toplevel_user_id) && in_array($toplevel_user_id, [DI::userSession()->getLocalUserId(), 0])) {
$profile_uid = $toplevel_user_id;
}
// Allow commenting if it is an answer to a public post
$allow_comment = DI::userSession()->getLocalUserId() && $toplevel_item_id && in_array($toplevel_item['private'], [Item::PUBLIC, Item::UNLISTED]) && in_array($toplevel_item['network'], Protocol::FEDERATED);
// Now check that valid personal details have been provided
if (!Security::canWriteToUserWall($profile_uid) && !$allow_comment) {
Logger::warning('Permission denied.', ['local' => DI::userSession()->getLocalUserId(), 'toplevel_item_id' => $toplevel_item_id, 'network' => $toplevel_item['network']]);
DI::sysmsg()->addNotice(DI::l10n()->t('Permission denied.'));
if ($return_path) {
DI::baseUrl()->redirect($return_path);
}
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.'));
}
// Init post instance
$orig_post = null;
// is this an edited post?
if ($post_id > 0) {
$orig_post = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]);
}
$user = User::getById($profile_uid, ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']);
if (!DBA::isResult($user) && !$toplevel_item_id) {
return 0;
}
$categories = '';
$postopts = '';
$emailcc = '';
$body = $_REQUEST['body'] ?? '';
$has_attachment = $_REQUEST['has_attachment'] ?? 0;
// If we have a speparate attachment, we need to add it to the body.
if (!empty($has_attachment)) {
$attachment_type = $_REQUEST['attachment_type'] ?? '';
$attachment_title = $_REQUEST['attachment_title'] ?? '';
$attachment_text = $_REQUEST['attachment_text'] ?? '';
$attachment_url = hex2bin($_REQUEST['attachment_url'] ?? '');
$attachment_img_src = hex2bin($_REQUEST['attachment_img_src'] ?? '');
$attachment_img_width = $_REQUEST['attachment_img_width'] ?? 0;
$attachment_img_height = $_REQUEST['attachment_img_height'] ?? 0;
// Fetch the basic attachment data
$attachment = ParseUrl::getSiteinfoCached($attachment_url);
unset($attachment['keywords']);
// Overwrite the basic data with possible changes from the frontend
$attachment['type'] = $attachment_type;
$attachment['title'] = $attachment_title;
$attachment['text'] = $attachment_text;
$attachment['url'] = $attachment_url;
if (!empty($attachment_img_src)) {
$attachment['images'] = [
0 => [
'src' => $attachment_img_src,
'width' => $attachment_img_width,
'height' => $attachment_img_height
]
];
} else {
unset($attachment['images']);
}
$att_bbcode = "\n" . PageInfo::getFooterFromData($attachment);
$body .= $att_bbcode;
} elseif (preg_match("/\[attachment\](.*?)\[\/attachment\]/ism", $body, $matches)) {
$body = preg_replace("/\[attachment].*?\[\/attachment\]/ism", PageInfo::getFooterFromUrl($matches[1]), $body);
}
// Convert links with empty descriptions to links without an explicit description
$body = preg_replace('#\[url=([^\]]*?)\]\[/url\]#ism', '[url]$1[/url]', $body);
if (!empty($orig_post)) {
$str_group_allow = $orig_post['allow_gid'];
$str_contact_allow = $orig_post['allow_cid'];
$str_group_deny = $orig_post['deny_gid'];
$str_contact_deny = $orig_post['deny_cid'];
$location = $orig_post['location'];
$coord = $orig_post['coord'];
$verb = $orig_post['verb'];
$objecttype = $orig_post['object-type'];
$app = $orig_post['app'];
$categories = Post\Category::getTextByURIId($orig_post['uri-id'], $orig_post['uid']);
$title = trim($_REQUEST['title'] ?? '');
$body = trim($body);
$private = $orig_post['private'];
$pubmail_enabled = $orig_post['pubmail'];
$network = $orig_post['network'];
$guid = $orig_post['guid'];
$extid = $orig_post['extid'];
} else {
$aclFormatter = DI::aclFormatter();
$str_contact_allow = isset($_REQUEST['contact_allow']) ? $aclFormatter->toString($_REQUEST['contact_allow']) : $user['allow_cid'] ?? '';
$str_group_allow = isset($_REQUEST['group_allow']) ? $aclFormatter->toString($_REQUEST['group_allow']) : $user['allow_gid'] ?? '';
$str_contact_deny = isset($_REQUEST['contact_deny']) ? $aclFormatter->toString($_REQUEST['contact_deny']) : $user['deny_cid'] ?? '';
$str_group_deny = isset($_REQUEST['group_deny']) ? $aclFormatter->toString($_REQUEST['group_deny']) : $user['deny_gid'] ?? '';
$visibility = $_REQUEST['visibility'] ?? '';
if ($visibility === 'public') {
// The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected
$str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = '';
} else if ($visibility === 'custom') {
// Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL
// case that would make it public. So we always append the author's contact id to the allowed contacts.
// See https://github.com/friendica/friendica/issues/9672
$str_contact_allow .= $aclFormatter->toString(Contact::getPublicIdByUserId($uid));
}
$title = trim($_REQUEST['title'] ?? '');
$location = trim($_REQUEST['location'] ?? '');
$coord = trim($_REQUEST['coord'] ?? '');
$verb = trim($_REQUEST['verb'] ?? '');
$emailcc = trim($_REQUEST['emailcc'] ?? '');
$body = trim($body);
$network = trim(($_REQUEST['network'] ?? '') ?: Protocol::DFRN);
$guid = System::createUUID();
$postopts = $_REQUEST['postopts'] ?? '';
if (strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) {
$private = Item::PRIVATE;
} elseif (DI::pConfig()->get($profile_uid, 'system', 'unlisted')) {
$private = Item::UNLISTED;
} else {
$private = Item::PUBLIC;
}
// If this is a comment, set the permissions from the parent.
if ($toplevel_item) {
// for non native networks use the network of the original post as network of the item
if (($toplevel_item['network'] != Protocol::DIASPORA)
&& ($toplevel_item['network'] != Protocol::OSTATUS)
&& ($network == '')) {
$network = $toplevel_item['network'];
}
$str_contact_allow = $toplevel_item['allow_cid'] ?? '';
$str_group_allow = $toplevel_item['allow_gid'] ?? '';
$str_contact_deny = $toplevel_item['deny_cid'] ?? '';
$str_group_deny = $toplevel_item['deny_gid'] ?? '';
$private = $toplevel_item['private'];
$wall = $toplevel_item['wall'];
}
$pubmail_enabled = ($_REQUEST['pubmail_enable'] ?? false) && !$private;
if (!strlen($body)) {
if ($preview) {
System::jsonExit(['preview' => '']);
}
DI::sysmsg()->addNotice(DI::l10n()->t('Empty post discarded.'));
if ($return_path) {
DI::baseUrl()->redirect($return_path);
}
throw new HTTPException\BadRequestException(DI::l10n()->t('Empty post discarded.'));
}
}
if (!empty($categories)) {
// get the "fileas" tags for this post
$filedas = FileTag::fileToArray($categories);
}
$list_array = explode(',', trim($_REQUEST['category'] ?? ''));
$categories = FileTag::arrayToFile($list_array, 'category');
if (!empty($filedas) && is_array($filedas)) {
// append the fileas stuff to the new categories list
$categories .= FileTag::arrayToFile($filedas);
}
// get contact info for poster
$author = null;
$self = false;
$contact_id = 0;
if (DI::userSession()->getLocalUserId() && ((DI::userSession()->getLocalUserId() == $profile_uid) || $allow_comment)) {
$self = true;
$author = DBA::selectFirst('contact', [], ['uid' => DI::userSession()->getLocalUserId(), 'self' => true]);
} elseif (!empty(DI::userSession()->getRemoteContactID($profile_uid))) {
$author = DBA::selectFirst('contact', [], ['id' => DI::userSession()->getRemoteContactID($profile_uid)]);
}
if (DBA::isResult($author)) {
$contact_id = $author['id'];
}
// get contact info for owner
if ($profile_uid == DI::userSession()->getLocalUserId() || $allow_comment) {
$contact_record = $author ?: [];
} else {
$contact_record = DBA::selectFirst('contact', [], ['uid' => $profile_uid, 'self' => true]) ?: [];
}
// Personal notes must never be altered to a forum post.
if ($posttype != Item::PT_PERSONAL_NOTE) {
// Look for any tags and linkify them
$item = [
'uid' => DI::userSession()->getLocalUserId() ? DI::userSession()->getLocalUserId() : $profile_uid,
'gravity' => $toplevel_item_id ? Item::GRAVITY_COMMENT : Item::GRAVITY_PARENT,
'network' => $network,
'body' => $body,
'postopts' => $postopts,
'private' => $private,
'allow_cid' => $str_contact_allow,
'allow_gid' => $str_group_allow,
'deny_cid' => $str_contact_deny,
'deny_gid' => $str_group_deny,
];
$item = DI::contentItem()->expandTags($item);
$body = $item['body'];
$inform = $item['inform'];
$postopts = $item['postopts'];
$private = $item['private'];
$str_contact_allow = $item['allow_cid'];
$str_group_allow = $item['allow_gid'];
$str_contact_deny = $item['deny_cid'];
$str_group_deny = $item['deny_gid'];
} else {
$inform = '';
}
/*
* When a photo was uploaded into the message using the (profile wall) ajax
* uploader, The permissions are initially set to disallow anybody but the
* owner from seeing it. This is because the permissions may not yet have been
* set for the post. If it's private, the photo permissions should be set
* appropriately. But we didn't know the final permissions on the post until
* now. So now we'll look for links of uploaded messages that are in the
* post and set them to the same permissions as the post itself.
*/
$match = null;
if (!$preview && Photo::setPermissionFromBody($body, $uid, $contact_id, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny)) {
$objecttype = Activity\ObjectType::IMAGE;
}
/*
* Next link in any attachment references we find in the post.
*/
$match = [];
/// @todo these lines should be moved to Model/Attach (Once it exists)
if (!$preview && preg_match_all("/\[attachment\](.*?)\[\/attachment\]/", $body, $match)) {
$attaches = $match[1];
if (count($attaches)) {
foreach ($attaches as $attach) {
// Ensure to only modify attachments that you own
$srch = '<' . intval($contact_id) . '>';
$condition = [
'allow_cid' => $srch,
'allow_gid' => '',
'deny_cid' => '',
'deny_gid' => '',
'id' => $attach,
];
if (!Attach::exists($condition)) {
continue;
}
$fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow,
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny];
$condition = ['id' => $attach];
Attach::update($fields, $condition);
}
}
}
// embedded bookmark or attachment in post? set bookmark flag
$data = BBCode::getAttachmentData($body);
$match = [];
if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $body, $match, PREG_SET_ORDER) || isset($data['type']))
&& ($posttype != Item::PT_PERSONAL_NOTE)) {
$posttype = Item::PT_PAGE;
$objecttype = Activity\ObjectType::BOOKMARK;
}
$body = DI::bbCodeVideo()->transform($body);
$body = BBCode::scaleExternalImages($body);
// Setting the object type if not defined before
if (!$objecttype) {
$objecttype = Activity\ObjectType::NOTE; // Default value
$objectdata = BBCode::getAttachedData($body);
if ($objectdata['type'] == 'link') {
$objecttype = Activity\ObjectType::BOOKMARK;
} elseif ($objectdata['type'] == 'video') {
$objecttype = Activity\ObjectType::VIDEO;
} elseif ($objectdata['type'] == 'photo') {
$objecttype = Activity\ObjectType::IMAGE;
}
}
$attachments = '';
$match = [];
if (preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/',$body,$match)) {
foreach ($match[2] as $mtch) {
$fields = ['id', 'filename', 'filesize', 'filetype'];
$attachment = Attach::selectFirst($fields, ['id' => $mtch]);
if ($attachment !== false) {
if (strlen($attachments)) {
$attachments .= ',';
}
$attachments .= Post\Media::getAttachElement(DI::baseUrl() . '/attach/' . $attachment['id'],
$attachment['filesize'], $attachment['filetype'], $attachment['filename'] ?? '');
}
$body = str_replace($match[1],'',$body);
}
}
if (!strlen($verb)) {
$verb = Activity::POST;
}
if ($network == '') {
$network = Protocol::DFRN;
}
$gravity = ($toplevel_item_id ? Item::GRAVITY_COMMENT : Item::GRAVITY_PARENT);
// even if the post arrived via API we are considering that it
// originated on this site by default for determining relayability.
// Don't use "defaults" here. It would turn 0 to 1
if (!isset($_REQUEST['origin'])) {
$origin = 1;
} else {
$origin = $_REQUEST['origin'];
}
$uri = Item::newURI($guid);
// Fallback so that we alway have a parent uri
if (!$thr_parent_uri || !$toplevel_item_id) {
$thr_parent_uri = $uri;
}
$datarray = [
'uid' => $profile_uid,
'wall' => $wall,
'gravity' => $gravity,
'network' => $network,
'contact-id' => $contact_id,
'owner-name' => $contact_record['name'] ?? '',
'owner-link' => $contact_record['url'] ?? '',
'owner-avatar' => $contact_record['thumb'] ?? '',
'author-name' => $author['name'],
'author-link' => $author['url'],
'author-avatar' => $author['thumb'],
'created' => empty($_REQUEST['created_at']) ? DateTimeFormat::utcNow() : $_REQUEST['created_at'],
'received' => DateTimeFormat::utcNow(),
'extid' => $extid,
'guid' => $guid,
'uri' => $uri,
'title' => $title,
'body' => $body,
'app' => $app,
'location' => $location,
'coord' => $coord,
'file' => $categories,
'inform' => $inform,
'verb' => $verb,
'post-type' => $posttype,
'object-type' => $objecttype,
'allow_cid' => $str_contact_allow,
'allow_gid' => $str_group_allow,
'deny_cid' => $str_contact_deny,
'deny_gid' => $str_group_deny,
'private' => $private,
'pubmail' => $pubmail_enabled,
'attach' => $attachments,
'thr-parent' => $thr_parent_uri,
'postopts' => $postopts,
'origin' => $origin,
'object' => $object,
'attachments' => $_REQUEST['attachments'] ?? [],
/*
* These fields are for the convenience of addons...
* 'self' if true indicates the owner is posting on their own wall
* If parent is 0 it is a top-level post.
*/
'parent' => $toplevel_item_id,
'self' => $self,
// This triggers posts via API and the mirror functions
'api_source' => false,
// This field is for storing the raw conversation data
'protocol' => Conversation::PARCEL_DIRECT,
'direction' => Conversation::PUSH,
];
// These cannot be part of above initialization ...
$datarray['edited'] = $datarray['created'];
$datarray['commented'] = $datarray['created'];
$datarray['changed'] = $datarray['created'];
$datarray['owner-id'] = Contact::getIdForURL($datarray['owner-link']);
$datarray['author-id'] = Contact::getIdForURL($datarray['author-link']);
$datarray['edit'] = $orig_post;
// Check for hashtags in the body and repair or add hashtag links
if ($preview || $orig_post) {
$datarray['body'] = Item::setHashtags($datarray['body']);
}
// preview mode - prepare the body for display and send it via json
if ($preview) {
// We set the datarray ID to -1 because in preview mode the dataray
// doesn't have an ID.
$datarray['id'] = -1;
$datarray['uri-id'] = -1;
$datarray['author-network'] = Protocol::DFRN;
$datarray['author-updated'] = '';
$datarray['author-gsid'] = 0;
$datarray['author-uri-id'] = ItemURI::getIdByURI($datarray['author-link']);
$datarray['owner-updated'] = '';
$datarray['has-media'] = false;
$datarray['quote-uri-id'] = Item::getQuoteUriId($datarray['body'], $datarray['uid']);
$datarray['body'] = BBCode::removeSharedData($datarray['body']);
$o = DI::conversation()->create([array_merge($contact_record, $datarray)], 'search', false, true);
System::jsonExit(['preview' => $o]);
}
Hook::callAll('post_local',$datarray);
if (!empty($_REQUEST['scheduled_at'])) {
$scheduled_at = DateTimeFormat::convert($_REQUEST['scheduled_at'], 'UTC', $a->getTimeZone());
if ($scheduled_at > DateTimeFormat::utcNow()) {
unset($datarray['created']);
unset($datarray['edited']);
unset($datarray['commented']);
unset($datarray['received']);
unset($datarray['changed']);
unset($datarray['edit']);
unset($datarray['self']);
unset($datarray['api_source']);
Post\Delayed::add($datarray['uri'], $datarray, Worker::PRIORITY_HIGH, Post\Delayed::PREPARED_NO_HOOK, $scheduled_at);
item_post_return(DI::baseUrl(), $return_path);
}
}
if (!empty($datarray['cancel'])) {
Logger::info('mod_item: post cancelled by addon.');
if ($return_path) {
DI::baseUrl()->redirect($return_path);
}
$json = ['cancel' => 1];
if (!empty($_REQUEST['jsreload'])) {
$json['reload'] = DI::baseUrl() . '/' . $_REQUEST['jsreload'];
}
System::jsonExit($json);
}
$datarray['uri-id'] = ItemURI::getIdByURI($datarray['uri']);
$quote_uri_id = Item::getQuoteUriId($datarray['body'], $datarray['uid']);
if (!empty($quote_uri_id)) {
$datarray['quote-uri-id'] = $quote_uri_id;
$datarray['body'] = BBCode::removeSharedData($datarray['body']);
}
if ($orig_post) {
$fields = [
'title' => $datarray['title'],
'body' => $datarray['body'],
'attach' => $datarray['attach'],
'file' => $datarray['file'],
'title' => $post['title'],
'body' => $post['body'],
'attach' => $post['attach'],
'file' => $post['file'],
'location' => $post['location'],
'coord' => $post['coord'],
'edited' => DateTimeFormat::utcNow(),
'changed' => DateTimeFormat::utcNow()
];
Item::update($fields, ['id' => $post_id]);
Item::updateDisplayCache($datarray['uri-id']);
$fields['body'] = Item::setHashtags($fields['body']);
$quote_uri_id = Item::getQuoteUriId($fields['body'], $post['uid']);
if (!empty($quote_uri_id)) {
$fields['quote-uri-id'] = $quote_uri_id;
$fields['body'] = BBCode::removeSharedData($post['body']);
}
Item::update($fields, ['id' => $post['id']]);
Item::updateDisplayCache($post['uri-id']);
if ($return_path) {
DI::baseUrl()->redirect($return_path);
@ -673,24 +138,77 @@ function item_post(App $a) {
throw new HTTPException\OKException(DI::l10n()->t('Post updated.'));
}
unset($datarray['edit']);
unset($datarray['self']);
unset($datarray['api_source']);
function item_insert(int $uid, array $request, bool $preview, string $return_path)
{
$post = ['uid' => $uid];
$post = DI::contentItem()->initializePost($post);
$post_id = Item::insert($datarray);
$post['edit'] = null;
$post['post-type'] = $request['post_type'] ?? '';
$post['wall'] = $request['wall'] ?? true;
$post['pubmail'] = $request['pubmail_enable'] ?? false;
$post['created'] = $request['created_at'] ?? DateTimeFormat::utcNow();
$post['edited'] = $post['changed'] = $post['commented'] = $post['created'];
$post['app'] = '';
$post['inform'] = '';
$post['postopts'] = '';
$post['file'] = '';
if (!$post_id) {
DI::sysmsg()->addNotice(DI::l10n()->t('Item wasn\'t stored.'));
if (!empty($request['parent'])) {
$parent_item = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $request['parent']]);
if ($parent_item) {
// if this isn't the top-level parent of the conversation, find it
if ($parent_item['gravity'] != Item::GRAVITY_PARENT) {
$toplevel_item = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $parent_item['parent']]);
} else {
$toplevel_item = $parent_item;
}
}
if (empty($toplevel_item)) {
if ($return_path) {
DI::sysmsg()->addNotice(DI::l10n()->t('Unable to locate original post.'));
DI::baseUrl()->redirect($return_path);
}
throw new HTTPException\NotFoundException(DI::l10n()->t('Unable to locate original post.'));
}
// When commenting on a public post then store the post for the current user
// This enables interaction like starring and saving into folders
if ($toplevel_item['uid'] == 0) {
$stored = Item::storeForUserByUriId($toplevel_item['uri-id'], $post['uid'], ['post-reason' => Item::PR_ACTIVITY]);
Logger::info('Public item stored for user', ['uri-id' => $toplevel_item['uri-id'], 'uid' => $post['uid'], 'stored' => $stored]);
}
$post['parent'] = $toplevel_item['id'];
$post['gravity'] = Item::GRAVITY_COMMENT;
$post['thr-parent'] = $parent_item['uri'];
$post['wall'] = $toplevel_item['wall'];
} else {
$parent_item = [];
$post['parent'] = 0;
$post['gravity'] = Item::GRAVITY_PARENT;
$post['thr-parent'] = $post['uri'];
}
$post = DI::contentItem()->getACL($post, $parent_item, $request);
$post['pubmail'] = $post['pubmail'] && !$post['private'];
$post = item_process($post, $request, $preview, $return_path);
$post_id = Item::insert($post);
if (!$post_id) {
if ($return_path) {
DI::sysmsg()->addNotice(DI::l10n()->t('Item wasn\'t stored.'));
DI::baseUrl()->redirect($return_path);
}
throw new HTTPException\InternalServerErrorException(DI::l10n()->t('Item wasn\'t stored.'));
}
$datarray = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]);
if (!DBA::isResult($datarray)) {
$post = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]);
if (!$post) {
Logger::error('Item couldn\'t be fetched.', ['post_id' => $post_id]);
if ($return_path) {
DI::baseUrl()->redirect($return_path);
@ -699,52 +217,9 @@ function item_post(App $a) {
throw new HTTPException\InternalServerErrorException(DI::l10n()->t('Item couldn\'t be fetched.'));
}
Tag::storeFromBody($datarray['uri-id'], $datarray['body']);
$recipients = explode(',', $request['emailcc'] ?? '');
if (!\Friendica\Content\Feature::isEnabled($uid, 'explicit_mentions') && ($datarray['gravity'] == Item::GRAVITY_COMMENT)) {
Tag::createImplicitMentions($datarray['uri-id'], $datarray['thr-parent-id']);
}
// These notifications are sent if someone else is commenting other your wall
if ($contact_record != $author) {
if ($toplevel_item_id) {
DI::notify()->createFromArray([
'type' => Notification\Type::COMMENT,
'otype' => Notification\ObjectType::ITEM,
'verb' => Activity::POST,
'uid' => $profile_uid,
'cid' => $datarray['author-id'],
'item' => $datarray,
'link' => DI::baseUrl() . '/display/' . urlencode($datarray['guid']),
]);
} elseif (empty($forum_contact)) {
DI::notify()->createFromArray([
'type' => Notification\Type::WALL,
'otype' => Notification\ObjectType::ITEM,
'verb' => Activity::POST,
'uid' => $profile_uid,
'cid' => $datarray['author-id'],
'item' => $datarray,
'link' => DI::baseUrl() . '/display/' . urlencode($datarray['guid']),
]);
}
}
Hook::callAll('post_local_end', $datarray);
if (strlen($emailcc) && $profile_uid == DI::userSession()->getLocalUserId()) {
$recipients = explode(',', $emailcc);
if (count($recipients)) {
foreach ($recipients as $recipient) {
$address = trim($recipient);
if (!strlen($address)) {
continue;
}
DI::emailer()->send(new ItemCCEMail(DI::app(), DI::l10n(), DI::baseUrl(),
$datarray, $address, $author['thumb'] ?? ''));
}
}
}
DI::contentItem()->postProcessPost($post, $recipients);
Logger::debug('post_complete');
@ -752,6 +227,95 @@ function item_post(App $a) {
// NOTREACHED
}
function item_process(array $post, array $request, bool $preview, string $return_path): array
{
$post['self'] = true;
$post['api_source'] = false;
$post['attach'] = '';
$post['title'] = trim($request['title'] ?? '');
$post['body'] = $request['body'] ?? '';
$post['location'] = trim($request['location'] ?? '');
$post['coord'] = trim($request['coord'] ?? '');
$post = DI::contentItem()->addCategories($post, $request['category'] ?? '');
// Add the attachment to the body.
if (!empty($request['has_attachment'])) {
$post['body'] .= DI::contentItem()->storeAttachmentFromRequest($request);
}
$post = DI::contentItem()->finalizePost($post);
if (!strlen($post['body'])) {
if ($preview) {
System::jsonExit(['preview' => '']);
}
if ($return_path) {
DI::sysmsg()->addNotice(DI::l10n()->t('Empty post discarded.'));
DI::baseUrl()->redirect($return_path);
}
throw new HTTPException\BadRequestException(DI::l10n()->t('Empty post discarded.'));
}
// preview mode - prepare the body for display and send it via json
if ($preview) {
// We have to preset some fields, so that the conversation can be displayed
$post['id'] = -1;
$post['uri-id'] = -1;
$post['author-network'] = Protocol::DFRN;
$post['author-updated'] = '';
$post['author-gsid'] = 0;
$post['author-uri-id'] = ItemURI::getIdByURI($post['author-link']);
$post['owner-updated'] = '';
$post['has-media'] = false;
$post['quote-uri-id'] = Item::getQuoteUriId($post['body'], $post['uid']);
$post['body'] = BBCode::removeSharedData(Item::setHashtags($post['body']));
$post['writable'] = true;
$o = DI::conversation()->create([$post], Conversation::MODE_SEARCH, false, true);
System::jsonExit(['preview' => $o]);
}
Hook::callAll('post_local',$post);
unset($post['edit']);
unset($post['self']);
unset($post['api_source']);
if (!empty($request['scheduled_at'])) {
$scheduled_at = DateTimeFormat::convert($request['scheduled_at'], 'UTC', DI::app()->getTimeZone());
if ($scheduled_at > DateTimeFormat::utcNow()) {
unset($post['created']);
unset($post['edited']);
unset($post['commented']);
unset($post['received']);
unset($post['changed']);
Post\Delayed::add($post['uri'], $post, Worker::PRIORITY_HIGH, Post\Delayed::PREPARED_NO_HOOK, $scheduled_at);
item_post_return(DI::baseUrl(), $return_path);
}
}
if (!empty($post['cancel'])) {
Logger::info('mod_item: post cancelled by addon.');
if ($return_path) {
DI::baseUrl()->redirect($return_path);
}
$json = ['cancel' => 1];
if (!empty($request['jsreload'])) {
$json['reload'] = DI::baseUrl() . '/' . $request['jsreload'];
}
System::jsonExit($json);
}
return $post;
}
function item_post_return($baseurl, $return_path)
{
if ($return_path) {
@ -804,6 +368,22 @@ function item_content(App $a)
Contact\User::setBlocked($item['author-id'], DI::userSession()->getLocalUserId(), true);
if (DI::mode()->isAjax()) {
// ajax return: [<item id>, 0 (no perm) | <owner id>]
System::jsonExit([intval($args->get(2)), DI::userSession()->getLocalUserId()]);
} else {
item_redirect_after_action($item, $args->get(3));
}
break;
case 'ignore':
$item = Post::selectFirstForUser(DI::userSession()->getLocalUserId(), ['guid', 'author-id', 'parent', 'gravity'], ['id' => $args->get(2)]);
if (empty($item['author-id'])) {
throw new HTTPException\NotFoundException('Item not found');
}
Contact\User::setIgnored($item['author-id'], DI::userSession()->getLocalUserId(), true);
if (DI::mode()->isAjax()) {
// ajax return: [<item id>, 0 (no perm) | <owner id>]
System::jsonExit([intval($args->get(2)), DI::userSession()->getLocalUserId()]);

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -58,7 +58,6 @@ function message_init(App $a)
$head_tpl = Renderer::getMarkupTemplate('message-head.tpl');
DI::page()['htmlhead'] .= Renderer::replaceMacros($head_tpl, [
'$baseurl' => DI::baseUrl()->get(true),
'$base' => $base
]);
}
@ -70,12 +69,13 @@ function message_post(App $a)
return;
}
$sender_id = DI::userSession()->getLocalUserId();
$replyto = !empty($_REQUEST['replyto']) ? trim($_REQUEST['replyto']) : '';
$subject = !empty($_REQUEST['subject']) ? trim($_REQUEST['subject']) : '';
$body = !empty($_REQUEST['body']) ? Strings::escapeHtml(trim($_REQUEST['body'])) : '';
$recipient = !empty($_REQUEST['recipient']) ? intval($_REQUEST['recipient']) : 0;
$ret = Mail::send($recipient, $body, $subject, $replyto);
$ret = Mail::send($sender_id, $recipient, $body, $subject, $replyto);
$norecip = false;
switch ($ret) {
@ -178,7 +178,6 @@ function message_content(App $a)
$tpl = Renderer::getMarkupTemplate('msg-header.tpl');
DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [
'$baseurl' => DI::baseUrl()->get(true),
'$nickname' => $a->getLoggedInUserNickname(),
'$linkurl' => DI::l10n()->t('Please enter a link URL:')
]);
@ -284,7 +283,6 @@ function message_content(App $a)
$tpl = Renderer::getMarkupTemplate('msg-header.tpl');
DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [
'$baseurl' => DI::baseUrl()->get(true),
'$nickname' => $a->getLoggedInUserNickname(),
'$linkurl' => DI::l10n()->t('Please enter a link URL:')
]);
@ -438,7 +436,7 @@ function render_messages(array $msg, string $t): string
$to_name_e = $rr['name'];
if (is_null($rr['url'])) {
// contact-id is pointing to a non existing contact
// contact-id is pointing to a nonexistent contact
continue;
}

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -20,6 +20,7 @@
*/
use Friendica\App;
use Friendica\Content\Conversation;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Database\DBA;
@ -84,7 +85,7 @@ function notes_content(App $a, bool $update = false)
$count = count($notes);
$o .= DI::conversation()->create($notes, 'notes', $update);
$o .= DI::conversation()->create($notes, Conversation::MODE_NOTES, $update);
}
$o .= $pager->renderMinimal($count);

View file

@ -1,128 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @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/>.
*
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Core\System;
use Friendica\DI;
use Friendica\Module\Response;
use Friendica\Module\Security\Login;
use Friendica\Util\XML;
function oexchange_init(App $a)
{
if ((DI::args()->getArgc() <= 1) || (DI::args()->getArgv()[1] != 'xrd')) {
return;
}
$baseURL = DI::baseUrl()->get();
$xml = null;
XML::fromArray([
'XRD' => [
'@attributes' => [
'xmlns' => 'http://docs.oasis-open.org/ns/xri/xrd-1.0',
],
'Subject' => $baseURL,
'1:Property' => [
'@attributes' => [
'type' => 'http://www.oexchange.org/spec/0.8/prop/vendor',
],
'Friendica'
],
'2:Property' => [
'@attributes' => [
'type' => 'http://www.oexchange.org/spec/0.8/prop/title',
],
'Friendica Social Network'
],
'3:Property' => [
'@attributes' => [
'type' => 'http://www.oexchange.org/spec/0.8/prop/name',
],
'Friendica'
],
'4:Property' => [
'@attributes' => [
'type' => 'http://www.oexchange.org/spec/0.8/prop/prompt',
],
'Send to Friendica'
],
'1:link' => [
'@attributes' => [
'rel' => 'icon',
'type' => 'image/png',
'href' => $baseURL . '/images/friendica-16.png'
]
],
'2:link' => [
'@attributes' => [
'rel' => 'icon32',
'type' => 'image/png',
'href' => $baseURL . '/images/friendica-32.png'
]
],
'3:link' => [
'@attributes' => [
'rel' => 'http://www.oexchange.org/spec/0.8/rel/offer',
'type' => 'text/html',
'href' => $baseURL . '/oexchange'
]
],
],
], $xml);
System::httpExit($xml->saveXML(), Response::TYPE_XML, 'application/xrd+xml');
}
function oexchange_content(App $a)
{
if (!DI::userSession()->getLocalUserId()) {
$o = Login::form();
return $o;
}
if ((DI::args()->getArgc() > 1) && DI::args()->getArgv()[1] === 'done') {
return;
}
$url = !empty($_REQUEST['url']) ? trim($_REQUEST['url']) : '';
$title = !empty($_REQUEST['title']) ? trim($_REQUEST['title']) : '';
$description = !empty($_REQUEST['description']) ? trim($_REQUEST['description']) : '';
$tags = !empty($_REQUEST['tags']) ? trim($_REQUEST['tags']) : '';
$s = BBCode::embedURL($url, true, $title, $description, $tags);
if (!strlen($s)) {
return;
}
$post = [];
$post['return'] = '/oexchange/done';
$post['body'] = HTML::toBBCode($s);
$_REQUEST = $post;
require_once 'mod/item.php';
item_post($a);
}

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -31,6 +31,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Item;
@ -61,7 +62,7 @@ function photos_init(App $a)
Nav::setSelected('home');
if (DI::args()->getArgc() > 1) {
$owner = User::getOwnerDataByNick(DI::args()->getArgv()[1]);
$owner = Profile::load(DI::app(), DI::args()->getArgv()[1], false);
if (!isset($owner['account_removed']) || $owner['account_removed']) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.'));
}
@ -110,12 +111,6 @@ function photos_init(App $a)
]);
}
if (empty(DI::page()['aside'])) {
DI::page()['aside'] = '';
}
DI::page()['aside'] .= Widget\VCard::getHTML($owner);
if (!empty($photo_albums_widget)) {
DI::page()['aside'] .= $photo_albums_widget;
}
@ -719,7 +714,7 @@ function photos_content(App $a)
// When PHP is configured with upload_max_filesize less than maximagesize provide this lower limit.
$maximagesize_bytes = (is_numeric($mis_bytes) && ($mis_bytes < $umf_bytes) ? $mis_bytes : $umf_bytes);
// @todo We may be want to use appropriate binary prefixed dynamicly
// @todo We may be want to use appropriate binary prefixed dynamically
$usage_message = DI::l10n()->t('The maximum accepted image size is %s', Strings::formatBytes($maximagesize_bytes));
$tpl = Renderer::getMarkupTemplate('photos_upload.tpl');
@ -923,7 +918,7 @@ function photos_content(App $a)
if ($order_field === 'created') {
$params = ['order' => [$order_field]];
} elseif (!empty($order_field)) {
} elseif (!empty($order_field) && DBStructure::existsColumn('photo', [$order_field])) {
$params = ['order' => [$order_field => true]];
} else {
$params = [];
@ -936,11 +931,17 @@ function photos_content(App $a)
$nxt = null;
foreach ($prvnxt as $z => $entry) {
if ($entry['resource-id'] == $ph[0]['resource-id']) {
$prv = $z - 1;
$nxt = $z + 1;
$prv = $order_field === 'created' ? $z - 1 : $z + 1;
$nxt = $order_field === 'created' ? $z + 1 : $z - 1;
if ($prv < 0) {
$prv = count($prvnxt) - 1;
}
if ($nxt < 0) {
$nxt = count($prvnxt) - 1;
}
if ($prv >= count($prvnxt)) {
$prv = 0;
}
if ($nxt >= count($prvnxt)) {
$nxt = 0;
}
@ -1138,7 +1139,7 @@ function photos_content(App $a)
'$preview' => DI::l10n()->t('Preview'),
'$loading' => DI::l10n()->t('Loading...'),
'$qcomment' => $qcomment,
'$rand_num' => Crypto::randomDigits(12)
'$rand_num' => Crypto::randomDigits(12),
]);
}
}
@ -1193,7 +1194,7 @@ function photos_content(App $a)
'$submit' => DI::l10n()->t('Submit'),
'$preview' => DI::l10n()->t('Preview'),
'$qcomment' => $qcomment,
'$rand_num' => Crypto::randomDigits(12)
'$rand_num' => Crypto::randomDigits(12),
]);
}
@ -1267,7 +1268,7 @@ function photos_content(App $a)
'$submit' => DI::l10n()->t('Submit'),
'$preview' => DI::l10n()->t('Preview'),
'$qcomment' => $qcomment,
'$rand_num' => Crypto::randomDigits(12)
'$rand_num' => Crypto::randomDigits(12),
]);
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -30,7 +30,7 @@ use Friendica\Model\Contact;
function update_contact_content(App $a)
{
if (!empty(DI::args()->get(1)) && (!empty($_GET['force']) || !DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'no_auto_update'))) {
if (!empty(DI::args()->get(1)) && !empty($_GET['force'])) {
$contact = Contact::getById(DI::args()->get(1), ['id', 'deleted']);
if (DBA::isResult($contact) && empty($contact['deleted'])) {
DI::page()['aside'] = '';

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*

View file

@ -32,5 +32,9 @@ Please check software documentation to know how modify these examples to make th
Sample systemd unit files to start worker.php periodically.
Please place them in the correct location for your system, typically this is `/etc/systemd/system/friendicaworker.timer` and `/etc/systemd/system/friendicaworker.service`.
Please report problems and improvements to `!helpers@forum.friendi.ca` and `@utzer@social.yl.ms` or open an issue in [the Github Friendica page](https://github.com/friendica/friendica/issues).
Please report problems and improvements to `!helpers@forum.friendi.ca` and `@utzer@social.yl.ms` or open an issue in [the GitHub Friendica page](https://github.com/friendica/friendica/issues).
This is for usage of systemd instead of cron to start the worker periodically, the solution is a work-in-progress and can surely be improved.
## `phpstorm-code-style.xml`
PHP Storm Code Style settings, used for this codebase

View file

@ -1,12 +1,12 @@
# Bookmarklet-share2friendica
Javascript bookmarklet to share websites with your friendica account
JavaScript bookmarklet to share websites with your friendica account
## Getting Started
### Installing
Open the file bookmarklet-share2friendica.js and change 'YourFriendicaDoomain.tld" with your friendica domain
Open the file bookmarklet-share2friendica.js and change 'YourFriendicaDomain.tld" with your friendica domain
If you friendica is at https://myfriend.myfami.ly/ , the original ...
```javascript
@ -20,7 +20,7 @@ javascript:(function(){f='https://myfriend.myfami.ly/bookmarklet/?url='+encodeUR
*Please copy the whole script, not only the part mentioned here!*
Then create a new bookmark, give it a name like "share2Friendica" and paste the script in the address field. Save it. Now you can click on that bookmarklet every time you want to share a website, you are currently reading. A new small window will open where title is prefilled and the website you want to share is put as attachement in the body of the new post.
Then create a new bookmark, give it a name like "share2Friendica" and paste the script in the address field. Save it. Now you can click on that bookmarklet every time you want to share a website, you are currently reading. A new small window will open where title is prefilled and the website you want to share is put as attachment in the body of the new post.
## Additional notes if it doesn't work

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*

View file

@ -1,6 +1,6 @@
<!-- styling for this page is done in the home.css file //-->
<!-- Some node specifiv welcome message //-->
<!-- Some node specific welcome message //-->
<p>Welcome to this <a href="https://friendi.ca">Friendica</a> node!</p>
<!-- Some general notes about Friendica, the other networks and difficulty to run //-->
@ -17,7 +17,7 @@
</div>
<div id="c3" class="homeinfobox">
<h4>Is it hard to run Friendica?</h4>
<p>No, not at all! You need a LAMP server, most shared hosting services that offer MySQL, PHP and the ability to run cron jobs will do just fine. If you have your own (virtual) server, for a small Friendica server something like a Raspberry2B is sufficenent from the specs.</p>
<p>No, not at all! You need a LAMP server, most shared hosting services that offer MySQL, PHP and the ability to run cron jobs will do just fine. If you have your own (virtual) server, for a small Friendica server something like a Raspberry2B is sufficient from the specs.</p>
<p><a href="https://github.com/friendica/friendica">Get the source</a></p>
</div>
</div>

50
mods/local.config.ci.php Normal file
View file

@ -0,0 +1,50 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @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/>.
*
*/
return [
'database' => [
'hostname' => 'localhost',
'username' => 'friendica',
'password' => 'friendica',
'database' => 'friendica',
'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' => 'admin@friendica.local',
'sitename' => 'Friendica Social Network',
'register_policy' => \Friendica\Module\Register::OPEN,
'register_text' => '',
],
'system' => [
'default_timezone' => 'UTC',
'language' => 'en',
'url' => 'https://friendica.local',
// don't start unexpected worker.php processes during test!
'worker_dont_fork' => true,
],
];

View file

@ -29,7 +29,6 @@ return [
// ****************************************************************
'config' => [
'hostname' => '192.168.56.10',
'admin_email' => 'admin@friendica.local',
'sitename' => 'Friendica Social Network',
'register_policy' => \Friendica\Module\Register::OPEN,
@ -39,6 +38,6 @@ return [
'default_timezone' => 'UTC',
'language' => 'en',
'basepath' => '/vagrant',
'ssl_policy' => \Friendica\App\BaseURL::SSL_POLICY_SELFSIGN,
'url' => 'https://192.168.56.10',
],
];

View file

@ -0,0 +1,34 @@
<code_scheme name="Default" version="173">
<Markdown>
<option name="WRAP_TEXT_IF_LONG" value="false" />
<option name="WRAP_TEXT_INSIDE_BLOCKQUOTES" value="false" />
</Markdown>
<PHPCodeStyleSettings>
<option name="ALIGN_KEY_VALUE_PAIRS" value="true" />
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
<option name="ALIGN_PHPDOC_COMMENTS" value="true" />
<option name="ALIGN_ASSIGNMENTS" value="true" />
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="ELSE_IF_STYLE" value="SEPARATE" />
<option name="VARIABLE_NAMING_STYLE" value="CAMEL_CASE" />
<option name="ALIGN_CLASS_CONSTANTS" value="true" />
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
</PHPCodeStyleSettings>
<codeStyleSettings language="PHP">
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>

View file

@ -22,7 +22,7 @@ the requested URL.
Enjoy!
On Debian Jessie with lighttpd 1.4.35-4 there was a problem encountered
between curl (which is used by Friendica in the background) and lighttp.
between curl (which is used by Friendica in the background) and lighttpd.
This problem caused requests being served with an error code of 417 in
the logs and no delivery of postings from the contacts.
@ -30,7 +30,7 @@ One can solve the issue by adding
server.reject-expect-100-with-417 = "disable"
to the lighttpd configuratiion file (e.g. in the beginning with the
to the lighttpd configuration file (e.g. in the beginning with the
other 'server.xxx' settings.
---------------( config starts )-----------------

View file

@ -30,12 +30,29 @@
##
# This configuration assumes your domain is example.net
# You have a separate subdomain friendica.example.net
# You want all Friendica traffic to be https using letsencrypt with cerbot
# You want all Friendica traffic to be https using letsencrypt with certbot
# You have an SSL certificate and key for your subdomain
# You have PHP FastCGI Process Manager (php7.4-fpm) running on localhost
# You have Friendica installed in /var/www/friendica
##
##
# by https://syshero.org/2018-04-13-nginx-unique-request-identifier/
# if X-Request-ID is set, NGINX will forward the same value to the next upstream
# if the header is not set, NGINX will generate a random request identifier and add it to the request.
#
# To guarantee backward compatibility, map to format the $request_id variable to a format that matches any old setups.
##
map $request_id $formatted_id {
"~*(?<p1>[0-9a-f]{8})(?<p2>[0-9a-f]{4})(?<p3>[0-9a-f]{4})(?<p4>[0-9a-f]{4})(?<p5>.*)$" "${p1}-${p2}-${p3}-${p4}-${p5}";
}
map $http_x_request_id $uuid {
default "${request_id}";
~* "${http_x_request_id}";
}
server {
listen 80;
server_name friendica.example.net;
@ -60,6 +77,9 @@ server {
client_max_body_size 20m;
client_body_buffer_size 128k;
# add the request id header to show it in the HTTP header output
add_header X-Request-ID $uuid;
# rewrite to front controller as default rule
location / {
try_files $uri /index.php?pagename=$uri&$args;
@ -106,6 +126,8 @@ server {
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_X_REQUEST_ID $uuid;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}

View file

@ -15,6 +15,25 @@
# -----
...
##
# by https://syshero.org/2018-04-13-nginx-unique-request-identifier/
# if X-Request-ID is set, NGINX will forward the same value to the next upstream
# if the header is not set, NGINX will generate a random request identifier and add it to the request.
#
# To guarantee backward compatibility, map to format the $request_id variable to a format that matches any old setups.
##
map $request_id $formatted_id {
"~*(?<p1>[0-9a-f]{8})(?<p2>[0-9a-f]{4})(?<p3>[0-9a-f]{4})(?<p4>[0-9a-f]{4})(?<p5>.*)$" "${p1}-${p2}-${p3}-${p4}-${p5}";
}
map $http_x_request_id $uuid {
default "${request_id}";
~* "${http_x_request_id}";
}
server {
...
@ -30,6 +49,7 @@ server {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Forwarded "for=$proxy_add_x_forwarded_for; proto=$scheme";
proxy_set_header X-Request-ID $uuid;
}
...

View file

@ -20,6 +20,24 @@
# http://wiki.nginx.org/Configuration
##
##
# by https://syshero.org/2018-04-13-nginx-unique-request-identifier/
# if X-Request-ID is set, NGINX will forward the same value to the next upstream
# if the header is not set, NGINX will generate a random request identifier and add it to the request.
#
# To guarantee backward compatibility, map to format the $request_id variable to a format that matches any old setups.
##
map $request_id $formatted_id {
"~*(?<p1>[0-9a-f]{8})(?<p2>[0-9a-f]{4})(?<p3>[0-9a-f]{4})(?<p4>[0-9a-f]{4})(?<p5>.*)$" "${p1}-${p2}-${p3}-${p4}-${p5}";
}
map $http_x_request_id $uuid {
default "${request_id}";
~* "${http_x_request_id}";
}
##
# This configuration assumes your domain is example.net
# You have a separate subdomain friendica.example.net
@ -80,6 +98,9 @@ server {
client_max_body_size 20m;
client_body_buffer_size 128k;
# add the request id header to show it in the HTTP header output
add_header X-Request-ID $uuid;
# rewrite to front controller as default rule
location / {
try_files $uri /index.php?pagename=$uri&$args;
@ -125,6 +146,7 @@ server {
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_X_REQUEST_ID $uuid;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;

View file

@ -1,6 +1,6 @@
Contact: mailto:info@friendi.ca
Expires: Sat, 30 Sept 2023 23:59 +0000
Expires: 2023-12-31T23:59:59Z
Preferred-Languages: en

View file

@ -45,7 +45,7 @@ is a superset of salmon).
zot:key
*******
A suitable randomly generated encyption key of length 32 octets for encrypting
A suitable randomly generated encryption key of length 32 octets for encrypting
the salmon packet. This is then encrypted with the sender's private key and
base64url encoded.
@ -59,7 +59,7 @@ key and base64url encoded.
zot:env_key
***********
A suitable randomly generated encyption key of length 32 octets for encrypting
A suitable randomly generated encryption key of length 32 octets for encrypting
the envelope. This is then encrypted with the recipient's public key and
base64url encoded. For bulk deliveries, it is encrypted with the site bulk
delivery public key.
@ -127,7 +127,7 @@ MUST be present.
Z-To: zot:bob@example.com, zot:alice@example.com, mailto:dave@example.com
Z-Bcc: zot:https://example.com/profile/richard
are valid entries. Adresses are comma separated and individual entries MUST NOT
are valid entries. Addresses are comma separated and individual entries MUST NOT
contain commas. There MAY be any number of ASCII space characters between
entries for legibility. Header lines are terminated with a linefeed character
(ASCII 0x0A).
@ -136,8 +136,8 @@ This specification provides the following protocol address prefixes
for use in Z-To: or Z-Bcc: elements:
zot: - normal zot delivery using webfinger or LRDD resolvable address
dfrn: - legacy DFRN mode delivery using webfinger or LRDD resovable address
ostatus: - normal OStatus delivery using webfinger or LRDD resovable address
dfrn: - legacy DFRN mode delivery using webfinger or LRDD resolvable address
ostatus: - normal OStatus delivery using webfinger or LRDD resolvable address
diaspora: - Diaspora network delivery using webfinger address
facebook: - Facebook profile page URL
twitter: - Twitter personal page URL without AJAX '#!' fragment
@ -289,7 +289,7 @@ systems MAY reject foreign messages.
*******************************
This section of the document is considered separate from the delivery
specification precding it and represents a different protocol, which is
specification preceding it and represents a different protocol, which is
currently incomplete. This will be split off into another document in the
future, but is presented here as a synergistic component of the Zot network
model.
@ -353,7 +353,7 @@ Salmon Magic Envelope
Atom Activity Stream Draft
http://activitystrea.ms/specs/atom/1.0/
Activty Stream Base Schema
Activity Stream Base Schema
http://activitystrea.ms/head/activity-schema.html
WebFinger Protocol

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
@ -25,11 +25,11 @@ use Exception;
use Friendica\App\Arguments;
use Friendica\App\BaseURL;
use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Content\Nav;
use Friendica\Core\Config\Factory\Config;
use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Database\Definition\DbaDefinition;
use Friendica\Database\Definition\ViewDefinition;
use Friendica\Model\User;
use Friendica\Module\Maintenance;
use Friendica\Security\Authentication;
use Friendica\Core\Config\ValueObject\Cache;
@ -64,7 +64,7 @@ class App
{
const PLATFORM = 'Friendica';
const CODENAME = 'Giant Rhubarb';
const VERSION = '2023.01';
const VERSION = '2023.03-rc';
// Allow themes to control internal parameters
// by changing App values in theme.php
@ -73,8 +73,6 @@ class App
'videoheight' => 350,
];
private $user_id = 0;
private $nickname = '';
private $timezone = '';
private $profile_owner = 0;
private $contact_id = 0;
@ -136,64 +134,39 @@ class App
private $session;
/**
* Set the user ID
*
* @param int $user_id
* @return void
* @deprecated 2022.03
* @see IHandleUserSessions::isAuthenticated()
*/
public function setLoggedInUserId(int $user_id)
{
$this->user_id = $user_id;
}
/**
* Set the nickname
*
* @param int $user_id
* @return void
*/
public function setLoggedInUserNickname(string $nickname)
{
$this->nickname = $nickname;
}
public function isLoggedIn(): bool
{
return $this->session->getLocalUserId() && $this->user_id && ($this->user_id == $this->session->getLocalUserId());
return $this->session->isAuthenticated();
}
/**
* Check if current user has admin role.
*
* @return bool true if user is an admin
* @throws Exception
* @deprecated 2022.03
* @see IHandleUserSessions::isSiteAdmin()
*/
public function isSiteAdmin(): bool
{
return
$this->session->getLocalUserId()
&& $this->database->exists('user', [
'uid' => $this->getLoggedInUserId(),
'email' => User::getAdminEmailList()
]);
return $this->session->isSiteAdmin();
}
/**
* Fetch the user id
* @return int User id
* @deprecated 2022.03
* @see IHandleUserSessions::getLocalUserId()
*/
public function getLoggedInUserId(): int
{
return $this->user_id;
return $this->session->getLocalUserId();
}
/**
* Fetch the user nick name
* @return string User's nickname
* @deprecated 2022.03
* @see IHandleUserSessions::getLocalUserNickname()
*/
public function getLoggedInUserNickname(): string
{
return $this->nickname;
return $this->session->getLocalUserNickname();
}
/**
@ -324,8 +297,7 @@ class App
*/
public function getBasePath(): string
{
// Don't use the basepath of the config table for basepath (it should always be the config-file one)
return $this->config->getCache()->get('system', 'basepath');
return $this->config->get('system', 'basepath');
}
/**
@ -385,10 +357,8 @@ class App
$this->profiler->reset();
if ($this->mode->has(App\Mode::DBAVAILABLE)) {
$this->profiler->update($this->config);
Core\Hook::loadHooks();
$loader = (new Config())->createConfigFileLoader($this->getBasePath(), $_SERVER);
$loader = (new Config())->createConfigFileManager($this->getBasePath(), $_SERVER);
Core\Hook::callAll('load_config', $loader);
// Hooks are now working, reload the whole definitions with hook enabled
@ -421,7 +391,7 @@ class App
}
/**
* Returns the current theme name. May be overriden by the mobile theme name.
* Returns the current theme name. May be overridden by the mobile theme name.
*
* @return string Current theme name or empty string in installation phase
* @throws Exception
@ -562,7 +532,7 @@ class App
/**
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
* @return string Current theme's stylsheet path
* @return string Current theme's stylesheet path
* @throws Exception
*/
public function getCurrentThemeStylesheetPath(): string
@ -570,25 +540,6 @@ class App
return Core\Theme::getStylesheetPath($this->getCurrentTheme());
}
/**
* Sets the base url for use in cmdline programs which don't have
* $_SERVER variables
*/
public function checkURL()
{
$url = $this->config->get('system', 'url');
// if the url isn't set or the stored url is radically different
// than the currently visited url, store the current value accordingly.
// "Radically different" ignores common variations such as http vs https
// and www.example.com vs example.com.
// We will only change the url to an ip address if there is no existing setting
if (empty($url) || (!Util\Strings::compareLink($url, $this->baseURL->get())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->baseURL->getHostname()))) {
$this->config->set('system', 'url', $this->baseURL->get());
}
}
/**
* Frontend App script
*
@ -601,13 +552,15 @@ class App
* @param IManagePersonalConfigValues $pconfig
* @param Authentication $auth The Authentication backend of the node
* @param App\Page $page The Friendica page printing container
* @param ModuleHTTPException $httpException The possible HTTP Exception container
* @param HTTPInputData $httpInput A library for processing PHP input streams
* @param float $start_time The start time of the overall script execution
* @param array $server The $_SERVER array
*
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, HTTPInputData $httpInput, float $start_time)
public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, Nav $nav, ModuleHTTPException $httpException, HTTPInputData $httpInput, float $start_time, array $server)
{
$this->profiler->set($start_time, 'start');
$this->profiler->set(microtime(true), 'classinit');
@ -623,10 +576,12 @@ class App
if (!$this->mode->isInstall()) {
// Force SSL redirection
if ($this->baseURL->checkRedirectHttps()) {
System::externalRedirect($this->baseURL->get() . '/' . $this->args->getQueryString());
if ($this->config->get('system', 'force_ssl') &&
(empty($server['HTTPS']) || $server['HTTPS'] === 'off') &&
!empty($server['REQUEST_METHOD']) &&
$server['REQUEST_METHOD'] === 'GET') {
System::externalRedirect($this->baseURL . '/' . $this->args->getQueryString());
}
Core\Hook::callAll('init_1');
}
@ -686,8 +641,7 @@ class App
if ($this->mode->isInstall() && $moduleName !== 'install') {
$this->baseURL->redirect('install');
} else {
$this->checkURL();
Core\Update::check($this->getBasePath(), false, $this->mode);
Core\Update::check($this->getBasePath(), false);
Core\Addon::loadAddons();
Core\Hook::loadHooks();
}
@ -741,17 +695,17 @@ class App
$httpinput = $httpInput->process();
$input = array_merge($httpinput['variables'], $httpinput['files'], $request ?? $_REQUEST);
// Let the module run it's internal process (init, get, post, ...)
// Let the module run its internal process (init, get, post, ...)
$timestamp = microtime(true);
$response = $module->run($input);
$response = $module->run($httpException, $input);
$this->profiler->set(microtime(true) - $timestamp, 'content');
if ($response->getHeaderLine(ICanCreateResponses::X_HEADER) === ICanCreateResponses::TYPE_HTML) {
$page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $this->session->getLocalUserId());
$page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId());
} else {
$page->exit($response);
}
} catch (HTTPException $e) {
(new ModuleHTTPException())->rawContent($e);
$httpException->rawContent($e);
}
$page->logRuntime($this->config, 'runFrontend');
}

View file

@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*

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