diff --git a/.gitignore b/.gitignore index 8d86b95875..9e6504184c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ include/jquery-1.4.2.min.js favicon.* home.html addon +*.orig *~ robots.txt @@ -57,4 +58,4 @@ venv/ /view/asset #ignore config files from JetBrains -/.idea \ No newline at end of file +/.idea diff --git a/.travis.yml b/.travis.yml index d3fffc6936..d68b7727e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,10 @@ --- language: php -php: 5.6 +## Friendica supports PHP version >= 5.6 +php: + - 5.6 + - 7.0 + - 7.1 + - 7.2 + install: composer install diff --git a/boot.php b/boot.php index 217a5f4e1d..ba12f86d2c 100644 --- a/boot.php +++ b/boot.php @@ -232,10 +232,11 @@ define('ACCOUNT_TYPE_RELAY', 4); * Type of the community page * @{ */ -define('CP_NO_COMMUNITY_PAGE', -1); -define('CP_USERS_ON_SERVER', 0); -define('CP_GLOBAL_COMMUNITY', 1); -define('CP_USERS_AND_GLOBAL', 2); +define('CP_NO_INTERNAL_COMMUNITY', -2); +define('CP_NO_COMMUNITY_PAGE', -1); +define('CP_USERS_ON_SERVER', 0); +define('CP_GLOBAL_COMMUNITY', 1); +define('CP_USERS_AND_GLOBAL', 2); /** * @} */ @@ -1291,7 +1292,7 @@ function get_server() $server = Config::get("system", "directory"); if ($server == "") { - $server = "http://dir.friendica.social"; + $server = "https://dir.friendica.social"; } return($server); diff --git a/doc/Account-Basics.md b/doc/Account-Basics.md index 7883a346fd..da865ad2b5 100644 --- a/doc/Account-Basics.md +++ b/doc/Account-Basics.md @@ -16,19 +16,19 @@ If you'd like to have your own server, you can do that too. Visit [the Friendica website](http://friendi.ca/) to download the code with setup instructions. It's a very simple installation process that anybody experienced in hosting websites, or with basic Linux experience can handle easily. -###OpenID +### OpenID The first field on the Registration page is for an OpenID address. If you do not have an OpenID address or do not wish to use OpenID, leave this field blank. If you have an OpenID account elsewhere and wish to use it, enter the address into this field and click 'Register'. Friendica will attempt to extract as much information as possible from your OpenID provider and return to this page with those items already filled in. -###Your Full Name +### Your Full Name Please provide your full name **as you would like it to be displayed on this system**. Most people use their real name for this, but you're under no obligation to do so yourself. -###Email Address +### Email Address Please provide a valid email address. Your email address is **never** published. @@ -38,7 +38,7 @@ This doesn't have to be your primary email address, but it does need to be a rea You can't get your initial password, or reset a lost password later without it. This is the only bit of personal information that has to be accurate. -###Nickname +### Nickname A nickname is used to generate web addresses for many of your personal pages, and is also treated like an email address when establishing communications with others. Due to the way that the nickname is used, it has some limitations. @@ -47,7 +47,7 @@ It also must be unique on this system. This is used in many places to identify your account, and once set it cannot be changed. -###Directory Publishing +### Directory Publishing The registration form also allows you to choose whether or not to list your account in the online directory of your node. This is like a "phone book" and you may choose to be unlisted. @@ -55,7 +55,7 @@ We recommend that you select 'Yes' so that other people (friends, family, etc.) If you choose 'No', you will essentially be invisible and have few opportunities for interaction. Whichever you choose, this can be changed any time from your Settings page after you login. -###Register +### Register Once you have provided the necessary details, click the 'Register' button. An email will be sent to you providing your account login details. diff --git a/doc/Addons.md b/doc/Addons.md index 4df91864bc..f7d93aac7a 100644 --- a/doc/Addons.md +++ b/doc/Addons.md @@ -126,8 +126,8 @@ $b contains the $a->user array. 'display_item' is called when formatting a post for display. $b is an array: - 'item' => The item (array) details pulled from the database - 'output' => the (string) HTML representation of this item prior to adding it to the page + 'item' => The item (array) details pulled from the database + 'output' => the (string) HTML representation of this item prior to adding it to the page ### 'post_local' * called when a status post or comment is entered on the local system @@ -167,8 +167,8 @@ $b is an array: 'profile_edit' is called prior to output of profile edit page. $b is an array containing: - 'profile' => profile (array) record from the database - 'entry' => the (string) HTML of the generated entry + 'profile' => profile (array) record from the database + 'entry' => the (string) HTML of the generated entry ### 'profile_advanced' * called when the HTML is generated for the 'Advanced profile', corresponding to the 'Profile' tab within a person's profile page @@ -179,7 +179,7 @@ $b is an array containing: 'directory_item' is called from the Directory page when formatting an item for display. $b is an array: - 'contact' => contact (array) record for the person from the database + 'contact' => contact (array) record for the person from the database 'entry' => the (string) HTML of the generated entry ### 'profile_sidebar_enter' @@ -190,15 +190,15 @@ $b is an array: 'profile_sidebar is called when generating the sidebar "short" profile for a page. $b is an array: - 'profile' => profile (array) record for the person from the database - 'entry' => the (string) HTML of the generated entry + 'profile' => profile (array) record for the person from the database + 'entry' => the (string) HTML of the generated entry ### 'contact_block_end' is called when formatting the block of contacts/friends on a profile sidebar has completed. $b is an array: - 'contacts' => array of contacts - 'output' => the (string) generated HTML of the contact block + 'contacts' => array of contacts + 'output' => the (string) generated HTML of the contact block ### 'bbcode' * called during conversion of bbcode to html @@ -216,8 +216,8 @@ $b is an array: 'personal_xrd' is called prior to output of personal XRD file. $b is an array: - 'user' => the user record for the person - 'xml' => the complete XML to be output + 'user' => the user record for the person + 'xml' => the complete XML to be output ### 'home_content' * called prior to output home page content, shown to unlogged users @@ -227,8 +227,8 @@ $b is an array: is called when editing contact details on an individual from the Contacts page. $b is an array: - 'contact' => contact record (array) of target contact - 'output' => the (string) generated HTML of the contact edit page + 'contact' => contact record (array) of target contact + 'output' => the (string) generated HTML of the contact edit page ### 'contact_edit_post' * called when posting the contact edit page. @@ -246,9 +246,9 @@ $b is an array: 'avatar_lookup' is called when looking up the avatar. $b is an array: - 'size' => the size of the avatar that will be looked up - 'email' => email to look up the avatar for - 'url' => the (string) generated URL of the avatar + 'size' => the size of the avatar that will be looked up + 'email' => email to look up the avatar for + 'url' => the (string) generated URL of the avatar ### 'emailer_send_prepare' 'emailer_send_prepare' called from Emailer::send() before building the mime message. @@ -306,199 +306,315 @@ Hook data: Called after the HTML conversion in prepare_body. Hook data: 'item' => item array (input) - 'html' => converted item body (input/output) - 'is_preview' => post preview flag (input) + 'html' => converted item body (input/output) + 'is_preview' => post preview flag (input) 'filter_reasons' => reasons array (input) ### 'prepare_body_final' Called at the end of prepare_body. Hook data: 'item' => item array (input) - 'html' => converted item body (input/output) + 'html' => converted item body (input/output) Complete list of hook callbacks --- Here is a complete list of all hook callbacks with file locations (as of 01-Apr-2018). Please see the source for details of any hooks not documented above. -index.php: Addon::callHooks('init_1'); -index.php: Addon::callHooks('app_menu', $arr); -index.php: Addon::callHooks('page_content_top', $a->page['content']); -index.php: Addon::callHooks($a->module.'_mod_init', $placeholder); -index.php: Addon::callHooks($a->module.'_mod_init', $placeholder); -index.php: Addon::callHooks($a->module.'_mod_post', $_POST); -index.php: Addon::callHooks($a->module.'_mod_afterpost', $placeholder); -index.php: Addon::callHooks($a->module.'_mod_content', $arr); -index.php: Addon::callHooks($a->module.'_mod_aftercontent', $arr); -index.php: Addon::callHooks('page_end', $a->page['content']); +### index.php -include/api.php: Addon::callHooks('logged_in', $a->user); -include/api.php: Addon::callHooks('authenticate', $addon_auth); -include/api.php: Addon::callHooks('logged_in', $a->user); + Addon::callHooks('init_1'); + Addon::callHooks('app_menu', $arr); + Addon::callHooks('page_content_top', $a->page['content']); + Addon::callHooks($a->module.'_mod_init', $placeholder); + Addon::callHooks($a->module.'_mod_init', $placeholder); + Addon::callHooks($a->module.'_mod_post', $_POST); + Addon::callHooks($a->module.'_mod_afterpost', $placeholder); + Addon::callHooks($a->module.'_mod_content', $arr); + Addon::callHooks($a->module.'_mod_aftercontent', $arr); + Addon::callHooks('page_end', $a->page['content']); + +### include/api.php -include/enotify.php: Addon::callHooks('enotify', $h); -include/enotify.php: Addon::callHooks('enotify_store', $datarray); -include/enotify.php: Addon::callHooks('enotify_mail', $datarray); -include/enotify.php: Addon::callHooks('check_item_notification', $notification_data); + Addon::callHooks('logged_in', $a->user); + Addon::callHooks('authenticate', $addon_auth); + Addon::callHooks('logged_in', $a->user); -include/conversation.php: Addon::callHooks('conversation_start', $cb); -include/conversation.php: Addon::callHooks('render_location', $locate); -include/conversation.php: Addon::callHooks('display_item', $arr); -include/conversation.php: Addon::callHooks('display_item', $arr); -include/conversation.php: Addon::callHooks('item_photo_menu', $args); -include/conversation.php: Addon::callHooks('jot_tool', $jotplugins); +### include/enotify.php + + Addon::callHooks('enotify', $h); + Addon::callHooks('enotify_store', $datarray); + Addon::callHooks('enotify_mail', $datarray); + Addon::callHooks('check_item_notification', $notification_data); + +### include/conversation.php -include/security.php: Addon::callHooks('logged_in', $a->user); + Addon::callHooks('conversation_start', $cb); + Addon::callHooks('render_location', $locate); + Addon::callHooks('display_item', $arr); + Addon::callHooks('display_item', $arr); + Addon::callHooks('item_photo_menu', $args); + Addon::callHooks('jot_tool', $jotplugins); -include/text.php: Addon::callHooks('contact_block_end', $arr); -include/text.php: Addon::callHooks('poke_verbs', $arr); -include/text.php: Addon::callHooks('prepare_body_init', $item); -include/text.php: Addon::callHooks('prepare_body_content_filter', $hook_data); -include/text.php: Addon::callHooks('prepare_body', $hook_data); -include/text.php: Addon::callHooks('prepare_body_final', $hook_data); +### include/security.php -include/items.php: Addon::callHooks('page_info_data', $data); + Addon::callHooks('logged_in', $a->user); -mod/directory.php: Addon::callHooks('directory_item', $arr); +### include/text.php -mod/xrd.php: Addon::callHooks('personal_xrd', $arr); + Addon::callHooks('contact_block_end', $arr); + Addon::callHooks('poke_verbs', $arr); + Addon::callHooks('prepare_body_init', $item); + Addon::callHooks('prepare_body_content_filter', $hook_data); + Addon::callHooks('prepare_body', $hook_data); + Addon::callHooks('prepare_body_final', $hook_data); -mod/ping.php: Addon::callHooks('network_ping', $arr); +### include/items.php -mod/parse_url.php: Addon::callHooks("parse_link", $arr); + Addon::callHooks('page_info_data', $data); -mod/manage.php: Addon::callHooks('home_init', $ret); +### mod/directory.php -mod/acl.php: Addon::callHooks('acl_lookup_end', $results); + Addon::callHooks('directory_item', $arr); -mod/network.php: Addon::callHooks('network_content_init', $arr); -mod/network.php: Addon::callHooks('network_tabs', $arr); +### mod/xrd.php -mod/friendica.php: Addon::callHooks('about_hook', $o); -mod/subthread.php: Addon::callHooks('post_local_end', $arr); + Addon::callHooks('personal_xrd', $arr); -mod/profiles.php: Addon::callHooks('profile_post', $_POST); -mod/profiles.php: Addon::callHooks('profile_edit', $arr); +### mod/ping.php -mod/settings.php: Addon::callHooks('addon_settings_post', $_POST); -mod/settings.php: Addon::callHooks('connector_settings_post', $_POST); -mod/settings.php: Addon::callHooks('display_settings_post', $_POST); -mod/settings.php: Addon::callHooks('settings_post', $_POST); -mod/settings.php: Addon::callHooks('addon_settings', $settings_addons); -mod/settings.php: Addon::callHooks('connector_settings', $settings_connectors); -mod/settings.php: Addon::callHooks('display_settings', $o); -mod/settings.php: Addon::callHooks('settings_form', $o); + Addon::callHooks('network_ping', $arr); -mod/photos.php: Addon::callHooks('photo_post_init', $_POST); -mod/photos.php: Addon::callHooks('photo_post_file', $ret); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', intval($item_id)); -mod/photos.php: Addon::callHooks('photo_upload_form', $ret); +### mod/parse_url.php -mod/profile.php: Addon::callHooks('profile_advanced', $o); + Addon::callHooks("parse_link", $arr); -mod/home.php: Addon::callHooks('home_init', $ret); -mod/home.php: Addon::callHooks("home_content", $content); +### mod/manage.php -mod/poke.php: Addon::callHooks('post_local_end', $arr); + Addon::callHooks('home_init', $ret); -mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST); -mod/contacts.php: Addon::callHooks('contact_edit', $arr); +### mod/acl.php -mod/tagger.php: Addon::callHooks('post_local_end', $arr); + Addon::callHooks('acl_lookup_end', $results); -mod/lockview.php: Addon::callHooks('lockview_content', $item); +### mod/network.php -mod/uexport.php: Addon::callHooks('uexport_options', $options); + Addon::callHooks('network_content_init', $arr); + Addon::callHooks('network_tabs', $arr); -mod/register.php: Addon::callHooks('register_post', $arr); -mod/register.php: Addon::callHooks('register_form', $arr); +### mod/friendica.php -mod/item.php: Addon::callHooks('post_local_start', $_REQUEST); -mod/item.php: Addon::callHooks('post_local', $datarray); -mod/item.php: Addon::callHooks('post_local_end', $datarray); + Addon::callHooks('about_hook', $o); + +### mod/subthread.php -mod/editpost.php: Addon::callHooks('jot_tool', $jotplugins); + Addon::callHooks('post_local_end', $arr); -src/Network/FKOAuth1.php: Addon::callHooks('logged_in', $a->user); +### mod/profiles.php -src/Render/FriendicaSmartyEngine.php: Addon::callHooks("template_vars", $arr); + Addon::callHooks('profile_post', $_POST); + Addon::callHooks('profile_edit', $arr); -src/Model/Item.php: Addon::callHooks('post_local', $item); -src/Model/Item.php: Addon::callHooks('post_remote', $item); -src/Model/Item.php: Addon::callHooks('post_local_end', $posted_item); -src/Model/Item.php: Addon::callHooks('post_remote_end', $posted_item); -src/Model/Item.php: Addon::callHooks('tagged', $arr); -src/Model/Item.php: Addon::callHooks('post_local_end', $new_item); +### mod/settings.php -src/Model/Contact.php: Addon::callHooks('contact_photo_menu', $args); -src/Model/Contact.php: Addon::callHooks('follow', $arr); + Addon::callHooks('addon_settings_post', $_POST); + Addon::callHooks('connector_settings_post', $_POST); + Addon::callHooks('display_settings_post', $_POST); + Addon::callHooks('settings_post', $_POST); + Addon::callHooks('addon_settings', $settings_addons); + Addon::callHooks('connector_settings', $settings_connectors); + Addon::callHooks('display_settings', $o); + Addon::callHooks('settings_form', $o); -src/Model/Profile.php: Addon::callHooks('profile_sidebar_enter', $profile); -src/Model/Profile.php: Addon::callHooks('profile_sidebar', $arr); -src/Model/Profile.php: Addon::callHooks('profile_tabs', $arr); -src/Model/Profile.php: Addon::callHooks('zrl_init', $arr); +### mod/photos.php -src/Model/Event.php: Addon::callHooks('event_updated', $event['id']); -src/Model/Event.php: Addon::callHooks("event_created", $event['id']); + Addon::callHooks('photo_post_init', $_POST); + Addon::callHooks('photo_post_file', $ret); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', intval($item_id)); + Addon::callHooks('photo_upload_form', $ret); -src/Model/User.php: Addon::callHooks('register_account', $uid); -src/Model/User.php: Addon::callHooks('remove_user', $user); +### mod/profile.php -src/Content/Text/BBCode.php: Addon::callHooks('bbcode', $text); -src/Content/Text/BBCode.php: Addon::callHooks('bb2diaspora', $text); + Addon::callHooks('profile_advanced', $o); -src/Content/Text/HTML.php: Addon::callHooks('html2bbcode', $message); +### mod/home.php -src/Content/Smilies.php: Addon::callHooks('smilie', $params); + Addon::callHooks('home_init', $ret); + Addon::callHooks("home_content", $content); -src/Content/Feature.php: Addon::callHooks('isEnabled', $arr); -src/Content/Feature.php: Addon::callHooks('get', $arr); +### mod/poke.php -src/Content/ContactSelector.php: Addon::callHooks('network_to_name', $nets); -src/Content/ContactSelector.php: Addon::callHooks('gender_selector', $select); -src/Content/ContactSelector.php: Addon::callHooks('sexpref_selector', $select); -src/Content/ContactSelector.php: Addon::callHooks('marital_selector', $select); + Addon::callHooks('post_local_end', $arr); -src/Content/OEmbed.php: Addon::callHooks('oembed_fetch_url', $embedurl, $j); +### mod/contacts.php -src/Content/Nav.php: Addon::callHooks('page_header', $a->page['nav']); -src/Content/Nav.php: Addon::callHooks('nav_info', $nav); + Addon::callHooks('contact_edit_post', $_POST); + Addon::callHooks('contact_edit', $arr); -src/Worker/Directory.php: Addon::callHooks('globaldir_update', $arr); -src/Worker/Notifier.php: Addon::callHooks('notifier_end', $target_item); -src/Worker/Queue.php: Addon::callHooks('queue_predeliver', $r); -src/Worker/Queue.php: Addon::callHooks('queue_deliver', $params); +### mod/tagger.php -src/Module/Login.php: Addon::callHooks('authenticate', $addon_auth); -src/Module/Login.php: Addon::callHooks('login_hook', $o); -src/Module/Logout.php: Addon::callHooks("logging_out"); + Addon::callHooks('post_local_end', $arr); -src/Object/Post.php: Addon::callHooks('render_location', $locate); -src/Object/Post.php: Addon::callHooks('display_item', $arr); +### mod/lockview.php -src/Core/ACL.php: Addon::callHooks('contact_select_options', $x); -src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr); -src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o); -src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr); -src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o); -src/Core/ACL.php: Addon::callHooks('jot_networks', $jotnets); + Addon::callHooks('lockview_content', $item); -src/Core/Worker.php: Addon::callHooks("proc_run", $arr); +### mod/uexport.php -src/Util/Emailer.php: Addon::callHooks('emailer_send_prepare', $params); -src/Util/Emailer.php: Addon::callHooks("emailer_send", $hookdata); + Addon::callHooks('uexport_options', $options); -src/Util/Map.php: Addon::callHooks('generate_map', $arr); -src/Util/Map.php: Addon::callHooks('generate_named_map', $arr); -src/Util/Map.php: Addon::callHooks('Map::getCoordinates', $arr); +### mod/register.php -src/Util/Network.php: Addon::callHooks('avatar_lookup', $avatar); + Addon::callHooks('register_post', $arr); + Addon::callHooks('register_form', $arr); -src/Util/ParseUrl.php: Addon::callHooks("getsiteinfo", $siteinfo); +### mod/item.php -src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom); -src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom); + Addon::callHooks('post_local_start', $_REQUEST); + Addon::callHooks('post_local', $datarray); + Addon::callHooks('post_local_end', $datarray); + +### mod/editpost.php + + Addon::callHooks('jot_tool', $jotplugins); + +### src/Network/FKOAuth1.php + + Addon::callHooks('logged_in', $a->user); + +### src/Render/FriendicaSmartyEngine.php + + Addon::callHooks("template_vars", $arr); + +### src/Model/Item.php + + Addon::callHooks('post_local', $item); + Addon::callHooks('post_remote', $item); + Addon::callHooks('post_local_end', $posted_item); + Addon::callHooks('post_remote_end', $posted_item); + Addon::callHooks('tagged', $arr); + Addon::callHooks('post_local_end', $new_item); + +### src/Model/Contact.php + + Addon::callHooks('contact_photo_menu', $args); + Addon::callHooks('follow', $arr); + +### src/Model/Profile.php + + Addon::callHooks('profile_sidebar_enter', $profile); + Addon::callHooks('profile_sidebar', $arr); + Addon::callHooks('profile_tabs', $arr); + Addon::callHooks('zrl_init', $arr); + +### src/Model/Event.php + + Addon::callHooks('event_updated', $event['id']); + Addon::callHooks("event_created", $event['id']); + +### src/Model/User.php + + Addon::callHooks('register_account', $uid); + Addon::callHooks('remove_user', $user); + +### src/Content/Text/BBCode.php + + Addon::callHooks('bbcode', $text); + Addon::callHooks('bb2diaspora', $text); + +### src/Content/Text/HTML.php + + Addon::callHooks('html2bbcode', $message); + +### src/Content/Smilies.php + + Addon::callHooks('smilie', $params); + +### src/Content/Feature.php + + Addon::callHooks('isEnabled', $arr); + Addon::callHooks('get', $arr); + +### src/Content/ContactSelector.php + + Addon::callHooks('network_to_name', $nets); + Addon::callHooks('gender_selector', $select); + Addon::callHooks('sexpref_selector', $select); + Addon::callHooks('marital_selector', $select); + +### src/Content/OEmbed.php + + Addon::callHooks('oembed_fetch_url', $embedurl, $j); + +### src/Content/Nav.php + + Addon::callHooks('page_header', $a->page['nav']); + Addon::callHooks('nav_info', $nav); + +### src/Worker/Directory.php + + Addon::callHooks('globaldir_update', $arr); + +### src/Worker/Notifier.php + + Addon::callHooks('notifier_end', $target_item); + +### src/Worker/Queue.php + + Addon::callHooks('queue_predeliver', $r); + Addon::callHooks('queue_deliver', $params); + +### src/Module/Login.php + + Addon::callHooks('authenticate', $addon_auth); + Addon::callHooks('login_hook', $o); + +### src/Module/Logout.php + + Addon::callHooks("logging_out"); + +### src/Object/Post.php + + Addon::callHooks('render_location', $locate); + Addon::callHooks('display_item', $arr); + +### src/Core/ACL.php + + Addon::callHooks('contact_select_options', $x); + Addon::callHooks($a->module.'_pre_'.$selname, $arr); + Addon::callHooks($a->module.'_post_'.$selname, $o); + Addon::callHooks($a->module.'_pre_'.$selname, $arr); + Addon::callHooks($a->module.'_post_'.$selname, $o); + Addon::callHooks('jot_networks', $jotnets); + +### src/Core/Worker.php + + Addon::callHooks("proc_run", $arr); + +### src/Util/Emailer.php + + Addon::callHooks('emailer_send_prepare', $params); + Addon::callHooks("emailer_send", $hookdata); + +### src/Util/Map.php + + Addon::callHooks('generate_map', $arr); + Addon::callHooks('generate_named_map', $arr); + Addon::callHooks('Map::getCoordinates', $arr); + +### src/Util/Network.php + + Addon::callHooks('avatar_lookup', $avatar); + +### src/Util/ParseUrl.php + + Addon::callHooks("getsiteinfo", $siteinfo); + +### src/Protocol/DFRN.php + + Addon::callHooks('atom_feed_end', $atom); + Addon::callHooks('atom_feed_end', $atom); diff --git a/doc/Chats.md b/doc/Chats.md index b7557944f3..29067e1280 100644 --- a/doc/Chats.md +++ b/doc/Chats.md @@ -37,7 +37,7 @@ You can use several servers to create an account: * [https://jappix.com](https://jappix.com) * [http://xmpp.net](http://xmpp.net) -###1. Basics +### 1. Basics At first you have to get the current version. You can either pull it from [Github](https://github.com) like so: @@ -54,7 +54,7 @@ The following page shows the settings of this addon. Activate the BOSH proxy. -###2. Settings +### 2. Settings Go to your user account settings next and choose the addon page. Scroll down until you find the Jappix Mini addon settings. diff --git a/doc/Improve-Performance.md b/doc/Improve-Performance.md index 48ac9e798d..79490c2573 100644 --- a/doc/Improve-Performance.md +++ b/doc/Improve-Performance.md @@ -29,7 +29,7 @@ Active the following addons: rendertime -###rendertime +### rendertime This addon doesn't speed up your system. It helps to analyze your bottlenecks. @@ -52,7 +52,7 @@ Apache Webserver The following Apache modules are recommended: -###Cache-Control +### Cache-Control This module tells the client to cache the content of static files so that they aren't fetched with every request. Enable the module "mod_expires" by typing in "a2enmod expires" as root. @@ -62,7 +62,7 @@ Please add the following lines to your site configuration in the "directory" con Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_expires.html) / [2.4](https://httpd.apache.org/docs/2.4/mod/mod_expires.html) documentation. -###Compress content +### Compress content This module compresses the traffic between the web server and the client. Enable the module "mod_deflate" by typing in "a2enmod deflate" as root. @@ -72,14 +72,14 @@ Also see the Apache [2.2](http://httpd.apache.org/docs/2.2/mod/mod_deflate.html) PHP -------- -###FCGI +### FCGI When using Apache think about using FCGI. In a Debian-based distribution you will need to install the packages named "php5-cgi" and "libapache2-mod-fcgid". Please refer to external documentation for a more detailed explanation how to set up a system based upon FCGI. -###Database +### 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. diff --git a/doc/Install.md b/doc/Install.md index b9b2debb42..2a80cf72a9 100644 --- a/doc/Install.md +++ b/doc/Install.md @@ -2,6 +2,7 @@ Friendica Installation =============== We've tried very hard to ensure that Friendica will run on commodity hosting platforms - such as those used to host Wordpress blogs and Drupal websites. +We offer a manual and an automatic installation. But be aware that Friendica is more than a simple web application. It is a complex communications system which more closely resembles an email server than a web server. For reliability and performance, messages are delivered in the background and are queued for later delivery when sites are down. @@ -27,10 +28,10 @@ Requirements * Apache with mod-rewrite enabled and "Options All" so you can use a local .htaccess file * PHP 5.6+ (PHP 7 is recommended for performance) -* PHP *command line* access with register_argc_argv set to true in the php.ini file -* Curl, GD, PDO, MySQLi, hash, xml, zip and OpenSSL extensions -* The POSIX module of PHP needs to be activated (e.g. [RHEL, CentOS](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) have disabled it) -* some form of email server or email gateway such that PHP mail() works + * PHP *command line* access with register_argc_argv set to true in the php.ini file + * Curl, GD, PDO, MySQLi, hash, xml, zip and OpenSSL extensions + * The POSIX module of PHP needs to be activated (e.g. [RHEL, CentOS](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) have disabled it) + * some form of email server or email gateway such that PHP mail() works * Mysql 5.5.3+ or an equivalant alternative for MySQL (MariaDB, Percona Server etc.) * the ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows) (Note: other options are presented in Section 7 of this document.) * Installation into a top-level domain or sub-domain (without a directory/path component in the URL) is preferred. Directory paths will not be as convenient to use and have not been thoroughly tested. @@ -79,24 +80,49 @@ In this case find the [mysqld] section in your my.cnf file and add the line : Restart mysql and you should be fine. - -### Run the installer +### Option A: Run the manual installer Point your web browser to the new site and follow the instructions. Please note any error messages and correct these before continuing. If you need to specify a port for the connection to the database, you can do so in the host name setting for the database. -*If* the automated installation fails for any reason, check the following: +*If* the manual installation fails for any reason, check the following: * Does ".htconfig.php" exist? If not, edit htconfig.php and change the system settings. Rename to .htconfig.php -* Is the database is populated? If not, import the contents of "database.sql" with phpmyadmin or mysql command line. +* Is the database is populated? If not, import the contents of "database.sql" with phpmyadmin or the mysql command line. At this point visit your website again, and register your personal account. Registration errors should all be recoverable automatically. If you get any *critical* failure at this point, it generally indicates the database was not installed correctly. You might wish to move/rename .htconfig.php to another name and empty (called 'dropping') the database tables, so that you can start fresh. +### Option B: Run the automatic install script + +Open the file htconfig.php in the main Friendica directory with a text editor. +Remove the `die('...');` line and edit the lines to suit your installation (MySQL, language, theme etc.). +Then save the file (do not rename it). + +Navigate to the main Friendica directory and execute the following command: + + bin/console autoinstall + +Or if you wish to include all optional checks, execute this statement instead: + + bin/console autoinstall -a + +At this point visit your website again, and register your personal account. + +*If* the automatic installation fails for any reason, check the following: + +* Does ".htconfig.php" already exist? If yes, the automatic installation won't start +* Are the settings inside "htconfig.php" correct? If not, edit the file again. +* Is the empty MySQL-database created? If not, create it. + +For more information during the installation, you can use this command line option + + bin/console autoinstall -v + ### Set up the worker Set up a cron job or scheduled task to run the worker once every 5-10 minutes in order to perform background processing. diff --git a/doc/Installing-Connectors.md b/doc/Installing-Connectors.md index 1d83f07420..5ea34d4733 100644 --- a/doc/Installing-Connectors.md +++ b/doc/Installing-Connectors.md @@ -32,7 +32,7 @@ Twitter Addon for Friendica * tobias.diekershoff@gmx.net * License: 3-clause BSD license -###Configuration +### Configuration To use this addon you need a OAuth Consumer key pair (key & secret). You can get it from [Twitter](https://twitter.com/apps). @@ -46,7 +46,7 @@ Add this key pair to your global .htconfig.php: After this, your users can configure their Twitter account settings from "Settings -> Connector Settings". -###More documentation +### More documentation Find the author's documentation here: [http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin](http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin) @@ -58,7 +58,7 @@ GNU Social Addon for Friendica * tobias.diekershoff@gmx.net * License: 3-clause BSD license -###Configuration +### Configuration When the addon is activated the user has to acquire the following in order to connect to the GNU Social account of choice. diff --git a/doc/Making-Friends.md b/doc/Making-Friends.md index d7f18298c5..e435dc7a4b 100644 --- a/doc/Making-Friends.md +++ b/doc/Making-Friends.md @@ -50,7 +50,7 @@ This will take you through a similar process. Connect to users of alternate networks --- -###Across the Federation and Fedivese +### Across the Federation and Fedivese You can also use your Identity Address or other people's Identity Addresses to become friends across the so-called Federation/Fedivese of open source social media. Currently, Friendica supports connections with people on diaspora*, Red, Hubzilla, GNU Social, StatusNet, Mastodon, Pleroma, socialhome, and ganggo platforms. @@ -60,13 +60,13 @@ Note: Some versions of GNU Social software may require the full URL to your prof People on these networks can also initiate contact with you, if they know your contact details. -###Other social media +### Other social media If you server provides this functionality, you can also connect with people one Twitter or important feeds from Tumblr, Wordpress, and many more. To connect, enter their contact details in the "connect" box on your "Contacts" page. -###Email +### Email If you have supplied your mailbox connection information on your Settings page, you can enter the email address of anybody that has sent you a message recently and have their email messages show up in your social stream. You can also reply to them from within Friendica. @@ -76,7 +76,7 @@ In order to avoid abuse or spam, you must have an email from Alice with the corr Subscribing to mailing lists is done in the same way, but without the use of the "mailto:" prefix. To subscribe to a mailing list, enter the email in following example format "mailling-list@list-server.net". -###Syndication feeds +### Syndication feeds You can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.). If we can find an information stream and a name to attach to the contact, we'll try to connect with them. diff --git a/doc/Profiles.md b/doc/Profiles.md index 715d27d957..aceb94da39 100644 --- a/doc/Profiles.md +++ b/doc/Profiles.md @@ -4,35 +4,32 @@ Profiles * [Home](help) Friendica has unlimited profiles. -You may use different profiles to show different "sides of yourself" to different audiences. +You may use different profiles to present different aspects of yourself to different audiences. Default / public profile --- You always have a profile known as your "default" or "public" profile. -This profile is always available to the general public and cannot be hidden (there may be rare exceptions on privately run or disconnected sites). -You may, and probably should restrict the information you make available on your public profile. +This profile is always available to the general public and usually cannot be hidden. +You may, and probably should restrict the personal information you make available on your public profile. That said, if you want other friends to be able to find you, it helps to have the following information in your public profile: * Your real name * A photo of **you** -* Your location on the planet, at least to a country level. +* Your location, preferably at least the country. -Without this basic information, you could get very lonely here. -Most people (even your best friends) will not try and connect with somebody that has a fake name or doesn't contain a real photo. - -In addition, if you'd like to meet people that share some general interests with you, please take a moment and add some "Public Keywords" to your profile. +In addition, if you'd like to meet people that share some general interests with you, add some "Public Keywords" to your profile. Such as "music, linux, photography" or whatever. You can add as many keywords as you like. Your default or public profile is also shown to contacts on other networks, since they do not have the ability to view your private profiles. -Only members of the Friendica network can see alternate/private profiles. +Only members of the Friendica network can see alternate/ private profiles. -Alternate profiles +Alternate/ private profiles --- To create an alternate profile, select "Profiles" from the menu of your Friendica site. You may edit an existing profile, change the profile photo, or create a new profile. -You may also create a "clone" of an existing profile if you only wish to change a few items but don't wish to enter all the information again. +You may also "clone" your existing profile if you only wish to change a few items but don't wish to enter all the information again. To assign a profile to specific persons, select the person from your "Contacts" page and click the pencil "Edit" icon. You will find a dropdown box listing the various profiles available. @@ -51,17 +48,13 @@ You may also be able to comment directly on posts from while visiting the other There are two settings which allow you to publish your profile to a directory and ensure that it can be found by others. You can change these through settings on the "Settings" page. One setting allows you to publish your profile in the site directory of this Friendica server. -Another option (this may have been disabled by the site creator) allows you to publish your profile in the "Global Directory". -This is a mega directory which contains people from many other Friendica installations world-wide. +Another option (this may have been disabled by the site admin) allows you to publish your profile in a [Global Directory](Making-Friends.md#the-directories). -If you do not wish to be visible to any of these sites, you may leave your profile unpublished. +If you do not wish to be visible to any of these directories, do not published your profile. Although you may have multiple profiles, you only have one profile photo. -This is intentional. -In early tests we experimented with different photos for each profile and found it was very confusing for people. -They might see a different picture depending on what website they visited or what conversation they were in, and often alerted them to the fact that other people might be able to see different profiles of you than they could see. - -(But you can use the rich-text information boxes within a profile such as "Tell us about yourself" and link other photos onto the page.) +This is intentional; it avoids confusion by potentially seeing different profile pictures of a contact depending on what website you visit or conversation you participate in. +You can always can use the free text information boxes within a profile such as "Tell us about yourself" and link other photos for yourself. Keywords and Directory Search --- @@ -70,8 +63,7 @@ The search is typically for your nickname or part of your full name. However this search will also match against other profile fields - such as gender, location, "about", work, and education. You may also include "Keywords" in your default profile - which may be used to search for common interests with other members. You have two sets of keywords available - public and private. -Private keywords are *not* visible to anybody. -You could use these keywords to locate people who share membership in secret societies, or that share a love of fishing (for example) - without making this information visible on your public profile. +Private keywords are *not* visible on your profile, but will bring up your profile when matched in a search of the site directory. Public keywords are used in the friend suggestion tool and although they aren't readily visible, they may be seen by viewing the HTML of your profile page. Directory searches are also able to use "boolean" logic so that you can search for "+lesbian +Florida" and find those who's sexual preference (or keywords) contain the world "lesbian" and that live in Florida. @@ -79,7 +71,7 @@ See the section on "Topical Tags" on the [Tags-and-Mentions](help/Tags-and-Menti On your Contacts page is a link to "Find People with Shared Interests" (unless your site administrator has disabled the global directory). This will combine both your public and private keywords, and find people in the global directory who have matching and/or similar keywords. -(Your private keywords are not identified or stored on the global directory). +Private keywords are not identified or stored on the global directory. The more keywords you provide, the more relevant the search results that are returned. These are sorted by relevance. You may discover that you are the first person on the list - because you are very likely the most relevant match for your keywords in the directory. diff --git a/doc/de/Addons.md b/doc/de/Addons.md index 7651840f41..02be19e30b 100644 --- a/doc/de/Addons.md +++ b/doc/de/Addons.md @@ -101,7 +101,7 @@ Derzeitige Hooks **'post_remote'** - wird aufgerufen, wenn ein Beitrag aus einer anderen Quelle empfangen wird. Dies kann auch genutzt werden, um lokale Aktivitäten oder systemgenerierte Nachrichten zu veröffentlichen/posten. $b ist das Item-Array einer Information, die in der Datenbank und im Item gespeichert ist. - {Bitte beachte: der Seiteninhalt ist bbcode - nicht HTML) + {Bitte beachte: der Seiteninhalt ist bbcode - nicht HTML) **'settings_form'** - wird aufgerufen, wenn die HTML-Ausgabe für die Einstellungsseite generiert wird. $b ist die HTML-Ausgabe (String) der Einstellungsseite vor dem finalen ""-Tag. @@ -191,184 +191,300 @@ Komplette Liste der Hook-Callbacks Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Apr-2018 generiert): Bitte schau in die Quellcodes für Details zu Hooks, die oben nicht dokumentiert sind. -index.php: Addon::callHooks('init_1'); -index.php: Addon::callHooks('app_menu', $arr); -index.php: Addon::callHooks('page_content_top', $a->page['content']); -index.php: Addon::callHooks($a->module.'_mod_init', $placeholder); -index.php: Addon::callHooks($a->module.'_mod_init', $placeholder); -index.php: Addon::callHooks($a->module.'_mod_post', $_POST); -index.php: Addon::callHooks($a->module.'_mod_afterpost', $placeholder); -index.php: Addon::callHooks($a->module.'_mod_content', $arr); -index.php: Addon::callHooks($a->module.'_mod_aftercontent', $arr); -index.php: Addon::callHooks('page_end', $a->page['content']); +### index.php -include/api.php: Addon::callHooks('logged_in', $a->user); -include/api.php: Addon::callHooks('authenticate', $addon_auth); -include/api.php: Addon::callHooks('logged_in', $a->user); + Addon::callHooks('init_1'); + Addon::callHooks('app_menu', $arr); + Addon::callHooks('page_content_top', $a->page['content']); + Addon::callHooks($a->module.'_mod_init', $placeholder); + Addon::callHooks($a->module.'_mod_init', $placeholder); + Addon::callHooks($a->module.'_mod_post', $_POST); + Addon::callHooks($a->module.'_mod_afterpost', $placeholder); + Addon::callHooks($a->module.'_mod_content', $arr); + Addon::callHooks($a->module.'_mod_aftercontent', $arr); + Addon::callHooks('page_end', $a->page['content']); + +### include/api.php -include/enotify.php: Addon::callHooks('enotify', $h); -include/enotify.php: Addon::callHooks('enotify_store', $datarray); -include/enotify.php: Addon::callHooks('enotify_mail', $datarray); -include/enotify.php: Addon::callHooks('check_item_notification', $notification_data); + Addon::callHooks('logged_in', $a->user); + Addon::callHooks('authenticate', $addon_auth); + Addon::callHooks('logged_in', $a->user); -include/conversation.php: Addon::callHooks('conversation_start', $cb); -include/conversation.php: Addon::callHooks('render_location', $locate); -include/conversation.php: Addon::callHooks('display_item', $arr); -include/conversation.php: Addon::callHooks('display_item', $arr); -include/conversation.php: Addon::callHooks('item_photo_menu', $args); -include/conversation.php: Addon::callHooks('jot_tool', $jotplugins); +### include/enotify.php -include/security.php: Addon::callHooks('logged_in', $a->user); + Addon::callHooks('enotify', $h); + Addon::callHooks('enotify_store', $datarray); + Addon::callHooks('enotify_mail', $datarray); + Addon::callHooks('check_item_notification', $notification_data); + +### include/conversation.php -include/text.php: Addon::callHooks('contact_block_end', $arr); -include/text.php: Addon::callHooks('poke_verbs', $arr); -include/text.php: Addon::callHooks('prepare_body_init', $item); -include/text.php: Addon::callHooks('prepare_body_content_filter', $hook_data); -include/text.php: Addon::callHooks('prepare_body', $hook_data); -include/text.php: Addon::callHooks('prepare_body_final', $hook_data); + Addon::callHooks('conversation_start', $cb); + Addon::callHooks('render_location', $locate); + Addon::callHooks('display_item', $arr); + Addon::callHooks('display_item', $arr); + Addon::callHooks('item_photo_menu', $args); + Addon::callHooks('jot_tool', $jotplugins); -include/items.php: Addon::callHooks('page_info_data', $data); +### include/security.php -mod/directory.php: Addon::callHooks('directory_item', $arr); + Addon::callHooks('logged_in', $a->user); -mod/xrd.php: Addon::callHooks('personal_xrd', $arr); +### include/text.php -mod/ping.php: Addon::callHooks('network_ping', $arr); + Addon::callHooks('contact_block_end', $arr); + Addon::callHooks('poke_verbs', $arr); + Addon::callHooks('prepare_body_init', $item); + Addon::callHooks('prepare_body_content_filter', $hook_data); + Addon::callHooks('prepare_body', $hook_data); + Addon::callHooks('prepare_body_final', $hook_data); -mod/parse_url.php: Addon::callHooks("parse_link", $arr); +### include/items.php -mod/manage.php: Addon::callHooks('home_init', $ret); + Addon::callHooks('page_info_data', $data); -mod/acl.php: Addon::callHooks('acl_lookup_end', $results); +### mod/directory.php -mod/network.php: Addon::callHooks('network_content_init', $arr); -mod/network.php: Addon::callHooks('network_tabs', $arr); + Addon::callHooks('directory_item', $arr); -mod/friendica.php: Addon::callHooks('about_hook', $o); -mod/subthread.php: Addon::callHooks('post_local_end', $arr); +### mod/xrd.php -mod/profiles.php: Addon::callHooks('profile_post', $_POST); -mod/profiles.php: Addon::callHooks('profile_edit', $arr); + Addon::callHooks('personal_xrd', $arr); -mod/settings.php: Addon::callHooks('addon_settings_post', $_POST); -mod/settings.php: Addon::callHooks('connector_settings_post', $_POST); -mod/settings.php: Addon::callHooks('display_settings_post', $_POST); -mod/settings.php: Addon::callHooks('settings_post', $_POST); -mod/settings.php: Addon::callHooks('addon_settings', $settings_addons); -mod/settings.php: Addon::callHooks('connector_settings', $settings_connectors); -mod/settings.php: Addon::callHooks('display_settings', $o); -mod/settings.php: Addon::callHooks('settings_form', $o); +### mod/ping.php -mod/photos.php: Addon::callHooks('photo_post_init', $_POST); -mod/photos.php: Addon::callHooks('photo_post_file', $ret); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', $foo); -mod/photos.php: Addon::callHooks('photo_post_end', intval($item_id)); -mod/photos.php: Addon::callHooks('photo_upload_form', $ret); + Addon::callHooks('network_ping', $arr); -mod/profile.php: Addon::callHooks('profile_advanced', $o); +### mod/parse_url.php -mod/home.php: Addon::callHooks('home_init', $ret); -mod/home.php: Addon::callHooks("home_content", $content); + Addon::callHooks("parse_link", $arr); -mod/poke.php: Addon::callHooks('post_local_end', $arr); +### mod/manage.php -mod/contacts.php: Addon::callHooks('contact_edit_post', $_POST); -mod/contacts.php: Addon::callHooks('contact_edit', $arr); + Addon::callHooks('home_init', $ret); -mod/tagger.php: Addon::callHooks('post_local_end', $arr); +### mod/acl.php -mod/lockview.php: Addon::callHooks('lockview_content', $item); + Addon::callHooks('acl_lookup_end', $results); -mod/uexport.php: Addon::callHooks('uexport_options', $options); +### mod/network.php -mod/register.php: Addon::callHooks('register_post', $arr); -mod/register.php: Addon::callHooks('register_form', $arr); + Addon::callHooks('network_content_init', $arr); + Addon::callHooks('network_tabs', $arr); -mod/item.php: Addon::callHooks('post_local_start', $_REQUEST); -mod/item.php: Addon::callHooks('post_local', $datarray); -mod/item.php: Addon::callHooks('post_local_end', $datarray); +### mod/friendica.php -mod/editpost.php: Addon::callHooks('jot_tool', $jotplugins); + Addon::callHooks('about_hook', $o); + +### mod/subthread.php -src/Network/FKOAuth1.php: Addon::callHooks('logged_in', $a->user); + Addon::callHooks('post_local_end', $arr); -src/Render/FriendicaSmartyEngine.php: Addon::callHooks("template_vars", $arr); +### mod/profiles.php -src/Model/Item.php: Addon::callHooks('post_local', $item); -src/Model/Item.php: Addon::callHooks('post_remote', $item); -src/Model/Item.php: Addon::callHooks('post_local_end', $posted_item); -src/Model/Item.php: Addon::callHooks('post_remote_end', $posted_item); -src/Model/Item.php: Addon::callHooks('tagged', $arr); -src/Model/Item.php: Addon::callHooks('post_local_end', $new_item); + Addon::callHooks('profile_post', $_POST); + Addon::callHooks('profile_edit', $arr); -src/Model/Contact.php: Addon::callHooks('contact_photo_menu', $args); -src/Model/Contact.php: Addon::callHooks('follow', $arr); +### mod/settings.php -src/Model/Profile.php: Addon::callHooks('profile_sidebar_enter', $profile); -src/Model/Profile.php: Addon::callHooks('profile_sidebar', $arr); -src/Model/Profile.php: Addon::callHooks('profile_tabs', $arr); -src/Model/Profile.php: Addon::callHooks('zrl_init', $arr); + Addon::callHooks('addon_settings_post', $_POST); + Addon::callHooks('connector_settings_post', $_POST); + Addon::callHooks('display_settings_post', $_POST); + Addon::callHooks('settings_post', $_POST); + Addon::callHooks('addon_settings', $settings_addons); + Addon::callHooks('connector_settings', $settings_connectors); + Addon::callHooks('display_settings', $o); + Addon::callHooks('settings_form', $o); -src/Model/Event.php: Addon::callHooks('event_updated', $event['id']); -src/Model/Event.php: Addon::callHooks("event_created", $event['id']); +### mod/photos.php -src/Model/User.php: Addon::callHooks('register_account', $uid); -src/Model/User.php: Addon::callHooks('remove_user', $user); + Addon::callHooks('photo_post_init', $_POST); + Addon::callHooks('photo_post_file', $ret); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', $foo); + Addon::callHooks('photo_post_end', intval($item_id)); + Addon::callHooks('photo_upload_form', $ret); -src/Content/Text/BBCode.php: Addon::callHooks('bbcode', $text); -src/Content/Text/BBCode.php: Addon::callHooks('bb2diaspora', $text); +### mod/profile.php -src/Content/Text/HTML.php: Addon::callHooks('html2bbcode', $message); + Addon::callHooks('profile_advanced', $o); -src/Content/Smilies.php: Addon::callHooks('smilie', $params); +### mod/home.php -src/Content/Feature.php: Addon::callHooks('isEnabled', $arr); -src/Content/Feature.php: Addon::callHooks('get', $arr); + Addon::callHooks('home_init', $ret); + Addon::callHooks("home_content", $content); -src/Content/ContactSelector.php: Addon::callHooks('network_to_name', $nets); -src/Content/ContactSelector.php: Addon::callHooks('gender_selector', $select); -src/Content/ContactSelector.php: Addon::callHooks('sexpref_selector', $select); -src/Content/ContactSelector.php: Addon::callHooks('marital_selector', $select); +### mod/poke.php -src/Content/OEmbed.php: Addon::callHooks('oembed_fetch_url', $embedurl, $j); + Addon::callHooks('post_local_end', $arr); -src/Content/Nav.php: Addon::callHooks('page_header', $a->page['nav']); -src/Content/Nav.php: Addon::callHooks('nav_info', $nav); +### mod/contacts.php -src/Worker/Directory.php: Addon::callHooks('globaldir_update', $arr); -src/Worker/Notifier.php: Addon::callHooks('notifier_end', $target_item); -src/Worker/Queue.php: Addon::callHooks('queue_predeliver', $r); -src/Worker/Queue.php: Addon::callHooks('queue_deliver', $params); + Addon::callHooks('contact_edit_post', $_POST); + Addon::callHooks('contact_edit', $arr); -src/Module/Login.php: Addon::callHooks('authenticate', $addon_auth); -src/Module/Login.php: Addon::callHooks('login_hook', $o); -src/Module/Logout.php: Addon::callHooks("logging_out"); +### mod/tagger.php -src/Object/Post.php: Addon::callHooks('render_location', $locate); -src/Object/Post.php: Addon::callHooks('display_item', $arr); + Addon::callHooks('post_local_end', $arr); -src/Core/ACL.php: Addon::callHooks('contact_select_options', $x); -src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr); -src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o); -src/Core/ACL.php: Addon::callHooks($a->module.'_pre_'.$selname, $arr); -src/Core/ACL.php: Addon::callHooks($a->module.'_post_'.$selname, $o); -src/Core/ACL.php: Addon::callHooks('jot_networks', $jotnets); +### mod/lockview.php -src/Core/Worker.php: Addon::callHooks("proc_run", $arr); + Addon::callHooks('lockview_content', $item); -src/Util/Emailer.php: Addon::callHooks('emailer_send_prepare', $params); -src/Util/Emailer.php: Addon::callHooks("emailer_send", $hookdata); +### mod/uexport.php -src/Util/Map.php: Addon::callHooks('generate_map', $arr); -src/Util/Map.php: Addon::callHooks('generate_named_map', $arr); -src/Util/Map.php: Addon::callHooks('Map::getCoordinates', $arr); + Addon::callHooks('uexport_options', $options); -src/Util/Network.php: Addon::callHooks('avatar_lookup', $avatar); +### mod/register.php -src/Util/ParseUrl.php: Addon::callHooks("getsiteinfo", $siteinfo); + Addon::callHooks('register_post', $arr); + Addon::callHooks('register_form', $arr); -src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom); -src/Protocol/DFRN.php: Addon::callHooks('atom_feed_end', $atom); +### mod/item.php + + Addon::callHooks('post_local_start', $_REQUEST); + Addon::callHooks('post_local', $datarray); + Addon::callHooks('post_local_end', $datarray); + +### mod/editpost.php + + Addon::callHooks('jot_tool', $jotplugins); + +### src/Network/FKOAuth1.php + + Addon::callHooks('logged_in', $a->user); + +### src/Render/FriendicaSmartyEngine.php + + Addon::callHooks("template_vars", $arr); + +### src/Model/Item.php + + Addon::callHooks('post_local', $item); + Addon::callHooks('post_remote', $item); + Addon::callHooks('post_local_end', $posted_item); + Addon::callHooks('post_remote_end', $posted_item); + Addon::callHooks('tagged', $arr); + Addon::callHooks('post_local_end', $new_item); + +### src/Model/Contact.php + + Addon::callHooks('contact_photo_menu', $args); + Addon::callHooks('follow', $arr); + +### src/Model/Profile.php + + Addon::callHooks('profile_sidebar_enter', $profile); + Addon::callHooks('profile_sidebar', $arr); + Addon::callHooks('profile_tabs', $arr); + Addon::callHooks('zrl_init', $arr); + +### src/Model/Event.php + + Addon::callHooks('event_updated', $event['id']); + Addon::callHooks("event_created", $event['id']); + +### src/Model/User.php + + Addon::callHooks('register_account', $uid); + Addon::callHooks('remove_user', $user); + +### src/Content/Text/BBCode.php + + Addon::callHooks('bbcode', $text); + Addon::callHooks('bb2diaspora', $text); + +### src/Content/Text/HTML.php + + Addon::callHooks('html2bbcode', $message); + +### src/Content/Smilies.php + + Addon::callHooks('smilie', $params); + +### src/Content/Feature.php + + Addon::callHooks('isEnabled', $arr); + Addon::callHooks('get', $arr); + +### src/Content/ContactSelector.php + + Addon::callHooks('network_to_name', $nets); + Addon::callHooks('gender_selector', $select); + Addon::callHooks('sexpref_selector', $select); + Addon::callHooks('marital_selector', $select); + +### src/Content/OEmbed.php + + Addon::callHooks('oembed_fetch_url', $embedurl, $j); + +### src/Content/Nav.php + + Addon::callHooks('page_header', $a->page['nav']); + Addon::callHooks('nav_info', $nav); + +### src/Worker/Directory.php + + Addon::callHooks('globaldir_update', $arr); + +### src/Worker/Notifier.php + + Addon::callHooks('notifier_end', $target_item); + +### src/Worker/Queue.php + + Addon::callHooks('queue_predeliver', $r); + Addon::callHooks('queue_deliver', $params); + +### src/Module/Login.php + + Addon::callHooks('authenticate', $addon_auth); + Addon::callHooks('login_hook', $o); + +### src/Module/Logout.php + + Addon::callHooks("logging_out"); + +### src/Object/Post.php + + Addon::callHooks('render_location', $locate); + Addon::callHooks('display_item', $arr); + +### src/Core/ACL.php + + Addon::callHooks('contact_select_options', $x); + Addon::callHooks($a->module.'_pre_'.$selname, $arr); + Addon::callHooks($a->module.'_post_'.$selname, $o); + Addon::callHooks($a->module.'_pre_'.$selname, $arr); + Addon::callHooks($a->module.'_post_'.$selname, $o); + Addon::callHooks('jot_networks', $jotnets); + +### src/Core/Worker.php + + Addon::callHooks("proc_run", $arr); + +### src/Util/Emailer.php + + Addon::callHooks('emailer_send_prepare', $params); + Addon::callHooks("emailer_send", $hookdata); + +### src/Util/Map.php + + Addon::callHooks('generate_map', $arr); + Addon::callHooks('generate_named_map', $arr); + Addon::callHooks('Map::getCoordinates', $arr); + +### src/Util/Network.php + + Addon::callHooks('avatar_lookup', $avatar); + +### src/Util/ParseUrl.php + + Addon::callHooks("getsiteinfo", $siteinfo); + +### src/Protocol/DFRN.php + + Addon::callHooks('atom_feed_end', $atom); + Addon::callHooks('atom_feed_end', $atom); diff --git a/doc/de/Chats.md b/doc/de/Chats.md index fc46af650e..77dfdeb440 100644 --- a/doc/de/Chats.md +++ b/doc/de/Chats.md @@ -8,7 +8,7 @@ Du hast derzeit zwei Möglichkeiten, einen Chat auf Deiner Friendica-Seite zu be * IRC - Internet Relay Chat * Jappix -##IRC Addon +## IRC Addon Sobald das Addon aktiviert ist, kannst Du den Chat unter [deineSeite.de/irc](../irc) finden. Beachte aber, dass dieser Chat auch ohne Anmeldung auf Deiner Seite zugänglich ist und somit auch Fremde diesen Chat mitnutzen können. @@ -27,7 +27,7 @@ Unten hast Du ein Eingabefeld, um Beiträge zu schreiben. Weiter Informationen zu IRC findest Du zum Beispiel auf ubuntuusers.de, in Wikipedia oder bei icrhelp.org (in Englisch). -##Jappix Mini +## Jappix Mini Das Jappix Mini Addon erlaubt das Erstellen einer Chatbox für Jabber/XMPP-Kontakte. Ein Jabber/XMPP Account sollte vor der Installation bereits vorhanden sein. diff --git a/doc/de/Improve-Performance.md b/doc/de/Improve-Performance.md index c1f0a54fa0..d9be4fca6e 100644 --- a/doc/de/Improve-Performance.md +++ b/doc/de/Improve-Performance.md @@ -35,7 +35,7 @@ Aktiviere die folgenden Addons: rendertime -###rendertime +### rendertime **Beschreibung** @@ -60,7 +60,7 @@ Webserver Wenn du einen Apache-Webserver nutzt, aktiviere bitte die folgenden Module: -###Cache-Control +### Cache-Control **Beschreibung** @@ -74,7 +74,7 @@ ExpiresActive on ExpiresDefault "access plus 1 week" Weitere Informationen findest du hier: http://httpd.apache.org/docs/2.2/mod/mod_expires.html. -###Compress content +### Compress content **Beschreibung** @@ -85,7 +85,7 @@ Aktiviere das Modul "mod_deflate" durch die Eingabe "a2enmod deflate" als root. Weitere Informationen findest du hier: http://httpd.apache.org/docs/2.2/mod/mod_deflate.html -###PHP +### PHP **FCGI** @@ -93,7 +93,7 @@ Wenn du Apache nutzt, dann denk darüber nach, FCGI zu nutzen. Wenn du eine Debian-basierte Distribution nutzt, dann wirst du die Pakete "php5-cgi" und "libapache2-mod-fcgid" benötigen. Nutze externe Dokumente, um eine detailiertere Erklärung für die Einrichtung eines Systems auf FCGI-Basis zu erhalten. -###Database +### 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. diff --git a/doc/de/Install.md b/doc/de/Install.md index 1842306c58..ff077351b7 100644 --- a/doc/de/Install.md +++ b/doc/de/Install.md @@ -4,6 +4,7 @@ Friendica Installation * [Zur Startseite der Hilfe](help) Wir haben hart daran gearbeitet, um Friendica auf vorgefertigten Hosting-Plattformen zum Laufen zu bringen - solche, auf denen auch Wordpress Blogs und Drupal-Installationen laufen. +Wir bieten eine manuelle und eine automatische Installation an. Aber bedenke, dass Friendica mehr als eine einfache Webanwendung ist. Es handelt sich um ein komplexes Kommunikationssystem, das eher an einen Email-Server erinnert als an einen Webserver. Um die Verfügbarkeit und Performance zu gewährleisten, werden Nachrichten im Hintergrund verschickt und gespeichert, um sie später zu verschicken, wenn eine Webseite gerade nicht erreichbar ist. @@ -11,83 +12,124 @@ Diese Funktionalität benötigt ein wenig mehr als die normalen Blogs. Nicht jeder PHP/MySQL-Hosting-Anbieter kann Friendica unterstützen. Viele hingegen können es. Aber **bitte** prüfe die Voraussetzungen deines Servers vor der Installation. -Wenn dir Fehler während der Installation auffallen, sag uns bitte über [github](https://github.com/friendica/issues) Bescheid. +Wenn dir Fehler während der Installation auffallen, sag uns bitte über [Helper](http://forum.friendi.ca/profile/helpers) oder das [Entwickler Forum](https://forum.friendi.ca/profile/developers) Bescheid oder [erstelle ein Issue](https://github.com/friendica/friendica/issues). Gib uns bitte so viele Infos zu deinem System, wie du kannst, und beschreibe den Fehler mit allen Details und Fehlermeldungen, so dass wir den Fehler zukünftig verhindern können. Aufgrund der großen Anzahl an verschiedenen Betriebssystemen und PHP-Plattformen haben wir nur geringe Kapazitäten, um deine PHP-Installation zu debuggen oder fehlende Module zu ersetzen, aber wir tun unser Bestes, um allgemeine Code-Fehler zu beheben. +Falls du noch keinen Friendica-Account hast, kannst du dir einen temporären Account hier erstellen: [tryfriendica.de](https://tryfriendica.de). +Darüber kannst du den genannten Forum beitreten. +Der Account wird nach 7 Tagen ablaufen, aber du kannst einen Server-Admin fragen, diesen Account länger zu erhalten, sollte das Problem nicht innerhalb dieser Zeit gelöst sein. Bevor du anfängst: suche dir einen Domain- oder Subdomainnamen für deinen Server. Dinge verändern sich und einige deiner Freunde haben möglicherweise Probleme, mit dir zu kommunizieren. Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben. -1. Voraussetzungen - - Apache mit einer aktiverten mod-rewrite-Funktion und dem Eintrag "Options All", so dass du die lokale .htaccess-Datei nutzen kannst - - PHP 5.6+. Je neuer, desto besser. - - PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei - - Curl, GD, PDO, MySQLi, xml, zip und OpenSSL-Erweiterung - - etwas in der Art eines Email-Servers oder eines Gateways wie PHP mail() - - Das POSIX Modul muss aktiviert sein ([CentOS, RHEL](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) haben dies z.B. deaktiviert) - - Mysql 5.5.3+ - - die Möglichkeit, wiederkehrende Aufgaben mit cron (Linux/Mac) oder "Scheduled Tasks" einzustellen (Windows) [Beachte: andere Optionen sind in Abschnitt 7 dieser Dokumentation zu finden] - - Installation in einer Top-Level-Domain oder Subdomain (ohne eine Verzeichnis/Pfad-Komponente in der URL) wird bevorzugt. Verzeichnispfade sind für diesen Zweck nicht so günstig und wurden auch nicht ausführlich getestet. +Requirements +--- +* Apache mit einer aktiverten mod-rewrite-Funktion und dem Eintrag "Options All", so dass du die lokale .htaccess-Datei nutzen kannst +* PHP 5.6+ (PHP 7 ist aufgrund der Performance empfohlen) + * PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei + * Curl, GD, PDO, MySQLi, xml, zip und OpenSSL-Erweiterung + * Das POSIX Modul muss aktiviert sein ([CentOS, RHEL](http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7http://www.bigsoft.co.uk/blog/index.php/2014/12/08/posix-php-commands-not-working-under-centos-7) haben dies z.B. deaktiviert) + * etwas in der Art eines Email-Servers oder eines Gateways wie PHP mail() +* Mysql 5.5.3+ (oder eine äquivalente Alternative: MariaDB, Percona Server etc.) +* die Möglichkeit, wiederkehrende Aufgaben mit cron (Linux/Mac) oder "Scheduled Tasks" einzustellen (Windows) [Beachte: andere Optionen sind in Abschnitt 7 dieser Dokumentation zu finden] +* Installation in einer Top-Level-Domain oder Subdomain (ohne eine Verzeichnis/Pfad-Komponente in der URL) wird bevorzugt. Verzeichnispfade sind für diesen Zweck nicht so günstig und wurden auch nicht ausführlich getestet. - [Dreamhost.com bietet ein ausreichendes Hosting-Paket mit den nötigen Features zu einem annehmbaren Preis. Wenn dein Hosting-Anbieter keinen Unix-Zugriff erlaubt, kannst du Schwierigkeiten mit der Einrichtung der Webseite haben. +Installation +--- - 1.1. APT-Pakete - - Apache: sudo apt-get install apache2 - - PHP5: sudo apt-get install php5 - - PHP5-Zusätzliche Pakete: sudo apt-get install php5-curl php5-gd php5-mysql - - MySQL: sudo apt-get install mysql-server +### Friendica -2. Entpacke die Friendica-Daten in das Quellverzeichnis (root) des Dokumentenbereichs deines Webservers. +Entpacke die Friendica-Daten in das Quellverzeichnis (root) des Dokumentenbereichs deines Webservers. +Wenn du die Möglichkeit hierzu hast, empfehlen wir dir "git" zu nutzen, um die Daten direkt von der Quelle zu klonen, statt die gepackte .tar- oder .zip-Datei zu nutzen. +Das macht die Aktualisierung wesentlich einfacher. +Der Linux-Code, mit dem man die Dateien direkt in ein Verzeichnis wie "meinewebseite" kopiert, ist - - Wenn du die Möglichkeit hierzu hast, empfehlen wir dir "git" zu nutzen, um die Daten direkt von der Quelle zu klonen, statt die gepackte .tar- oder .zip-Datei zu nutzen. Das macht die Aktualisierung wesentlich einfacher. Der Linux-Code, mit dem man die Dateien direkt in ein Verzeichnis wie "meinewebseite" kopiert, ist + git clone https://github.com/friendica/friendica.git mywebsite + cd mywebsite + bin/composer.phar install - `git clone https://github.com/friendica/friendica.git meinewebseite` +Stelle sicher, dass der Ordner *view/smarty3* existiert and von dem Webserver-Benutzer beschreibbar ist - - und dann kannst du die letzten Änderungen immer mit dem folgenden Code holen + mkdir view/smarty3 + chmod 777 view/smarty3 - `cd meinewebseite` - `git pull` - `bin/composer.phar install` +Falls Addons installiert werden sollen: Gehe in den Friendica-Ordner - - Addons installieren - - zunächst solltest du **in** deinem Webseitenordner sein + cd mywebsite - `cd meinewebseite` +Und die Addon Repository klonst: - - dann kannst du das Addon-Verzeichnis seperat kopieren + git clone https://github.com/friendica/friendica-addons.git addon - `git clone https://github.com/friendica/friendica-addons.git addon` +Um das Addon-Verzeichnis aktuell zu halten, solltest du in diesem Pfad ein "git pull"-Befehl eintragen - - Um das Addon-Verzeichnis aktuell zu halten, solltest du in diesem Pfad ein "git pull"-Befehl eintragen + cd meinewebseite/addon + git pull - `cd meinewebseite/addon` +Wenn du den Verzeichnispfad auf deinen Webserver kopierst, dann stelle sicher, dass du auch die .htaccess kopierst, da "Punkt"-Dateien oft versteckt sind und normalerweise nicht direkt kopiert werden. - `git pull` +### Erselle eine Datenbank - - Wenn du den Verzeichnispfad auf deinen Webserver kopierst, dann stelle sicher, dass du auch die .htaccess kopierst, da "Punkt"-Dateien oft versteckt sind und normalerweise nicht direkt kopiert werden. - - -3. Erstelle eine leere Datenbank und notiere alle Zugangsdaten (Adresse der Datenbank, Nutzername, Passwort, Datenbankname). +Erstelle eine leere Datenbank und notiere alle Zugangsdaten (Adresse der Datenbank, Nutzername, Passwort, Datenbankname). Friendica benötigt die Berechtigungen um neue Felder in dieser Datenbank zu ertellen (create) und zu löschen (delete). -4. Besuche deine Webseite mit deinem Browser und befolge die Anleitung. Bitte beachte jeden Fehler und korrigiere diese, bevor du fortfährst. +Mit neueren Versionen von MySQL (5.7.17+) musst du den `sql_mode` zu `''` (blank) setzen. +Benutze diese Einstellung, wenn der Installer nicht in der Lage ist, die Tabellen aufgrund eines Timestamp-Format Problems zu erstellen. +Falls dem so ist, finde den `[mysqld]` Bereich in deiner `my.conf` Datei und füge diese Zeile hinzu: -5. *Wenn* die automatisierte Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende: + sql_mode = '' - - ".htconfig.php" existiert ... wenn nicht, bearbeite die „htconfig.php“ und ändere die Systemeinstellungen. Benenne sie um in „.htconfig.php" -“ - - die Datenbank beinhaltet Daten. ... wenn nicht, importiere den Inhalt der Datei "database.sql" mit phpmyadmin oder per mysql-Kommandozeile. +Starte MySQL dann neu und es sollte klappen. -6. Besuche deine Seite an diesem Punkt wieder und registriere deinen persönlichen Account. Alle Registrierungsprobleme sollten automatisch behebbar sein. -Wenn du irgendwelche **kritischen** Fehler zu diesen Zeitpunkt erhalten solltest, deutet das darauf hin, dass die Datenbank nicht korrekt installiert wurde. Du kannst bei Bedarf die Datei .htconfig.php verschieben/umbenennen und die Datenbank leeren (als „Dropping“ bezeichnet), so dass du mit einem sauberen System neu starten kannst. +### Option A: Der manuelle Installer -7. Erstelle einen Cron job oder einen regelmäßigen Task, um den Poller alle 5-10 Minuten im Hintergrund ablaufen zu lassen. Beispiel: +Besuche deine Webseite mit deinem Browser und befolge die Anleitung. +Bitte beachte jeden Fehler und korrigiere diese, bevor du fortfährst. - `cd /base/directory; /path/to/php bin/worker.php` +Falls du einen Port für die Datenbankverbindung angeben musst, kannst du diesen in der Host-Eingabe Zeile angeben. + +*Wenn* die manuelle Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende: +* ".htconfig.php" existiert ... wenn nicht, bearbeite die „htconfig.php“ und ändere die Systemeinstellungen. Benenne sie um in „.htconfig.php". +* die Datenbank beinhaltet Daten. ... wenn nicht, importiere den Inhalt der Datei "database.sql" mit phpmyadmin oder per mysql-Kommandozeile. + +Besuche deine Seite an diesem Punkt wieder und registriere deinen persönlichen Account. +Alle Registrierungsprobleme sollten automatisch behebbar sein. +Wenn du irgendwelche **kritischen** Fehler zu diesen Zeitpunkt erhalten solltest, deutet das darauf hin, dass die Datenbank nicht korrekt installiert wurde. +Du kannst bei Bedarf die Datei .htconfig.php verschieben/umbenennen und die Datenbank leeren (als „Dropping“ bezeichnet), so dass du mit einem sauberen System neu starten kannst. + +### Option B: Starte das manuelle Installationsscript + +Öffne die Datei htconfig.php im Friendica-Hauptordner mit einem Text-Editor. +Entferne die `die('...');` Zeile und bearbeite die Einstellungen so, das sie zu deinem System passen (MySQL, Sprache, Theme etc.). +Dann speichere die Datei (jedoch nicht umbenennen). + +Gehe in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus: + + bin/console autoinstall + +Oder falls du alle optionalen Checks ausfürehn lassen möchtest, benutze diese Option: + + bin/console autoinstall -a + +*Wenn* die automatisierte Installation aus irgendeinem Grund fehlschlägt, dann prüfe das Folgende: +* Existiert die `.htconfig.php`? Falls ja, wird die automatisierte Installation nicht gestartet. +* Sind Einstellungen in der `.htconfig.php` korrekt? Falls nicht, bitte bearbeite diese Datei erneut. +* Ist die leere MySQL-Datenbank erstellt? Falls nicht, erstelle diese. + +Für mehr Informationen kannst du diese Option verwenden: + + bin/console autoinstall -v + +### Einen Worker einrichten + +Erstelle einen Cron job oder einen regelmäßigen Task, um den Poller alle 5-10 Minuten im Hintergrund ablaufen zu lassen. +Beispiel: + + cd /base/directory; /path/to/php bin/worker.php Ändere "/base/directory" und "/path/to/php" auf deine Systemvorgaben. @@ -101,10 +143,11 @@ Friendica wird nicht korrekt laufen, wenn dieser Schritt nicht erfolgreich abges Falls das Einrichten des cron nicht möglich ist, kannst Du alternativ den "frontend worker" vom Administrationsinterface aus aktivieren. -###Erstelle einen Backup Plan +### Erstelle einen Backup Plan + Es werden schlimme Dinge geschehen. -Sei es nun ein Hardwareversage oder eine korrumpierte Datenbank. -Deshalb solltest du dir nachdem die Installation deines Friendica Knotens abgeschlossen ist einen Backup Plan erstellen. +Sei es nun ein Hardwareversagen oder eine kaputte Datenbank. +Deshalb solltest du dir, nachdem die Installation deines Friendica Knotens abgeschlossen ist, einen Backup Plan erstellen. Die wichtigste Datei ist die `.htconfig.php` im Stammverzeichnis deiner Friendica Installation. Und da alle Daten in der Datenbank gespeichert werden, solltest du einen nicht all zu alten Dump der Friendica Datenbank zur Hand haben, solltest du deinen Knoten wieder herstellen müssen. diff --git a/include/dba.php b/include/dba.php index 6446bb444b..1d3b432141 100644 --- a/include/dba.php +++ b/include/dba.php @@ -860,12 +860,15 @@ class dba { * * @param string $table Table name * @param array $conditions Field condition(s) + * @param array $options + * - cascade: If true we delete records in other tables that depend on the one we're deleting through + * relations (default: true) * @param boolean $in_process Internal use: Only do a commit after the last delete * @param array $callstack Internal use: prevent endless loops * * @return boolean|array was the delete successful? When $in_process is set: deletion data */ - public static function delete($table, array $conditions, $in_process = false, array &$callstack = []) + public static function delete($table, array $conditions, array $options = [], $in_process = false, array &$callstack = []) { if (empty($table) || empty($conditions)) { logger('Table and conditions have to be set'); @@ -888,13 +891,15 @@ class dba { $commands[$key] = ['table' => $table, 'conditions' => $conditions]; + $cascade = defaults($options, 'cascade', true); + // To speed up the whole process we cache the table relations - if (count(self::$relation) == 0) { + if ($cascade && count(self::$relation) == 0) { self::buildRelationData(); } // Is there a relation entry for the table? - if (isset(self::$relation[$table])) { + if ($cascade && isset(self::$relation[$table])) { // We only allow a simple "one field" relation. $field = array_keys(self::$relation[$table])[0]; $rel_def = array_values(self::$relation[$table])[0]; @@ -907,7 +912,7 @@ class dba { if ((count($conditions) == 1) && ($field == array_keys($conditions)[0])) { foreach ($rel_def AS $rel_table => $rel_fields) { foreach ($rel_fields AS $rel_field) { - $retval = self::delete($rel_table, [$rel_field => array_values($conditions)[0]], true, $callstack); + $retval = self::delete($rel_table, [$rel_field => array_values($conditions)[0]], $options, true, $callstack); $commands = array_merge($commands, $retval); } } @@ -921,7 +926,7 @@ class dba { while ($row = self::fetch($data)) { // Now we accumulate the delete commands - $retval = self::delete($table, [$field => $row[$field]], true, $callstack); + $retval = self::delete($table, [$field => $row[$field]], $options, true, $callstack); $commands = array_merge($commands, $retval); } @@ -968,7 +973,7 @@ class dba { // Split the SQL queries in chunks of 100 values // We do the $i stuff here to make the code better readable $i = $counter[$key_table][$key_condition]; - if (count($compacted[$key_table][$key_condition][$i]) > 100) { + if (isset($compacted[$key_table][$key_condition][$i]) && count($compacted[$key_table][$key_condition][$i]) > 100) { ++$i; } diff --git a/include/text.php b/include/text.php index a37d5815d5..040ac4ce0d 100644 --- a/include/text.php +++ b/include/text.php @@ -1411,18 +1411,13 @@ function prepare_body(array &$item, $attach = false, $is_preview = false) function apply_content_filter($html, array $reasons) { if (count($reasons)) { - $rnd = random_string(8); - $content_filter_html = ' -

' . - L10n::t('Click to open/close') . - '

- '; + $tpl = get_markup_template('wall/content_filter.tpl'); + $html = replace_macros($tpl, [ + '$reasons' => $reasons, + '$rnd' => random_string(8), + '$openclose' => L10n::t('Click to open/close'), + '$html' => $html + ]); } return $html; diff --git a/mod/admin.php b/mod/admin.php index 3debb57bed..3090376bea 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -1120,6 +1120,7 @@ function admin_page_site_post(App $a) } Config::set('system', 'language', $language); Config::set('system', 'theme', $theme); + Theme::install($theme); if ($theme_mobile == '---') { Config::delete('system', 'mobile-theme'); @@ -1262,6 +1263,7 @@ function admin_page_site(App $a) /* Community page style */ $community_page_style_choices = [ + CP_NO_INTERNAL_COMMUNITY => L10n::t("No community page for local users"), CP_NO_COMMUNITY_PAGE => L10n::t("No community page"), CP_USERS_ON_SERVER => L10n::t("Public postings from users of this site"), CP_GLOBAL_COMMUNITY => L10n::t("Public postings from the federated network"), diff --git a/mod/babel.php b/mod/babel.php index cafd06556b..3352366bd5 100644 --- a/mod/babel.php +++ b/mod/babel.php @@ -23,6 +23,12 @@ function babel_content() 'content' => visible_lf($bbcode) ]; + $plain = Text\BBCode::toPlaintext($bbcode, false); + $results[] = [ + 'title' => L10n::t('BBCode::toPlaintext'), + 'content' => visible_lf($plain) + ]; + $html = Text\BBCode::convert($bbcode); $results[] = [ 'title' => L10n::t("BBCode::convert \x28raw HTML\x29"), diff --git a/mod/community.php b/mod/community.php index 40ebdbb6e0..876339dea1 100644 --- a/mod/community.php +++ b/mod/community.php @@ -30,6 +30,11 @@ function community_content(App $a, $update = 0) $page_style = Config::get('system', 'community_page_style'); + if ($page_style == CP_NO_INTERNAL_COMMUNITY) { + notice(L10n::t('Access denied.') . EOL); + return; + } + if ($a->argc > 1) { $content = $a->argv[1]; } else { diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 7eddd4f3d5..e2f0336db6 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -25,42 +25,13 @@ function dfrn_notify_post(App $a) { $data = json_decode($postdata); if (is_object($data)) { $nick = defaults($a->argv, 1, ''); + $user = dba::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]); if (!DBM::is_result($user)) { System::httpExit(500); } - $msg = Diaspora::decodeRaw($user, $postdata); - - // Check if the user has got this contact - $cid = Contact::getIdForURL($msg['author'], $user['uid']); - if (!$cid) { - // Otherwise there should be a public contact - $cid = Contact::getIdForURL($msg['author']); - if (!$cid) { - logger('Contact not found for address ' . $msg['author']); - System::xmlExit(3, 'Contact not found'); - } - } - - // We now have some contact, so we fetch it - $importer = dba::fetch_first("SELECT *, `name` as `senderName` - FROM `contact` - WHERE NOT `blocked` AND `id` = ? LIMIT 1", - $cid); - - // This should never fail - if (!DBM::is_result($importer)) { - logger('Contact not found for address ' . $msg['author']); - System::xmlExit(3, 'Contact not found'); - } - - // Set the user id. This is important if this is a public contact - $importer['importer_uid'] = $user['uid']; - - // Now we should be able to import it - $ret = DFRN::import($msg['message'], $importer); - System::xmlExit($ret, 'Done'); - } else { + dfrn_dispatch_private($user, $postdata); + } elseif (!dfrn_dispatch_public($postdata)) { require_once 'mod/salmon.php'; salmon_post($a, $postdata); } @@ -91,19 +62,12 @@ function dfrn_notify_post(App $a) { $dfrn_id = substr($dfrn_id, 2); } - $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", - dbesc($dfrn_id), - dbesc($challenge) - ); - if (! DBM::is_result($r)) { - logger('dfrn_notify: could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge); + if (!dba::exists('challenge', ['dfrn-id' => $dfrn_id, 'challenge' => $challenge])) { + logger('could not match challenge to dfrn_id ' . $dfrn_id . ' challenge=' . $challenge); System::xmlExit(3, 'Could not match challenge'); } - $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s'", - dbesc($dfrn_id), - dbesc($challenge) - ); + dba::delete('challenge', ['dfrn-id' => $dfrn_id, 'challenge' => $challenge]); // find the local user who owns this relationship. @@ -143,8 +107,8 @@ function dfrn_notify_post(App $a) { dbesc($a->argv[1]) ); - if (! DBM::is_result($r)) { - logger('dfrn_notify: contact not found for dfrn_id ' . $dfrn_id); + if (!DBM::is_result($r)) { + logger('contact not found for dfrn_id ' . $dfrn_id); System::xmlExit(3, 'Contact not found'); //NOTREACHED } @@ -153,15 +117,11 @@ function dfrn_notify_post(App $a) { $importer = $r[0]; - logger("Remote rino version: ".$rino_remote." for ".$importer["url"], LOGGER_DEBUG); - if ((($writable != (-1)) && ($writable != $importer['writable'])) || ($importer['forum'] != $forum) || ($importer['prv'] != $prv)) { - q("UPDATE `contact` SET `writable` = %d, forum = %d, prv = %d WHERE `id` = %d", - intval(($writable == (-1)) ? $importer['writable'] : $writable), - intval($forum), - intval($prv), - intval($importer['id']) - ); + $fields = ['writable' => ($writable == (-1)) ? $importer['writable'] : $writable, + 'forum' => $forum, 'prv' => $prv]; + dba::update('contact', $fields, ['id' => $importer['id']]); + if ($writable != (-1)) { $importer['writable'] = $writable; } @@ -173,8 +133,7 @@ function dfrn_notify_post(App $a) { $importer = Contact::updateSslPolicy($importer, $ssl_policy); - logger('dfrn_notify: received notify from ' . $importer['name'] . ' for ' . $importer['username']); - logger('dfrn_notify: data: ' . $data, LOGGER_DATA); + logger('data: ' . $data, LOGGER_DATA); if ($dissolve == 1) { // Relationship is dissolved permanently @@ -186,8 +145,6 @@ function dfrn_notify_post(App $a) { $rino = Config::get('system', 'rino_encrypt'); $rino = intval($rino); - logger("Local rino version: " . $rino, LOGGER_DEBUG); - if (strlen($key)) { // if local rino is lower than remote rino, abort: should not happen! @@ -198,24 +155,25 @@ function dfrn_notify_post(App $a) { } $rawkey = hex2bin(trim($key)); - logger('rino: md5 raw key: ' . md5($rawkey)); + logger('rino: md5 raw key: ' . md5($rawkey), LOGGER_DATA); + $final_key = ''; if ($dfrn_version >= 2.1) { - if ((($importer['duplex']) && strlen($importer['cprvkey'])) || (! strlen($importer['cpubkey']))) { + if (($importer['duplex'] && strlen($importer['cprvkey'])) || !strlen($importer['cpubkey'])) { openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']); } else { openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']); } } else { - if ((($importer['duplex']) && strlen($importer['cpubkey'])) || (! strlen($importer['cprvkey']))) { + if (($importer['duplex'] && strlen($importer['cpubkey'])) || !strlen($importer['cprvkey'])) { openssl_public_decrypt($rawkey, $final_key, $importer['cpubkey']); } else { openssl_private_decrypt($rawkey, $final_key, $importer['cprvkey']); } } - switch($rino_remote) { + switch ($rino_remote) { case 0: case 1: // we got a key. old code send only the key, without RINO version. @@ -230,16 +188,93 @@ function dfrn_notify_post(App $a) { logger('rino: decrypted data: ' . $data, LOGGER_DATA); } + logger('Importing post from ' . $importer['addr'] . ' to ' . $importer['nickname'] . ' with the RINO ' . $rino_remote . ' encryption.', LOGGER_DEBUG); + $ret = DFRN::import($data, $importer); System::xmlExit($ret, 'Processed'); // NOTREACHED } +function dfrn_dispatch_public($postdata) +{ + $msg = Diaspora::decodeRaw([], $postdata); + if (!$msg) { + // We have to fail silently to be able to hand it over to the salmon parser + return false; + } + + // Fetch the corresponding public contact + $contact = Contact::getDetailsByAddr($msg['author'], 0); + if (!$contact) { + logger('Contact not found for address ' . $msg['author']); + System::xmlExit(3, 'Contact not found'); + } + + // We now have some contact, so we fetch it + $importer = dba::fetch_first("SELECT *, `name` as `senderName` + FROM `contact` + WHERE NOT `blocked` AND `id` = ? LIMIT 1", + $contact['id']); + + $importer['importer_uid'] = 0; + + // This should never fail + if (!DBM::is_result($importer)) { + logger('Contact not found for address ' . $msg['author']); + System::xmlExit(3, 'Contact not found'); + } + + logger('Importing post from ' . $msg['author'] . ' with the public envelope.', LOGGER_DEBUG); + + // Now we should be able to import it + $ret = DFRN::import($msg['message'], $importer); + System::xmlExit($ret, 'Done'); +} + +function dfrn_dispatch_private($user, $postdata) +{ + $msg = Diaspora::decodeRaw($user, $postdata); + if (!$msg) { + System::xmlExit(4, 'Unable to parse message'); + } + + // Check if the user has got this contact + $cid = Contact::getIdForURL($msg['author'], $user['uid']); + if (!$cid) { + // Otherwise there should be a public contact + $cid = Contact::getIdForURL($msg['author']); + if (!$cid) { + logger('Contact not found for address ' . $msg['author']); + System::xmlExit(3, 'Contact not found'); + } + } + + // We now have some contact, so we fetch it + $importer = dba::fetch_first("SELECT *, `name` as `senderName` + FROM `contact` + WHERE NOT `blocked` AND `id` = ? LIMIT 1", + $cid); + + // This should never fail + if (!DBM::is_result($importer)) { + logger('Contact not found for address ' . $msg['author']); + System::xmlExit(3, 'Contact not found'); + } + + // Set the user id. This is important if this is a public contact + $importer['importer_uid'] = $user['uid']; + + logger('Importing post from ' . $msg['author'] . ' to ' . $user['nickname'] . ' with the private envelope.', LOGGER_DEBUG); + + // Now we should be able to import it + $ret = DFRN::import($msg['message'], $importer); + System::xmlExit($ret, 'Done'); +} function dfrn_notify_content(App $a) { - if(x($_GET,'dfrn_id')) { + if (x($_GET,'dfrn_id')) { /* * initial communication from external contact, $direction is their direction. @@ -252,10 +287,10 @@ function dfrn_notify_content(App $a) { $type = ""; $last_update = ""; - logger('dfrn_notify: new notification dfrn_id=' . $dfrn_id); + logger('new notification dfrn_id=' . $dfrn_id); $direction = (-1); - if(strpos($dfrn_id,':') == 1) { + if (strpos($dfrn_id,':') == 1) { $direction = intval(substr($dfrn_id,0,1)); $dfrn_id = substr($dfrn_id,2); } @@ -264,23 +299,18 @@ function dfrn_notify_content(App $a) { $status = 0; - $r = q("DELETE FROM `challenge` WHERE `expire` < " . intval(time())); + dba::delete('challenge', ["`expire` < ?", time()]); - $r = q("INSERT INTO `challenge` ( `challenge`, `dfrn-id`, `expire` , `type`, `last_update` ) - VALUES( '%s', '%s', %d, '%s', '%s' ) ", - dbesc($hash), - dbesc($dfrn_id), - intval(time() + 90 ), - dbesc($type), - dbesc($last_update) - ); + $fields = ['challenge' => $hash, 'dfrn-id' => $dfrn_id, 'expire' => time() + 90, + 'type' => $type, 'last_update' => $last_update]; + dba::insert('challenge', $fields); - logger('dfrn_notify: challenge=' . $hash, LOGGER_DEBUG); + logger('challenge=' . $hash, LOGGER_DATA); $sql_extra = ''; switch($direction) { case (-1): - $sql_extra = sprintf(" AND ( `issued-id` = '%s' OR `dfrn-id` = '%s' ) ", dbesc($dfrn_id), dbesc($dfrn_id)); + $sql_extra = sprintf(" AND (`issued-id` = '%s' OR `dfrn-id` = '%s') ", dbesc($dfrn_id), dbesc($dfrn_id)); $my_id = $dfrn_id; break; case 0: @@ -302,11 +332,11 @@ function dfrn_notify_content(App $a) { dbesc($a->argv[1]) ); - if (! DBM::is_result($r)) { + if (!DBM::is_result($r)) { $status = 1; } - logger("Remote rino version: ".$rino_remote." for ".$r[0]["url"], LOGGER_DEBUG); + logger("Remote rino version: ".$rino_remote." for ".$r[0]["url"], LOGGER_DATA); $challenge = ''; $encrypted_id = ''; @@ -316,7 +346,7 @@ function dfrn_notify_content(App $a) { $pub_key = trim($r[0]['pubkey']); $dplx = intval($r[0]['duplex']); - if ((($dplx) && (strlen($prv_key))) || ((strlen($prv_key)) && (!(strlen($pub_key))))) { + if (($dplx && strlen($prv_key)) || (strlen($prv_key) && !strlen($pub_key))) { openssl_private_encrypt($hash, $challenge, $prv_key); openssl_private_encrypt($id_str, $encrypted_id, $prv_key); } elseif (strlen($pub_key)) { @@ -334,7 +364,7 @@ function dfrn_notify_content(App $a) { $rino = Config::get('system', 'rino_encrypt'); $rino = intval($rino); - logger("Local rino version: ". $rino, LOGGER_DEBUG); + logger("Local rino version: ". $rino, LOGGER_DATA); // if requested rino is lower than enabled local rino, lower local rino version // if requested rino is higher than enabled local rino, reply with local rino @@ -342,7 +372,7 @@ function dfrn_notify_content(App $a) { $rino = $rino_remote; } - if((($r[0]['rel']) && ($r[0]['rel'] != CONTACT_IS_SHARING)) || ($r[0]['page-flags'] == PAGE_COMMUNITY)) { + if (($r[0]['rel'] && ($r[0]['rel'] != CONTACT_IS_SHARING)) || ($r[0]['page-flags'] == PAGE_COMMUNITY)) { $perm = 'rw'; } else { $perm = 'r'; @@ -362,5 +392,4 @@ function dfrn_notify_content(App $a) { killme(); } - } diff --git a/mod/friendica.php b/mod/friendica.php index 6c143634ca..1929150f27 100644 --- a/mod/friendica.php +++ b/mod/friendica.php @@ -116,14 +116,14 @@ function friendica_content(App $a) } else { $o .= '

' . L10n::t('No installed addons/apps') . '

' . PHP_EOL; } - + if (Config::get('system', 'tosdisplay')) { $o .= '

'.L10n::t('Read about the Terms of Service of this node.', System::baseurl()).'

'; } - $blocklist = Config::get('system', 'blocklist'); - if (count($blocklist)) { + $blocklist = Config::get('system', 'blocklist', []); + if (!empty($blocklist)) { $o .= '

' . L10n::t('On this server the following remote servers are blocked.') . '

' . PHP_EOL; $o .= '' . PHP_EOL; foreach ($blocklist as $b) { diff --git a/mod/install.php b/mod/install.php index 4596f9a251..323cb31fdd 100644 --- a/mod/install.php +++ b/mod/install.php @@ -51,7 +51,7 @@ function install_post(App $a) { $phpath = notags(trim($_POST['phpath'])); require_once("include/dba.php"); - if (!dba::connect($dbhost, $dbuser, $dbpass, $dbdata)) { + if (!dba::connect($dbhost, $dbuser, $dbpass, $dbdata, true)) { $a->data['db_conn_failed'] = true; } @@ -140,11 +140,37 @@ function install_content(App $a) { switch ($install_wizard_pass) { case 1: { // System check + + $checks = []; + + check_funcs($checks); + + check_imagik($checks); + + check_htconfig($checks); + + check_smarty3($checks); + + check_keys($checks); + if (x($_POST, 'phpath')) { $phpath = notags(trim($_POST['phpath'])); } - list($checks, $checkspassed) = Install::check($phpath); + check_php($phpath, $checks); + + check_htaccess($checks); + + /// @TODO Maybe move this out? + function check_passed($v, $c) { + if ($c['required']) { + $v = $v && $c['status']; + } + return $v; + } + $checkspassed = array_reduce($checks, "check_passed", true); + + $tpl = get_markup_template('install_checks.tpl'); $o .= replace_macros($tpl, [ diff --git a/mod/invite.php b/mod/invite.php index 6807ff2c12..813dbf7044 100644 --- a/mod/invite.php +++ b/mod/invite.php @@ -144,14 +144,13 @@ function invite_content(App $a) { $o = replace_macros($tpl, [ '$form_security_token' => get_form_security_token("send_invite"), - '$invite' => L10n::t('Send invitations'), - '$addr_text' => L10n::t('Enter email addresses, one per line:'), - '$msg_text' => L10n::t('Your message:'), - '$default_message' => L10n::t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n" + '$title' => L10n::t('Send invitations'), + '$recipients' => ['recipients', L10n::t('Enter email addresses, one per line:')], + '$message' => ['message', L10n::t('Your message:'),L10n::t('You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web.') . "\r\n" . "\r\n" . $linktxt . "\r\n" . "\r\n" . (($invonly) ? L10n::t('You will need to supply this invitation code: $invite_code') . "\r\n" . "\r\n" : '') .L10n::t('Once you have registered, please connect with me via my profile page at:') . "\r\n" . "\r\n" . System::baseUrl() . '/profile/' . $a->user['nickname'] - . "\r\n" . "\r\n" . L10n::t('For more information about the Friendica project and why we feel it is important, please visit http://friendi.ca') . "\r\n" . "\r\n" , + . "\r\n" . "\r\n" . L10n::t('For more information about the Friendica project and why we feel it is important, please visit http://friendi.ca') . "\r\n" . "\r\n"], '$submit' => L10n::t('Submit') ]); diff --git a/mod/noscrape.php b/mod/noscrape.php index 9efaeb2bf1..20936929dd 100644 --- a/mod/noscrape.php +++ b/mod/noscrape.php @@ -23,9 +23,18 @@ function noscrape_init(App $a) Profile::load($a, $which, $profile); + $json_info = [ + 'addr' => $a->profile['addr'], + 'nick' => $which, + 'guid' => $a->profile['guid'], + 'key' => $a->profile['pubkey'], + 'homepage' => System::baseUrl()."/profile/{$which}", + 'comm' => ($a->profile['account-type'] == ACCOUNT_TYPE_COMMUNITY), + ]; + if (!$a->profile['net-publish'] || $a->profile['hidewall']) { header('Content-type: application/json; charset=utf-8'); - $json_info = ["hide" => true]; + $json_info["hide"] = true; echo json_encode($json_info); exit; } @@ -36,17 +45,9 @@ function noscrape_init(App $a) $contactPhoto = dba::selectFirst('contact', ['photo'], ['self' => true, 'uid' => $a->profile['uid']]); - $json_info = [ - 'fn' => $a->profile['name'], - 'addr' => $a->profile['addr'], - 'nick' => $which, - 'guid' => $a->profile['guid'], - 'key' => $a->profile['pubkey'], - 'homepage' => System::baseUrl()."/profile/{$which}", - 'comm' => (x($a->profile, 'page-flags')) && ($a->profile['page-flags'] == PAGE_COMMUNITY), - 'photo' => $contactPhoto["photo"], - 'tags' => $keywords - ]; + $json_info['fn'] = $a->profile['name']; + $json_info['photo'] = $contactPhoto["photo"]; + $json_info['tags'] = $keywords; if (is_array($a->profile) && !$a->profile['hide-friends']) { /// @todo What should this value tell us? diff --git a/mod/profile.php b/mod/profile.php index ab11b4d5fe..d6cbd276ff 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -191,7 +191,7 @@ function profile_content(App $a, $update = 0) $o .= Widget::commonFriendsVisitor($a->profile['profile_uid']); if (x($_SESSION, 'new_member') && $is_owner) { - $o .= '' . L10n::t('Tips for New Members') . '' . EOL; + $o .= '
' . L10n::t('Tips for New Members') . '
'; } $commpage = $a->profile['page-flags'] == PAGE_COMMUNITY; diff --git a/mod/settings.php b/mod/settings.php index aec2b2a050..3102fef233 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -12,6 +12,7 @@ use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\PConfig; use Friendica\Core\System; +use Friendica\Core\Theme; use Friendica\Core\Worker; use Friendica\Database\DBM; use Friendica\Model\Contact; @@ -354,6 +355,7 @@ function settings_post(App $a) theme_post($a); } } + Theme::install($theme); $r = q("UPDATE `user` SET `theme` = '%s' WHERE `uid` = %d", dbesc($theme), diff --git a/src/Content/ForumManager.php b/src/Content/ForumManager.php index 4f09b8a112..cfd083f9f8 100644 --- a/src/Content/ForumManager.php +++ b/src/Content/ForumManager.php @@ -49,7 +49,7 @@ class ForumManager "SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro`, `contact`.`thumb` FROM `contact` WHERE `network`= 'dfrn' AND $select AND `uid` = ? - AND NOT `blocked` AND NOT `hidden` AND NOT `pending` AND NOT `archive` + AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `success_update` > `failure_update` $order ", $uid diff --git a/src/Content/Nav.php b/src/Content/Nav.php index c7dfd447cd..cd2cfb3639 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -28,23 +28,23 @@ class Nav if (!(x($a->page, 'nav'))) { $a->page['nav'] = ''; } - + $a->page['htmlhead'] .= replace_macros(get_markup_template('nav_head.tpl'), []); - + /* * Placeholder div for popup panel */ - + $a->page['nav'] .= '' ; - + $nav_info = self::getInfo($a); - + /* * Build the page */ - + $tpl = get_markup_template('nav.tpl'); - + $a->page['nav'] .= replace_macros($tpl, [ '$baseurl' => System::baseUrl(), '$sitelocation' => $nav_info['sitelocation'], @@ -57,10 +57,10 @@ class Nav '$clear_notifs' => L10n::t('Clear notifications'), '$search_hint' => L10n::t('@name, !forum, #tags, content') ]); - + Addon::callHooks('page_header', $a->page['nav']); } - + /** * Prepares a list of navigation links * @@ -75,27 +75,27 @@ class Nav private static function getInfo(App $a) { $ssl_state = ((local_user()) ? true : false); - + /* * Our network is distributed, and as you visit friends some of the * sites look exactly the same - it isn't always easy to know where you are. * Display the current site location as a navigation aid. */ - + $myident = ((is_array($a->user) && isset($a->user['nickname'])) ? $a->user['nickname'] . '@' : ''); - + $sitelocation = $myident . substr(System::baseUrl($ssl_state), strpos(System::baseUrl($ssl_state), '//') + 2); - + // nav links: array of array('href', 'text', 'extra css classes', 'title') $nav = []; - + // Display login or logout $nav['usermenu'] = []; $userinfo = null; - + if (local_user()) { $nav['logout'] = ['logout', L10n::t('Logout'), '', L10n::t('End this session')]; - + // user menu $nav['usermenu'][] = ['profile/' . $a->user['nickname'], L10n::t('Status'), '', L10n::t('Your posts and conversations')]; $nav['usermenu'][] = ['profile/' . $a->user['nickname'] . '?tab=profile', L10n::t('Profile'), '', L10n::t('Your profile page')]; @@ -103,7 +103,7 @@ class Nav $nav['usermenu'][] = ['videos/' . $a->user['nickname'], L10n::t('Videos'), '', L10n::t('Your videos')]; $nav['usermenu'][] = ['events/', L10n::t('Events'), '', L10n::t('Your events')]; $nav['usermenu'][] = ['notes/', L10n::t('Personal notes'), '', L10n::t('Your personal notes')]; - + // user info $contact = dba::selectFirst('contact', ['micro'], ['uid' => $a->user['uid'], 'self' => true]); $userinfo = [ @@ -113,120 +113,117 @@ class Nav } else { $nav['login'] = ['login', L10n::t('Login'), ($a->module == 'login' ? 'selected' : ''), L10n::t('Sign in')]; } - + // "Home" should also take you home from an authenticated remote profile connection $homelink = Profile::getMyURL(); if (! $homelink) { $homelink = ((x($_SESSION, 'visitor_home')) ? $_SESSION['visitor_home'] : ''); } - + if (($a->module != 'home') && (! (local_user()))) { $nav['home'] = [$homelink, L10n::t('Home'), '', L10n::t('Home Page')]; } - + if (($a->config['register_policy'] == REGISTER_OPEN) && (! local_user()) && (! remote_user())) { $nav['register'] = ['register', L10n::t('Register'), '', L10n::t('Create an account')]; } - + $help_url = 'help'; - + if (!Config::get('system', 'hide_help')) { $nav['help'] = [$help_url, L10n::t('Help'), '', L10n::t('Help and documentation')]; } - + if (count($a->apps) > 0) { $nav['apps'] = ['apps', L10n::t('Apps'), '', L10n::t('Addon applications, utilities, games')]; } - + if (local_user() || !Config::get('system', 'local_search')) { $nav['search'] = ['search', L10n::t('Search'), '', L10n::t('Search site content')]; - + $nav['searchoption'] = [ L10n::t('Full Text'), L10n::t('Tags'), L10n::t('Contacts') ]; - + if (Config::get('system', 'poco_local_search')) { $nav['searchoption'][] = L10n::t('Forums'); } } - + $gdirpath = 'directory'; - + if (strlen(Config::get('system', 'singleuser'))) { $gdir = Config::get('system', 'directory'); if (strlen($gdir)) { $gdirpath = Profile::zrl($gdir, true); } } - - if (local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) { + + if ((local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) && + !(Config::get('system', 'community_page_style') == CP_NO_INTERNAL_COMMUNITY)) { $nav['community'] = ['community', L10n::t('Community'), '', L10n::t('Conversations on this and other servers')]; } - + if (local_user()) { $nav['events'] = ['events', L10n::t('Events'), '', L10n::t('Events and Calendar')]; } - + $nav['directory'] = [$gdirpath, L10n::t('Directory'), '', L10n::t('People directory')]; - + $nav['about'] = ['friendica', L10n::t('Information'), '', L10n::t('Information about this friendica instance')]; - + // The following nav links are only show to logged in users if (local_user()) { $nav['network'] = ['network', L10n::t('Network'), '', L10n::t('Conversations from your friends')]; $nav['net_reset'] = ['network/0?f=&order=comment&nets=all', L10n::t('Network Reset'), '', L10n::t('Load Network page with no filters')]; - + $nav['home'] = ['profile/' . $a->user['nickname'], L10n::t('Home'), '', L10n::t('Your posts and conversations')]; - - if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE, PAGE_PRVGROUP])) { - // only show friend requests for normal pages. Other page types have automatic friendship. - if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_PRVGROUP])) { - $nav['introductions'] = ['notifications/intros', L10n::t('Introductions'), '', L10n::t('Friend Requests')]; - } - if (in_array($_SESSION['page_flags'], [PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE])) { - $nav['notifications'] = ['notifications', L10n::t('Notifications'), '', L10n::t('Notifications')]; - $nav['notifications']['all'] = ['notifications/system', L10n::t('See all notifications'), '', '']; - $nav['notifications']['mark'] = ['', L10n::t('Mark as seen'), '', L10n::t('Mark all system notifications seen')]; - } + + // Don't show notifications for public communities + if ($_SESSION['page_flags'] != PAGE_COMMUNITY) { + $nav['introductions'] = ['notifications/intros', L10n::t('Introductions'), '', L10n::t('Friend Requests')]; + $nav['notifications'] = ['notifications', L10n::t('Notifications'), '', L10n::t('Notifications')]; + $nav['notifications']['all'] = ['notifications/system', L10n::t('See all notifications'), '', '']; + $nav['notifications']['mark'] = ['', L10n::t('Mark as seen'), '', L10n::t('Mark all system notifications seen')]; } - + $nav['messages'] = ['message', L10n::t('Messages'), '', L10n::t('Private mail')]; $nav['messages']['inbox'] = ['message', L10n::t('Inbox'), '', L10n::t('Inbox')]; $nav['messages']['outbox'] = ['message/sent', L10n::t('Outbox'), '', L10n::t('Outbox')]; $nav['messages']['new'] = ['message/new', L10n::t('New Message'), '', L10n::t('New Message')]; - + if (is_array($a->identities) && count($a->identities) > 1) { $nav['manage'] = ['manage', L10n::t('Manage'), '', L10n::t('Manage other pages')]; } - + $nav['delegations'] = ['delegate', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')]; - + $nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')]; - + if (Feature::isEnabled(local_user(), 'multi_profiles')) { $nav['profiles'] = ['profiles', L10n::t('Profiles'), '', L10n::t('Manage/Edit Profiles')]; } - + $nav['contacts'] = ['contacts', L10n::t('Contacts'), '', L10n::t('Manage/edit friends and contacts')]; } - + // Show the link to the admin configuration page if user is admin if (is_site_admin()) { $nav['admin'] = ['admin/', L10n::t('Admin'), '', L10n::t('Site setup and configuration')]; } - + $nav['navigation'] = ['navigation/', L10n::t('Navigation'), '', L10n::t('Site map')]; - + // Provide a banner/logo/whatever $banner = Config::get('system', 'banner'); if (is_null($banner)) { $banner = 'logoFriendica'; } - + Addon::callHooks('nav_info', $nav); - + return [ 'sitelocation' => $sitelocation, 'nav' => $nav, @@ -234,7 +231,7 @@ class Nav 'userinfo' => $userinfo, ]; } - + /** * Set a menu item in navbar as selected */ diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 3755593465..6c441bac6f 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -343,159 +343,20 @@ class BBCode extends BaseObject } /** - * @brief Convert a message into plaintext for connectors to other networks + * @brief Converts a BBCode text into plaintext * - * @param array $b The message array that is about to be posted - * @param int $limit The maximum number of characters when posting to that network - * @param bool $includedlinks Has an attached link to be included into the message? - * @param int $htmlmode This triggers the behaviour of the bbcode conversion - * @param string $target_network Name of the network where the post should go to. + * @param bool $keep_urls Whether to keep URLs in the resulting plaintext * - * @return string The converted message + * @return string */ - public static function toPlaintext($b, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = "") + public static function toPlaintext($text, $keep_urls = true) { - // Remove the hash tags - $URLSearchString = "^\[\]"; - $body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $b["body"]); - - // Add an URL element if the text contains a raw link - $body = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2[/url]', $body); - - // Remove the abstract - $body = self::stripAbstract($body); - - // At first look at data that is attached via "type-..." stuff - // This will hopefully replaced with a dedicated bbcode later - //$post = self::getAttachedData($b["body"]); - $post = self::getAttachedData($body, $b); - - if (($b["title"] != "") && ($post["text"] != "")) { - $post["text"] = trim($b["title"]."\n\n".$post["text"]); - } elseif ($b["title"] != "") { - $post["text"] = trim($b["title"]); + $naked_text = preg_replace('/\[(.+?)\]/','', $text); + if (!$keep_urls) { + $naked_text = preg_replace('#https?\://[^\s<]+[^\s\.\)]#i', '', $naked_text); } - $abstract = ""; - - // Fetch the abstract from the given target network - if ($target_network != "") { - $default_abstract = self::getAbstract($b["body"]); - $abstract = self::getAbstract($b["body"], $target_network); - - // If we post to a network with no limit we only fetch - // an abstract exactly for this network - if (($limit == 0) && ($abstract == $default_abstract)) { - $abstract = ""; - } - } else {// Try to guess the correct target network - switch ($htmlmode) { - case 8: - $abstract = self::getAbstract($b["body"], NETWORK_TWITTER); - break; - case 7: - $abstract = self::getAbstract($b["body"], NETWORK_STATUSNET); - break; - case 6: - $abstract = self::getAbstract($b["body"], NETWORK_APPNET); - break; - default: // We don't know the exact target. - // We fetch an abstract since there is a posting limit. - if ($limit > 0) { - $abstract = self::getAbstract($b["body"]); - } - } - } - - if ($abstract != "") { - $post["text"] = $abstract; - - if ($post["type"] == "text") { - $post["type"] = "link"; - $post["url"] = $b["plink"]; - } - } - - $html = self::convert($post["text"].$post["after"], false, $htmlmode); - $msg = HTML::toPlaintext($html, 0, true); - $msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8')); - - $link = ""; - if ($includedlinks) { - if ($post["type"] == "link") { - $link = $post["url"]; - } elseif ($post["type"] == "text") { - $link = $post["url"]; - } elseif ($post["type"] == "video") { - $link = $post["url"]; - } elseif ($post["type"] == "photo") { - $link = $post["image"]; - } - - if (($msg == "") && isset($post["title"])) { - $msg = trim($post["title"]); - } - - if (($msg == "") && isset($post["description"])) { - $msg = trim($post["description"]); - } - - // If the link is already contained in the post, then it neeedn't to be added again - // But: if the link is beyond the limit, then it has to be added. - if (($link != "") && strstr($msg, $link)) { - $pos = strpos($msg, $link); - - // Will the text be shortened in the link? - // Or is the link the last item in the post? - if (($limit > 0) && ($pos < $limit) && (($pos + 23 > $limit) || ($pos + strlen($link) == strlen($msg)))) { - $msg = trim(str_replace($link, "", $msg)); - } elseif (($limit == 0) || ($pos < $limit)) { - // The limit has to be increased since it will be shortened - but not now - // Only do it with Twitter (htmlmode = 8) - if (($limit > 0) && (strlen($link) > 23) && ($htmlmode == 8)) { - $limit = $limit - 23 + strlen($link); - } - - $link = ""; - - if ($post["type"] == "text") { - unset($post["url"]); - } - } - } - } - - if ($limit > 0) { - // Reduce multiple spaces - // When posted to a network with limited space, we try to gain space where possible - while (strpos($msg, " ") !== false) { - $msg = str_replace(" ", " ", $msg); - } - - // Twitter is using its own limiter, so we always assume that shortened links will have this length - if (iconv_strlen($link, "UTF-8") > 0) { - $limit = $limit - 23; - } - - if (iconv_strlen($msg, "UTF-8") > $limit) { - if (($post["type"] == "text") && isset($post["url"])) { - $post["url"] = $b["plink"]; - } elseif (!isset($post["url"])) { - $limit = $limit - 23; - $post["url"] = $b["plink"]; - // Which purpose has this line? It is now uncommented, but left as a reminder - //} elseif (strpos($b["body"], "[share") !== false) { - // $post["url"] = $b["plink"]; - } elseif (PConfig::get($b["uid"], "system", "no_intelligent_shortening")) { - $post["url"] = $b["plink"]; - } - $msg = Plaintext::shorten($msg, $limit); - } - } - - $post["text"] = trim($msg); - - return($post); + return $naked_text; } public static function scaleExternalImages($srctext, $include_link = true, $scale_replace = false) @@ -1947,7 +1808,7 @@ class BBCode extends BaseObject * @param string $addon The addon for which the abstract is meant for * @return string The abstract */ - private static function getAbstract($text, $addon = "") + public static function getAbstract($text, $addon = "") { $abstract = ""; $abstracts = []; diff --git a/src/Content/Widget.php b/src/Content/Widget.php index 058a7a1fb5..04dfbb8e03 100644 --- a/src/Content/Widget.php +++ b/src/Content/Widget.php @@ -55,19 +55,24 @@ class Widget } } - return replace_macros(get_markup_template('peoplefind.tpl'), array( - '$findpeople' => L10n::t('Find People'), - '$desc' => L10n::t('Enter name or interest'), - '$label' => L10n::t('Connect/Follow'), - '$hint' => L10n::t('Examples: Robert Morgenstein, Fishing'), - '$findthem' => L10n::t('Find'), - '$suggest' => L10n::t('Friend Suggestions'), - '$similar' => L10n::t('Similar Interests'), - '$random' => L10n::t('Random Profile'), - '$inv' => L10n::t('Invite Friends'), - '$directory' => L10n::t('View Global Directory'), - '$global_dir' => $global_dir - )); + $nv = []; + $nv['findpeople'] = L10n::t('Find People'); + $nv['desc'] = L10n::t('Enter name or interest'); + $nv['label'] = L10n::t('Connect/Follow'); + $nv['hint'] = L10n::t('Examples: Robert Morgenstein, Fishing'); + $nv['findthem'] = L10n::t('Find'); + $nv['suggest'] = L10n::t('Friend Suggestions'); + $nv['similar'] = L10n::t('Similar Interests'); + $nv['random'] = L10n::t('Random Profile'); + $nv['inv'] = L10n::t('Invite Friends'); + $nv['directory'] = L10n::t('Global Directory'); + $nv['global_dir'] = $global_dir; + $nv['local_directory'] = L10n::t('Local Directory'); + + $aside = []; + $aside['$nv'] = $nv; + + return replace_macros(get_markup_template('peoplefind.tpl'), $aside); } /** diff --git a/src/Core/Addon.php b/src/Core/Addon.php index a3bfeec32b..3adc7fc0ec 100644 --- a/src/Core/Addon.php +++ b/src/Core/Addon.php @@ -246,7 +246,7 @@ class Addon } else { // remove orphan hooks $condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]]; - dba::delete('hook', $condition); + dba::delete('hook', $condition, ['cascade' => false]); } } diff --git a/src/Core/Console.php b/src/Core/Console.php index 82c485179e..a5aff4ae80 100644 --- a/src/Core/Console.php +++ b/src/Core/Console.php @@ -21,6 +21,7 @@ class Console extends \Asika\SimpleConsole\Console 'extract' => __NAMESPACE__ . '\Console\Extract', 'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock', 'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence', + 'archivecontact' => __NAMESPACE__ . '\Console\ArchiveContact', 'autoinstall' => __NAMESPACE__ . '\Console\AutomaticInstallation', 'maintenance' => __NAMESPACE__ . '\Console\Maintenance', 'newpassword' => __NAMESPACE__ . '\Console\NewPassword', @@ -42,6 +43,7 @@ Commands: extract Generate translation string file for the Friendica project (deprecated) globalcommunityblock Block remote profile from interacting with this node globalcommunitysilence Silence remote profile from global community page + archivecontact Archive a contact when you know that it isn't existing anymore help Show help about a command, e.g (bin/console help config) autoinstall Starts automatic installation of friendica based on values from htconfig.php maintenance Set maintenance mode for this node diff --git a/src/Core/Console/ArchiveContact.php b/src/Core/Console/ArchiveContact.php new file mode 100644 index 0000000000..7a973f3116 --- /dev/null +++ b/src/Core/Console/ArchiveContact.php @@ -0,0 +1,79 @@ + [-h|--help|-?] [-v] + +Description + Archive a contact when you know that it isn't existing anymore. Normally this does happen automatically after a few days. + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + $a = get_app(); + + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + $nurl = normalise_link($this->getArgument(0)); + if (!dba::exists('contact', ['nurl' => $nurl, 'archive' => false])) { + throw new \RuntimeException(L10n::t('Could not find any unarchived contact entry for this URL (%s)', $nurl)); + } + if (dba::update('contact', ['archive' => true], ['nurl' => $nurl])) { + $condition = ["`cid` IN (SELECT `id` FROM `contact` WHERE `archive`)"]; + dba::delete('queue', $condition); + $this->out(L10n::t('The contact entries have been archived')); + } else { + throw new \RuntimeException('The contact archival failed.'); + } + + return 0; + } +} diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 48e8be3106..0bd5d06f68 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -423,7 +423,7 @@ class Contact extends BaseObject // Fetch the data from the gcontact table if (!DBM::is_result($r)) { $s = dba::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`, - `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, `community` AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self` + `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self` FROM `gcontact` WHERE `nurl` = ?", normalise_link($url)); $r = dba::inArray($s); } diff --git a/src/Model/Item.php b/src/Model/Item.php index bdb85af441..e7fd115dd1 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -7,6 +7,7 @@ namespace Friendica\Model; use Friendica\BaseObject; +use Friendica\Content\Text; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\L10n; @@ -838,6 +839,101 @@ class Item extends BaseObject return $current_post; } + /** + * @brief Distributes public items to the receivers + * + * @param integer $itemid Item ID that should be added + */ + public static function distribute($itemid) + { + $condition = ["`id` IN (SELECT `parent` FROM `item` WHERE `id` = ?)", $itemid]; + $parent = dba::selectFirst('item', ['owner-id'], $condition); + if (!DBM::is_result($parent)) { + return; + } + + // Only distribute public items from native networks + $condition = ['id' => $itemid, 'uid' => 0, + 'network' => [NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""], + 'visible' => true, 'deleted' => false, 'moderated' => false, 'private' => false]; + $item = dba::selectFirst('item', [], ['id' => $itemid]); + if (!DBM::is_result($item)) { + return; + } + + unset($item['id']); + unset($item['parent']); + unset($item['mention']); + unset($item['wall']); + unset($item['origin']); + unset($item['starred']); + unset($item['rendered-hash']); + unset($item['rendered-html']); + + $users = []; + + $condition = ["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `id` = ?) AND `uid` != 0 AND NOT `blocked` AND NOT `readonly` AND `rel` IN (?, ?)", + $parent['owner-id'], CONTACT_IS_SHARING, CONTACT_IS_FRIEND]; + $contacts = dba::select('contact', ['uid'], $condition); + while ($contact = dba::fetch($contacts)) { + $users[$contact['uid']] = $contact['uid']; + } + + if ($item['uri'] != $item['parent-uri']) { + $parents = dba::select('item', ['uid'], ["`uri` = ? AND `uid` != 0", $item['parent-uri']]); + while ($parent = dba::fetch($parents)) { + $users[$parent['uid']] = $parent['uid']; + } + } + + foreach ($users as $uid) { + self::storeForUser($itemid, $item, $uid); + } + } + + /** + * @brief Store public items for the receivers + * + * @param integer $itemid Item ID that should be added + * @param array $item The item entry that will be stored + * @param integer $uid The user that will receive the item entry + */ + private static function storeForUser($itemid, $item, $uid) + { + $item['uid'] = $uid; + $item['origin'] = 0; + $item['wall'] = 0; + if ($item['uri'] == $item['parent-uri']) { + $item['contact-id'] = Contact::getIdForURL($item['owner-link'], $uid); + } else { + $item['contact-id'] = Contact::getIdForURL($item['author-link'], $uid); + } + + if (empty($item['contact-id'])) { + $self = dba::selectFirst('contact', ['id'], ['self' => true, 'uid' => $uid]); + if (!DBM::is_result($self)) { + return; + } + $item['contact-id'] = $self['id']; + } + + if (in_array($item['type'], ["net-comment", "wall-comment"])) { + $item['type'] = 'remote-comment'; + } elseif ($item['type'] == 'wall') { + $item['type'] = 'remote'; + } + + /// @todo Handling of "event-id" + + $distributed = self::insert($item, false, false, true); + + if (!$distributed) { + logger("Distributed public item " . $itemid . " for user " . $uid . " wasn't stored", LOGGER_DEBUG); + } else { + logger("Distributed public item " . $itemid . " for user " . $uid . " with id " . $distributed, LOGGER_DEBUG); + } + } + /** * @brief Add a shadow entry for a given item id that is a thread starter * @@ -849,8 +945,8 @@ class Item extends BaseObject */ public static function addShadow($itemid) { - $fields = ['uid', 'wall', 'private', 'moderated', 'visible', 'contact-id', 'deleted', 'network', 'author-id', 'owner-id']; - $condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid]; + $fields = ['uid', 'private', 'moderated', 'visible', 'deleted', 'network']; + $condition = ['id' => $itemid, 'parent' => [0, $itemid]]; $item = dba::selectFirst('item', $fields, $condition); if (!DBM::is_result($item)) { @@ -872,35 +968,22 @@ class Item extends BaseObject return; } - // Only do these checks if the post isn't a wall post - if (!$item["wall"]) { - // Check, if hide-friends is activated - then don't do a shadow entry - if (dba::exists('profile', ['is-default' => true, 'uid' => $item['uid'], 'hide-friends' => true])) { - return; - } - - // Check if the contact is hidden or blocked - if (!dba::exists('contact', ['hidden' => false, 'blocked' => false, 'id' => $item['contact-id']])) { - return; - } - } - - // Only add a shadow, if the profile isn't hidden - if (dba::exists('user', ['uid' => $item['uid'], 'hidewall' => true])) { - return; - } - $item = dba::selectFirst('item', [], ['id' => $itemid]); - if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') && + if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') && ($item["deny_cid"] == '') && ($item["deny_gid"] == '')) { if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) { // Preparing public shadow (removing user specific data) - unset($item['id']); $item['uid'] = 0; - $item['origin'] = 0; - $item['wall'] = 0; + unset($item['id']); + unset($item['parent']); + unset($item['wall']); + unset($item['mention']); + unset($item['origin']); + unset($item['starred']); + unset($item['rendered-hash']); + unset($item['rendered-html']); if ($item['uri'] == $item['parent-uri']) { $item['contact-id'] = Contact::getIdForURL($item['owner-link']); } else { @@ -954,11 +1037,20 @@ class Item extends BaseObject return; } + // Save "origin" and "parent" state + $origin = $item['origin']; + $parent = $item['parent']; + // Preparing public shadow (removing user specific data) - unset($item['id']); $item['uid'] = 0; - $item['origin'] = 0; - $item['wall'] = 0; + unset($item['id']); + unset($item['parent']); + unset($item['wall']); + unset($item['mention']); + unset($item['origin']); + unset($item['starred']); + unset($item['rendered-hash']); + unset($item['rendered-html']); $item['contact-id'] = Contact::getIdForURL($item['author-link']); if (in_array($item['type'], ["net-comment", "wall-comment"])) { @@ -970,6 +1062,14 @@ class Item extends BaseObject $public_shadow = self::insert($item, false, false, true); logger("Stored public shadow for comment ".$item['uri']." under id ".$public_shadow, LOGGER_DEBUG); + + // If this was a comment to a Diaspora post we don't get our comment back. + // This means that we have to distribute the comment by ourselves. + if ($origin) { + if (dba::exists('item', ['id' => $parent, 'network' => NETWORK_DIASPORA])) { + self::distribute($public_shadow); + } + } } /** @@ -977,35 +1077,35 @@ class Item extends BaseObject * if possible and not already present. * Expects "body" element to exist in $arr. */ - private static function addLanguageInPostopts(&$arr) + private static function addLanguageInPostopts(&$item) { - if (x($arr, 'postopts')) { - if (strstr($arr['postopts'], 'lang=')) { + if (!empty($item['postopts'])) { + if (strstr($item['postopts'], 'lang=')) { // do not override return; } - $postopts = $arr['postopts']; + $postopts = $item['postopts']; } else { $postopts = ""; } - $naked_body = preg_replace('/\[(.+?)\]/','', $arr['body']); - $l = new Text_LanguageDetect(); - $lng = $l->detect($naked_body, 3); + $naked_body = Text\BBCode::toPlaintext($item['body'], false); - if (sizeof($lng) > 0) { - if ($postopts != "") { + $languages = (new Text_LanguageDetect())->detect($naked_body, 3); + + if (sizeof($languages) > 0) { + if ($postopts != '') { $postopts .= '&'; // arbitrary separator, to be reviewed } $postopts .= 'lang='; $sep = ""; - foreach ($lng as $language => $score) { + foreach ($languages as $language => $score) { $postopts .= $sep . $language . ";" . $score; $sep = ':'; } - $arr['postopts'] = $postopts; + $item['postopts'] = $postopts; } } diff --git a/src/Model/ItemContent.php b/src/Model/ItemContent.php new file mode 100644 index 0000000000..21dbd34d0a --- /dev/null +++ b/src/Model/ItemContent.php @@ -0,0 +1,176 @@ + 0) { + $abstract = Text\BBCode::getAbstract($item['body']); + } + } + } + + if ($abstract != '') { + $post['text'] = $abstract; + + if ($post['type'] == 'text') { + $post['type'] = 'link'; + $post['url'] = $item['plink']; + } + } + + $html = Text\BBCode::convert($post['text'] . $post['after'], false, $htmlmode); + $msg = Text\HTML::toPlaintext($html, 0, true); + $msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8')); + + $link = ''; + if ($includedlinks) { + if ($post['type'] == 'link') { + $link = $post['url']; + } elseif ($post['type'] == 'text') { + $link = $post['url']; + } elseif ($post['type'] == 'video') { + $link = $post['url']; + } elseif ($post['type'] == 'photo') { + $link = $post['image']; + } + + if (($msg == '') && isset($post['title'])) { + $msg = trim($post['title']); + } + + if (($msg == '') && isset($post['description'])) { + $msg = trim($post['description']); + } + + // If the link is already contained in the post, then it neeedn't to be added again + // But: if the link is beyond the limit, then it has to be added. + if (($link != '') && strstr($msg, $link)) { + $pos = strpos($msg, $link); + + // Will the text be shortened in the link? + // Or is the link the last item in the post? + if (($limit > 0) && ($pos < $limit) && (($pos + 23 > $limit) || ($pos + strlen($link) == strlen($msg)))) { + $msg = trim(str_replace($link, '', $msg)); + } elseif (($limit == 0) || ($pos < $limit)) { + // The limit has to be increased since it will be shortened - but not now + // Only do it with Twitter (htmlmode = 8) + if (($limit > 0) && (strlen($link) > 23) && ($htmlmode == 8)) { + $limit = $limit - 23 + strlen($link); + } + + $link = ''; + + if ($post['type'] == 'text') { + unset($post['url']); + } + } + } + } + + if ($limit > 0) { + // Reduce multiple spaces + // When posted to a network with limited space, we try to gain space where possible + while (strpos($msg, ' ') !== false) { + $msg = str_replace(' ', ' ', $msg); + } + + // Twitter is using its own limiter, so we always assume that shortened links will have this length + if (iconv_strlen($link, 'UTF-8') > 0) { + $limit = $limit - 23; + } + + if (iconv_strlen($msg, 'UTF-8') > $limit) { + if (($post['type'] == 'text') && isset($post['url'])) { + $post['url'] = $item['plink']; + } elseif (!isset($post['url'])) { + $limit = $limit - 23; + $post['url'] = $item['plink']; + } elseif (strpos($item['body'], '[share') !== false) { + $post['url'] = $item['plink']; + } elseif (PConfig::get($item['uid'], 'system', 'no_intelligent_shortening')) { + $post['url'] = $item['plink']; + } + $msg = Text\Plaintext::shorten($msg, $limit); + } + } + + $post['text'] = trim($msg); + + return $post; + } +} diff --git a/src/Model/Profile.php b/src/Model/Profile.php index ec53d064d6..d4773a8062 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -92,14 +92,14 @@ class Profile { $user = dba::selectFirst('user', ['uid'], ['nickname' => $nickname]); - if (!$user && !count($user) && !count($profiledata)) { + if (!DBM::is_result($user) && empty($profiledata)) { logger('profile error: ' . $a->query_string, LOGGER_DEBUG); notice(L10n::t('Requested account is not available.') . EOL); $a->error = 404; return; } - if (!x($a->page, 'aside')) { + if (empty($a->page['aside'])) { $a->page['aside'] = ''; } @@ -157,10 +157,6 @@ class Profile require_once $theme_info_file; } - if (!x($a->page, 'aside')) { - $a->page['aside'] = ''; - } - if (local_user() && local_user() == $a->profile['uid'] && $profiledata) { $a->page['aside'] .= replace_macros( get_markup_template('profile_edlink.tpl'), @@ -644,26 +640,26 @@ class Profile $classtoday = ''; $s = dba::p( - "SELECT * + "SELECT `event`.* FROM `event` - WHERE `event`.`uid` = ? - AND `event`.`type` != 'birthday' - AND `event`.`start` < ? - AND `event`.`start` >= ? - AND NOT EXISTS ( - SELECT `id` - FROM `item` - WHERE `item`.`uid` = `event`.`uid` + INNER JOIN `item` + ON `item`.`uid` = `event`.`uid` AND `item`.`parent-uri` = `event`.`uri` - AND `item`.`verb` = ? - AND `item`.`visible` - AND NOT `item`.`deleted` - ) + WHERE `event`.`uid` = ? + AND `event`.`type` != 'birthday' + AND `event`.`start` < ? + AND `event`.`start` >= ? + AND `item`.`author-id` = ? + AND (`item`.`verb` = ? OR `item`.`verb` = ?) + AND `item`.`visible` + AND NOT `item`.`deleted` ORDER BY `event`.`start` ASC", local_user(), DateTimeFormat::utc('now + 7 days'), DateTimeFormat::utc('now - 1 days'), - ACTIVITY_ATTENDNO + public_contact(), + ACTIVITY_ATTEND, + ACTIVITY_ATTENDMAYBE ); $r = []; @@ -954,7 +950,7 @@ class Profile ]; } - if ((!$is_owner) && ((count($a->profile)) || (!$a->profile['hide-friends']))) { + if (!$is_owner && empty($a->profile['hide-friends'])) { $tabs[] = [ 'label' => L10n::t('Contacts'), 'url' => System::baseUrl() . '/viewcontacts/' . $nickname, diff --git a/src/Object/Post.php b/src/Object/Post.php index 86e1414678..820730a32b 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -78,7 +78,7 @@ class Post extends BaseObject } // Prepare the children - if (count($data['children'])) { + if (!empty($data['children'])) { foreach ($data['children'] as $item) { // Only add will be displayed if ($item['network'] === NETWORK_MAIL && local_user() != $item['uid']) { diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index d1a4f0c4be..f233f158a9 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1197,6 +1197,7 @@ class DFRN $ret = Network::curl($url); if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { + Contact::markForArchival($contact); return -2; // timed out } @@ -1204,24 +1205,28 @@ class DFRN $curl_stat = $a->get_curl_code(); if (empty($curl_stat)) { + Contact::markForArchival($contact); return -3; // timed out } logger('dfrn_deliver: ' . $xml, LOGGER_DATA); if (empty($xml)) { + Contact::markForArchival($contact); return 3; } if (strpos($xml, 'status) != 0) || (! strlen($res->challenge)) || (! strlen($res->dfrn_id))) { + if ((intval($res->status) != 0) || !strlen($res->challenge) || !strlen($res->dfrn_id)) { + Contact::markForArchival($contact); return ($res->status ? $res->status : 3); } @@ -1274,6 +1279,7 @@ class DFRN if ($final_dfrn_id != $orig_id) { logger('dfrn_deliver: wrong dfrn_id.'); // did not decode properly - cannot trust this site + Contact::markForArchival($contact); return 3; } @@ -1309,6 +1315,7 @@ class DFRN break; default: logger("rino: invalid requested version '$rino_remote_version'"); + Contact::markForArchival($contact); return -8; } @@ -1346,22 +1353,26 @@ class DFRN $curl_stat = $a->get_curl_code(); if (empty($curl_stat) || empty($xml)) { + Contact::markForArchival($contact); return -9; // timed out } if (($curl_stat == 503) && stristr($a->get_curl_headers(), 'retry-after')) { + Contact::markForArchival($contact); return -10; } if (strpos($xml, 'status)) { + Contact::markForArchival($contact); return -11; } @@ -1374,7 +1385,7 @@ class DFRN logger('Delivery returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG); } - if ($res->status == 200) { + if (($res->status >= 200) && ($res->status <= 299)) { Contact::unmarkForArchival($contact); } @@ -1394,28 +1405,41 @@ class DFRN { $a = get_app(); - if (empty($contact['addr'])) { - logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.'); - if (Contact::updateFromProbe($contact['id'])) { - $new_contact = dba::selectFirst('contact', ['addr'], ['id' => $contact['id']]); - $contact['addr'] = $new_contact['addr']; - } - + if (!$public_batch) { if (empty($contact['addr'])) { - logger('Unable to find contact handle for ' . $contact['id'] . ' - ' . $contact['url']); - return -21; - } - } + logger('Empty contact handle for ' . $contact['id'] . ' - ' . $contact['url'] . ' - trying to update it.'); + if (Contact::updateFromProbe($contact['id'])) { + $new_contact = dba::selectFirst('contact', ['addr'], ['id' => $contact['id']]); + $contact['addr'] = $new_contact['addr']; + } - $fcontact = Diaspora::personByHandle($contact['addr']); - if (empty($fcontact)) { - logger('Unable to find contact details for ' . $contact['id'] . ' - ' . $contact['addr']); - return -22; + if (empty($contact['addr'])) { + logger('Unable to find contact handle for ' . $contact['id'] . ' - ' . $contact['url']); + Contact::markForArchival($contact); + return -21; + } + } + + $fcontact = Diaspora::personByHandle($contact['addr']); + if (empty($fcontact)) { + logger('Unable to find contact details for ' . $contact['id'] . ' - ' . $contact['addr']); + Contact::markForArchival($contact); + return -22; + } } $envelope = Diaspora::buildMessage($atom, $owner, $contact, $owner['uprvkey'], $fcontact['pubkey'], $public_batch); - $dest_url = ($public_batch ? $fcontact["batch"] : $contact["notify"]); + // Create the endpoint for public posts. This is some WIP and should later be added to the probing + if ($public_batch && empty($contact["batch"])) { + $parts = parse_url($contact["notify"]); + $path_parts = explode('/', $parts['path']); + array_pop($path_parts); + $parts['path'] = implode('/', $path_parts); + $contact["batch"] = Network::unparseURL($parts); + } + + $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); $content_type = ($public_batch ? "application/magic-envelope+xml" : "application/json"); @@ -1424,22 +1448,26 @@ class DFRN $curl_stat = $a->get_curl_code(); if (empty($curl_stat) || empty($xml)) { logger('Empty answer from ' . $contact['id'] . ' - ' . $dest_url); + Contact::markForArchival($contact); return -9; // timed out } if (($curl_stat == 503) && (stristr($a->get_curl_headers(), 'retry-after'))) { + Contact::markForArchival($contact); return -10; } if (strpos($xml, 'status)) { + Contact::markForArchival($contact); return -23; } @@ -1447,7 +1475,7 @@ class DFRN logger('Transmit to ' . $dest_url . ' returned status '.$res->status.' - '.$res->message, LOGGER_DEBUG); } - if ($res->status == 200) { + if (($res->status >= 200) && ($res->status <= 299)) { Contact::unmarkForArchival($contact); } @@ -1467,33 +1495,33 @@ class DFRN // Check for duplicates $r = q( "SELECT `id` FROM `event` WHERE `uid` = %d AND `cid` = %d AND `start` = '%s' AND `type` = '%s' LIMIT 1", - intval($contact["uid"]), - intval($contact["id"]), + intval($contact['uid']), + intval($contact['id']), dbesc(DateTimeFormat::utc($birthday)), - dbesc("birthday") + dbesc('birthday') ); if (DBM::is_result($r)) { return; } - logger("updating birthday: ".$birthday." for contact ".$contact["id"]); + logger('updating birthday: ' . $birthday . ' for contact ' . $contact['id']); - $bdtext = L10n::t("%s\'s birthday", $contact["name"]); - $bdtext2 = L10n::t("Happy Birthday %s", " [url=".$contact["url"]."]".$contact["name"]."[/url]"); + $bdtext = L10n::t('%s\'s birthday', $contact['name']); + $bdtext2 = L10n::t('Happy Birthday %s', ' [url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'); $r = q( "INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", - intval($contact["uid"]), - intval($contact["id"]), + intval($contact['uid']), + intval($contact['id']), dbesc(DateTimeFormat::utcNow()), dbesc(DateTimeFormat::utcNow()), dbesc(DateTimeFormat::utc($birthday)), - dbesc(DateTimeFormat::utc($birthday . " + 1 day ")), + dbesc(DateTimeFormat::utc($birthday . ' + 1 day ')), dbesc($bdtext), dbesc($bdtext2), - dbesc("birthday") + dbesc('birthday') ); } @@ -2747,6 +2775,10 @@ class DFRN if ($posted_id) { logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG); + if ($item['uid'] == 0) { + Item::distribute($posted_id); + } + $item["id"] = $posted_id; $r = q( @@ -2771,7 +2803,7 @@ class DFRN logger('ignoring read-only contact '.$importer["id"]); return; } - if ($importer["uid"] == 0) { + if (($importer["uid"] == 0) && ($importer["importer_uid"] != 0)) { logger("Contact ".$importer["id"]." isn't known to user ".$importer["importer_uid"].". The post will be ignored.", LOGGER_DEBUG); return; } @@ -2801,6 +2833,10 @@ class DFRN logger("Item was stored with id ".$posted_id, LOGGER_DEBUG); + if ($item['uid'] == 0) { + Item::distribute($posted_id); + } + if (stristr($item["verb"], ACTIVITY_POKE)) { self::doPoke($item, $importer, $posted_id); } @@ -2923,6 +2959,9 @@ class DFRN logger("Import DFRN message for user " . $importer["importer_uid"] . " from contact " . $importer["id"], LOGGER_DEBUG); + // is it a public forum? Private forums aren't exposed with this method + $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()")->item(0)->nodeValue); + // The account type is new since 3.5.1 if ($xpath->query("/atom:feed/dfrn:account_type")->length > 0) { $accounttype = intval($xpath->evaluate("/atom:feed/dfrn:account_type/text()")->item(0)->nodeValue); @@ -2930,17 +2969,17 @@ class DFRN if ($accounttype != $importer["contact-type"]) { dba::update('contact', ['contact-type' => $accounttype], ['id' => $importer["id"]]); } - } - - // is it a public forum? Private forums aren't supported with this method - // This is deprecated since 3.5.1 - $forum = intval($xpath->evaluate("/atom:feed/dfrn:community/text()")->item(0)->nodeValue); - - if ($forum != $importer["forum"]) { + // A forum contact can either have set "forum" or "prv" - but not both + if (($accounttype == ACCOUNT_TYPE_COMMUNITY) && (($forum != $importer["forum"]) || ($forum == $importer["prv"]))) { + $condition = ['(`forum` != ? OR `prv` != ?) AND `id` = ?', $forum, !$forum, $importer["id"]]; + dba::update('contact', ['forum' => $forum, 'prv' => !$forum], $condition); + } + } elseif ($forum != $importer["forum"]) { // Deprecated since 3.5.1 $condition = ['`forum` != ? AND `id` = ?', $forum, $importer["id"]]; dba::update('contact', ['forum' => $forum], $condition); } + // We are processing relocations even if we are ignoring a contact $relocations = $xpath->query("/atom:feed/dfrn:relocate"); foreach ($relocations as $relocation) { diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index e81c53499f..61d1a586fa 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -590,59 +590,15 @@ class Diaspora return false; } - if (!($postdata = self::validPosting($msg))) { + if (!($fields = self::validPosting($msg))) { logger("Invalid posting"); return false; } - $fields = $postdata['fields']; + $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; + $success = self::dispatch($importer, $msg, $fields); - // Is it a an action (comment, like, ...) for our own post? - if (isset($fields->parent_guid) && !$postdata["relayed"]) { - $guid = notags(unxmlify($fields->parent_guid)); - $importer = self::importerForGuid($guid); - if (is_array($importer)) { - logger("delivering to origin: ".$importer["name"]); - $message_id = self::dispatch($importer, $msg, $fields); - return $message_id; - } - } - - // Process item retractions. This has to be done separated from the other stuff, - // since retractions for comments could come even from non followers. - if (!empty($fields) && in_array($fields->getName(), ['retraction'])) { - $target = notags(unxmlify($fields->target_type)); - if (in_array($target, ["Comment", "Like", "Post", "Reshare", "StatusMessage"])) { - logger('processing retraction for '.$target, LOGGER_DEBUG); - $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; - $message_id = self::dispatch($importer, $msg, $fields); - return $message_id; - } - } - - // Now distribute it to the followers - $r = q( - "SELECT `user`.* FROM `user` WHERE `user`.`uid` IN - (SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s') - AND NOT `account_expired` AND NOT `account_removed`", - dbesc(NETWORK_DIASPORA), - dbesc($msg["author"]) - ); - - if (DBM::is_result($r)) { - foreach ($r as $rr) { - logger("delivering to: ".$rr["username"]); - self::dispatch($rr, $msg, $fields); - } - } elseif (!Config::get('system', 'relay_subscribe', false)) { - logger("Unwanted message from ".$msg["author"]." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG); - } else { - // Use a dummy importer to import the data for the public copy - $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; - $message_id = self::dispatch($importer, $msg, $fields); - } - - return $message_id; + return $success; } /** @@ -662,11 +618,13 @@ class Diaspora // This is only needed for private postings since this is already done for public ones before if (is_null($fields)) { - if (!($postdata = self::validPosting($msg))) { + $private = true; + if (!($fields = self::validPosting($msg))) { logger("Invalid posting"); return false; } - $fields = $postdata['fields']; + } else { + $private = false; } $type = $fields->getName(); @@ -675,27 +633,47 @@ class Diaspora switch ($type) { case "account_migration": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveAccountMigration($importer, $fields); case "account_deletion": - return self::receiveAccountDeletion($importer, $fields); + return self::receiveAccountDeletion($fields); case "comment": return self::receiveComment($importer, $sender, $fields, $msg["message"]); case "contact": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveContactRequest($importer, $fields); case "conversation": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveConversation($importer, $msg, $fields); case "like": return self::receiveLike($importer, $sender, $fields); case "message": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveMessage($importer, $fields); case "participation": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveParticipation($importer, $fields); case "photo": // Not implemented @@ -705,6 +683,10 @@ class Diaspora return self::receivePollParticipation($importer, $fields); case "profile": + if (!$private) { + logger('Message with type ' . $type . ' is not private, quitting.'); + return false; + } return self::receiveProfile($importer, $fields); case "reshare": @@ -840,7 +822,7 @@ class Diaspora // Only some message types have signatures. So we quit here for the other types. if (!in_array($type, ["comment", "like"])) { - return ["fields" => $fields, "relayed" => false]; + return $fields; } // No author_signature? This is a must, so we quit. if (!isset($author_signature)) { @@ -849,25 +831,29 @@ class Diaspora } if (isset($parent_author_signature)) { - $relayed = true; - $key = self::key($msg["author"]); + if (empty($key)) { + logger("No key found for parent author ".$msg["author"], LOGGER_DEBUG); + return false; + } if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) { logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG); return false; } - } else { - $relayed = false; } $key = self::key($fields->author); + if (empty($key)) { + logger("No key found for author ".$fields->author, LOGGER_DEBUG); + return false; + } if (!Crypto::rsaVerify($signed_data, $author_signature, $key, "sha256")) { logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG); return false; } else { - return ["fields" => $fields, "relayed" => $relayed]; + return $fields; } } @@ -1650,25 +1636,23 @@ class Diaspora /** * @brief Processes an account deletion * - * @param array $importer Array of the importer user * @param object $data The message object * * @return bool Success */ - private static function receiveAccountDeletion($importer, $data) + private static function receiveAccountDeletion($data) { - /// @todo Account deletion should remove the contact from the global contacts as well - $author = notags(unxmlify($data->author)); - $contact = self::contactByHandle($importer["uid"], $author); - if (!$contact) { - logger("cannot find contact for author: ".$author); - return false; + $contacts = dba::select('contact', ['id'], ['addr' => $author]); + while ($contact = dba::fetch($contacts)) { + Contact::remove($contact["id"]); } - // We now remove the contact - Contact::remove($contact["id"]); + dba::delete('gcontact', ['addr' => $author]); + + logger('Removed contacts for ' . $author); + return true; } @@ -1836,6 +1820,9 @@ class Diaspora if ($message_id) { logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } } // If we are the origin of the parent we store the original data and notify our followers @@ -2157,6 +2144,9 @@ class Diaspora if ($message_id) { logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } } // like on comments have the comment as parent. So we need to fetch the toplevel parent @@ -2739,10 +2729,15 @@ class Diaspora */ public static function originalItem($guid, $orig_author) { + if (empty($guid)) { + logger('Empty guid. Quitting.'); + return false; + } + // Do we already have this item? $fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar']; - $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false]; + $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false]; $item = dba::selectfirst('item', $fields, $condition); if (DBM::is_result($item)) { @@ -2752,7 +2747,7 @@ class Diaspora // Then refetch the content, if it is a reshare from a reshare. // If it is a reshared post from another network then reformat to avoid display problems with two share elements if (self::isReshare($item["body"], true)) { - $r = []; + $item = []; } elseif (self::isReshare($item["body"], false) || strstr($item["body"], "[share")) { $item["body"] = Markdown::toBBCode(BBCode::toMarkdown($item["body"])); @@ -2767,21 +2762,26 @@ class Diaspora } } - if (!DBM::is_result($r)) { - $server = "https://".substr($orig_author, strpos($orig_author, "@") + 1); - logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server); - $item_id = self::storeByGuid($guid, $server); - - if (!$item_id) { - $server = "http://".substr($orig_author, strpos($orig_author, "@") + 1); - logger("2nd try: reshared message ".$guid." will be fetched without SLL from the server ".$server); - $item_id = self::storeByGuid($guid, $server); + if (!DBM::is_result($item)) { + if (empty($orig_author)) { + logger('Empty author for guid ' . $guid . '. Quitting.'); + return false; } - if ($item_id) { + $server = "https://".substr($orig_author, strpos($orig_author, "@") + 1); + logger("1st try: reshared message ".$guid." will be fetched via SSL from the server ".$server); + $stored = self::storeByGuid($guid, $server); + + if (!$stored) { + $server = "http://".substr($orig_author, strpos($orig_author, "@") + 1); + logger("2nd try: reshared message ".$guid." will be fetched without SSL from the server ".$server); + $stored = self::storeByGuid($guid, $server); + } + + if ($stored) { $fields = ['body', 'tag', 'app', 'created', 'object-type', 'uri', 'guid', 'author-name', 'author-link', 'author-avatar']; - $condition = ['id' => $item_id, 'visible' => true, 'deleted' => false]; + $condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false]; $item = dba::selectfirst('item', $fields, $condition); if (DBM::is_result($item)) { @@ -2883,6 +2883,9 @@ class Diaspora if ($message_id) { logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } return true; } else { return false; @@ -3107,6 +3110,9 @@ class Diaspora if ($message_id) { logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } return true; } else { return false; diff --git a/src/Util/Network.php b/src/Util/Network.php index 4a11f92595..c1ea6e3547 100644 --- a/src/Util/Network.php +++ b/src/Util/Network.php @@ -36,7 +36,30 @@ class Network */ public static function fetchUrl($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = 0) { - $ret = self::curl( + $ret = self::fetchUrlFull($url, $binary, $redirects, $timeout, $accept_content, $cookiejar); + + return $ret['body']; + } + + /** + * @brief Curl wrapper with array of return values. + * + * Inner workings and parameters are the same as @ref fetchUrl but returns an array with + * all the information collected during the fetch. + * + * @param string $url URL to fetch + * @param boolean $binary default false + * TRUE if asked to return binary results (file download) + * @param integer $redirects The recursion counter for internal use - default 0 + * @param integer $timeout Timeout in seconds, default system config value or 60 seconds + * @param string $accept_content supply Accept: header with 'accept_content' as the value + * @param string $cookiejar Path to cookie jar file + * + * @return array With all relevant information, 'body' contains the actual fetched content. + */ + public static function fetchUrlFull($url, $binary = false, &$redirects = 0, $timeout = 0, $accept_content = null, $cookiejar = 0) + { + return self::curl( $url, $binary, $redirects, @@ -45,8 +68,6 @@ class Network 'cookiejar'=>$cookiejar ] ); - - return($ret['body']); } /** diff --git a/src/Util/Temporal.php b/src/Util/Temporal.php index 1ed08ed1df..46bd8bba50 100644 --- a/src/Util/Temporal.php +++ b/src/Util/Temporal.php @@ -59,7 +59,7 @@ class Temporal $o = ' + {{if $field.3}} {{$field.3}} + {{/if}} diff --git a/view/templates/field_combobox.tpl b/view/templates/field_combobox.tpl index 4586550166..876e607cdf 100644 --- a/view/templates/field_combobox.tpl +++ b/view/templates/field_combobox.tpl @@ -13,6 +13,8 @@ {{foreach $field.4 as $opt=>$val}}{{/foreach}} - {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}} diff --git a/view/templates/field_custom.tpl b/view/templates/field_custom.tpl index 0b09284023..6649b0ff94 100644 --- a/view/templates/field_custom.tpl +++ b/view/templates/field_custom.tpl @@ -3,5 +3,7 @@
{{$field.2}} - {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/templates/field_input.tpl b/view/templates/field_input.tpl index 495493f2fd..850656bb8c 100644 --- a/view/templates/field_input.tpl +++ b/view/templates/field_input.tpl @@ -2,5 +2,7 @@
+ {{if $field.3}} {{$field.3}} + {{/if}}
diff --git a/view/templates/field_intcheckbox.tpl b/view/templates/field_intcheckbox.tpl index 73bdf60417..9c5f04e796 100644 --- a/view/templates/field_intcheckbox.tpl +++ b/view/templates/field_intcheckbox.tpl @@ -3,5 +3,7 @@
+ {{if $field.4}} {{$field.4}} + {{/if}}
diff --git a/view/templates/field_openid.tpl b/view/templates/field_openid.tpl index 062ac6ac6e..9a18bbc13c 100644 --- a/view/templates/field_openid.tpl +++ b/view/templates/field_openid.tpl @@ -2,5 +2,7 @@
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/templates/field_password.tpl b/view/templates/field_password.tpl index 333ce67c38..4b4d4f2b2e 100644 --- a/view/templates/field_password.tpl +++ b/view/templates/field_password.tpl @@ -2,5 +2,7 @@
+ {{if $field.3}} {{$field.3}} + {{/if}}
diff --git a/view/templates/field_radio.tpl b/view/templates/field_radio.tpl index 6b880ed997..1e1d8e0b10 100644 --- a/view/templates/field_radio.tpl +++ b/view/templates/field_radio.tpl @@ -1,5 +1,7 @@
+ {{if $field.3}} {{$field.3}} + {{/if}}
diff --git a/view/templates/field_richtext.tpl b/view/templates/field_richtext.tpl index 67553bb95a..bc346ddb0b 100644 --- a/view/templates/field_richtext.tpl +++ b/view/templates/field_richtext.tpl @@ -3,5 +3,7 @@
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/templates/field_select.tpl b/view/templates/field_select.tpl index 2d037439df..87a2ab9ff8 100644 --- a/view/templates/field_select.tpl +++ b/view/templates/field_select.tpl @@ -5,5 +5,7 @@ - {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}} diff --git a/view/templates/field_select_raw.tpl b/view/templates/field_select_raw.tpl index 4c826a0427..147c028eff 100644 --- a/view/templates/field_select_raw.tpl +++ b/view/templates/field_select_raw.tpl @@ -5,5 +5,7 @@ - {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}} diff --git a/view/templates/field_textarea.tpl b/view/templates/field_textarea.tpl index c37537d6ec..60594a2666 100644 --- a/view/templates/field_textarea.tpl +++ b/view/templates/field_textarea.tpl @@ -3,5 +3,7 @@
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/templates/field_themeselect.tpl b/view/templates/field_themeselect.tpl index 51f6057ae3..5f56c187ef 100644 --- a/view/templates/field_themeselect.tpl +++ b/view/templates/field_themeselect.tpl @@ -5,6 +5,8 @@ - {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}} {{if $field.5}}
{{/if}} diff --git a/view/templates/field_yesno.tpl b/view/templates/field_yesno.tpl index 155d0488b3..7e7c3cc4ee 100644 --- a/view/templates/field_yesno.tpl +++ b/view/templates/field_yesno.tpl @@ -10,5 +10,7 @@ {{if $field.4}}{{$field.4.1}}{{else}}ON{{/if}} - {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}} diff --git a/view/templates/htconfig.tpl b/view/templates/htconfig.tpl index d72307fb5a..1325a61771 100644 --- a/view/templates/htconfig.tpl +++ b/view/templates/htconfig.tpl @@ -107,7 +107,7 @@ $a->config['system']['no_regfullname'] = true; //$a->config['system']['block_local_dir'] = false; // Location of the global directory -$a->config['system']['directory'] = 'http://dir.friendica.social'; +$a->config['system']['directory'] = 'https://dir.friendica.social'; // Authentication cookie lifetime, in days $a->config['system']['auth_cookie_lifetime'] = 7; diff --git a/view/templates/install_checks.tpl b/view/templates/install_checks.tpl index 10a197482b..f960729111 100644 --- a/view/templates/install_checks.tpl +++ b/view/templates/install_checks.tpl @@ -16,7 +16,13 @@ {{/if}} {{if $check.help}} - + {{/if}} {{/foreach}}
' . L10n::t('Blocked domain') . '' . L10n::t('Reason for the block') . '
{{if $check.required}}(required){{/if}}
{{$check.help}}
+
{{$check.help}}
+ {{if $check.error_msg}} +
{{$check.error_msg.head}}
{{$check.error_msg.url}}
+
{{$check.error_msg.msg}}
+ {{/if}} +
diff --git a/view/templates/invite.tpl b/view/templates/invite.tpl index 6fd8539c5a..2087635e4f 100644 --- a/view/templates/invite.tpl +++ b/view/templates/invite.tpl @@ -1,31 +1,18 @@
- + -
+
-

{{$invite}}

+

{{$title}}

-
-{{$addr_text}} -
+ {{include file="field_textarea.tpl" field=$recipients}} + {{include file="field_textarea.tpl" field=$message}} -
- -
+
+ +
-
-{{$msg_text}} -
- -
- -
- -
- -
- -
+
diff --git a/view/templates/login.tpl b/view/templates/login.tpl index e1e8c5f3a6..029ebb0343 100644 --- a/view/templates/login.tpl +++ b/view/templates/login.tpl @@ -4,11 +4,14 @@
-
{{$login}}
+

{{$login}}

{{include file="field_input.tpl" field=$lname}} {{include file="field_password.tpl" field=$lpassword}} +
{{if $openid}} @@ -17,16 +20,11 @@
{{/if}} - {{include file="field_checkbox.tpl" field=$lremember}} - - -
+ + {{include file="field_checkbox.tpl" field=$lremember}} {{foreach $hiddens as $k=>$v}} @@ -35,5 +33,11 @@
+{{if $register}} + +{{/if}} diff --git a/view/templates/paginate.tpl b/view/templates/paginate.tpl index fcd580b071..ee9a1cc330 100644 --- a/view/templates/paginate.tpl +++ b/view/templates/paginate.tpl @@ -1,5 +1,5 @@ +{{if $pager && ($pager.prev || $pager.next)}}
- {{if $pager}} {{if $pager.prev}}{{$pager.prev.text}}{{/if}} {{if $pager.first}}{{$pager.first.text}}{{/if}} @@ -9,5 +9,5 @@ {{if $pager.last}} {{$pager.last.text}}{{/if}} {{if $pager.next}}{{$pager.next.text}}{{/if}} - {{/if}}
+{{/if}} diff --git a/view/templates/peoplefind.tpl b/view/templates/peoplefind.tpl index 481bdd71e0..67f7a8086b 100644 --- a/view/templates/peoplefind.tpl +++ b/view/templates/peoplefind.tpl @@ -1,16 +1,17 @@
-

{{$findpeople}}

-
{{$desc}}
+

{{$nv.findpeople}}

+
{{$nv.desc}}
- +
- - - - - {{if $inv}} - + + + + + + {{if $nv.inv}} + {{/if}}
diff --git a/view/templates/wall/content_filter.tpl b/view/templates/wall/content_filter.tpl new file mode 100644 index 0000000000..1e2b99c226 --- /dev/null +++ b/view/templates/wall/content_filter.tpl @@ -0,0 +1,22 @@ +{{if count($reasons) > 1}} + +

+ +

+{{else}} +

+ {{$reasons.0|escape:html}} + +

+{{/if}} + diff --git a/view/theme/frio/README.md b/view/theme/frio/README.md index 037028ff44..c729d12820 100644 --- a/view/theme/frio/README.md +++ b/view/theme/frio/README.md @@ -37,11 +37,11 @@ Don't blame me too much for ugly code and hacks. Fix it ;-) **Theme - Settings** ![Theme - Settings](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-settings.png) -**Red schema** -![Red schema](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-schema-red.png) +**Red scheme** +![Red scheme](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-scheme-red.png) -**Love Music schema** -![Love Music schema](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-schema-love-music.png) +**Love Music scheme** +![Love Music scheme](https://github.com/rabuzarus/frio/blob/master/img/screenshots/screenshot-scheme-love-music.png) **frio on mobile** diff --git a/view/theme/frio/config.php b/view/theme/frio/config.php index 9081d9df47..55a653696a 100644 --- a/view/theme/frio/config.php +++ b/view/theme/frio/config.php @@ -8,128 +8,134 @@ use Friendica\Core\System; require_once 'view/theme/frio/php/Image.php'; -function theme_post(App $a) { +function theme_post(App $a) +{ if (!local_user()) { return; } if (isset($_POST['frio-settings-submit'])) { - PConfig::set(local_user(), 'frio', 'schema', $_POST["frio_schema"]); - PConfig::set(local_user(), 'frio', 'nav_bg', $_POST["frio_nav_bg"]); - PConfig::set(local_user(), 'frio', 'nav_icon_color', $_POST["frio_nav_icon_color"]); - PConfig::set(local_user(), 'frio', 'link_color', $_POST["frio_link_color"]); - PConfig::set(local_user(), 'frio', 'background_color', $_POST["frio_background_color"]); - PConfig::set(local_user(), 'frio', 'contentbg_transp', $_POST["frio_contentbg_transp"]); - PConfig::set(local_user(), 'frio', 'background_image', $_POST["frio_background_image"]); - PConfig::set(local_user(), 'frio', 'bg_image_option', $_POST["frio_bg_image_option"]); + PConfig::set(local_user(), 'frio', 'scheme', $_POST['frio_scheme']); + PConfig::set(local_user(), 'frio', 'nav_bg', $_POST['frio_nav_bg']); + PConfig::set(local_user(), 'frio', 'nav_icon_color', $_POST['frio_nav_icon_color']); + PConfig::set(local_user(), 'frio', 'link_color', $_POST['frio_link_color']); + PConfig::set(local_user(), 'frio', 'background_color', $_POST['frio_background_color']); + PConfig::set(local_user(), 'frio', 'contentbg_transp', $_POST['frio_contentbg_transp']); + PConfig::set(local_user(), 'frio', 'background_image', $_POST['frio_background_image']); + PConfig::set(local_user(), 'frio', 'bg_image_option', $_POST['frio_bg_image_option']); PConfig::set(local_user(), 'frio', 'css_modified', time()); } } -function theme_admin_post(App $a) { +function theme_admin_post(App $a) +{ if (!local_user()) { return; } if (isset($_POST['frio-settings-submit'])) { - Config::set('frio', 'schema', $_POST["frio_schema"]); - Config::set('frio', 'nav_bg', $_POST["frio_nav_bg"]); - Config::set('frio', 'nav_icon_color', $_POST["frio_nav_icon_color"]); - Config::set('frio', 'link_color', $_POST["frio_link_color"]); - Config::set('frio', 'background_color', $_POST["frio_background_color"]); - Config::set('frio', 'contentbg_transp', $_POST["frio_contentbg_transp"]); - Config::set('frio', 'background_image', $_POST["frio_background_image"]); - Config::set('frio', 'bg_image_option', $_POST["frio_bg_image_option"]); - Config::set('frio', 'login_bg_image', $_POST["frio_login_bg_image"]); - Config::set('frio', 'login_bg_color', $_POST["frio_login_bg_color"]); + Config::set('frio', 'scheme', $_POST['frio_scheme']); + Config::set('frio', 'nav_bg', $_POST['frio_nav_bg']); + Config::set('frio', 'nav_icon_color', $_POST['frio_nav_icon_color']); + Config::set('frio', 'link_color', $_POST['frio_link_color']); + Config::set('frio', 'background_color', $_POST['frio_background_color']); + Config::set('frio', 'contentbg_transp', $_POST['frio_contentbg_transp']); + Config::set('frio', 'background_image', $_POST['frio_background_image']); + Config::set('frio', 'bg_image_option', $_POST['frio_bg_image_option']); + Config::set('frio', 'login_bg_image', $_POST['frio_login_bg_image']); + Config::set('frio', 'login_bg_color', $_POST['frio_login_bg_color']); Config::set('frio', 'css_modified', time()); } } -function theme_content(App $a) { +function theme_content(App $a) +{ if (!local_user()) { return; } $arr = []; - $arr["schema"] = PConfig::get(local_user(), 'frio', 'schema'); - $arr["nav_bg"] = PConfig::get(local_user(), 'frio', 'nav_bg'); - $arr["nav_icon_color"] = PConfig::get(local_user(), 'frio', 'nav_icon_color'); - $arr["link_color"] = PConfig::get(local_user(), 'frio', 'link_color'); - $arr["bgcolor"] = PConfig::get(local_user(), 'frio', 'background_color'); - $arr["contentbg_transp"] = PConfig::get(local_user(), 'frio', 'contentbg_transp'); - $arr["background_image"] = PConfig::get(local_user(), 'frio', 'background_image'); - $arr["bg_image_option"] = PConfig::get(local_user(), 'frio', 'bg_image_option'); + $arr['scheme'] = PConfig::get(local_user(), 'frio', 'scheme', PConfig::get(local_user(), 'frio', 'schema')); + $arr['nav_bg'] = PConfig::get(local_user(), 'frio', 'nav_bg'); + $arr['nav_icon_color'] = PConfig::get(local_user(), 'frio', 'nav_icon_color'); + $arr['link_color'] = PConfig::get(local_user(), 'frio', 'link_color'); + $arr['background_color'] = PConfig::get(local_user(), 'frio', 'background_color'); + $arr['contentbg_transp'] = PConfig::get(local_user(), 'frio', 'contentbg_transp'); + $arr['background_image'] = PConfig::get(local_user(), 'frio', 'background_image'); + $arr['bg_image_option'] = PConfig::get(local_user(), 'frio', 'bg_image_option'); return frio_form($arr); } -function theme_admin(App $a) { +function theme_admin(App $a) +{ if (!local_user()) { return; } $arr = []; - $arr["schema"] = Config::get('frio', 'schema'); - $arr["nav_bg"] = Config::get('frio', 'nav_bg'); - $arr["nav_icon_color"] = Config::get('frio', 'nav_icon_color'); - $arr["link_color"] = Config::get('frio', 'link_color'); - $arr["bgcolor"] = Config::get('frio', 'background_color'); - $arr["contentbg_transp"] = Config::get('frio', 'contentbg_transp'); - $arr["background_image"] = Config::get('frio', 'background_image'); - $arr["bg_image_option"] = Config::get('frio', 'bg_image_option'); - $arr["login_bg_image"] = Config::get('frio', 'login_bg_image'); - $arr["login_bg_color"] = Config::get('frio', 'login_bg_color'); + $arr['scheme'] = Config::get('frio', 'scheme', Config::get('frio', 'scheme')); + $arr['nav_bg'] = Config::get('frio', 'nav_bg'); + $arr['nav_icon_color'] = Config::get('frio', 'nav_icon_color'); + $arr['link_color'] = Config::get('frio', 'link_color'); + $arr['background_color'] = Config::get('frio', 'background_color'); + $arr['contentbg_transp'] = Config::get('frio', 'contentbg_transp'); + $arr['background_image'] = Config::get('frio', 'background_image'); + $arr['bg_image_option'] = Config::get('frio', 'bg_image_option'); + $arr['login_bg_image'] = Config::get('frio', 'login_bg_image'); + $arr['login_bg_color'] = Config::get('frio', 'login_bg_color'); return frio_form($arr); } -function frio_form($arr) { - require_once("view/theme/frio/php/schema.php"); +function frio_form($arr) +{ + require_once 'view/theme/frio/php/scheme.php'; - $scheme_info = get_schema_info($arr["schema"]); - $disable = $scheme_info["overwrites"]; + $scheme_info = get_scheme_info($arr['scheme']); + $disable = $scheme_info['overwrites']; if (!is_array($disable)) { $disable = []; } $scheme_choices = []; - $scheme_choices["---"] = L10n::t("Default"); - $files = glob('view/theme/frio/schema/*.php'); + $scheme_choices['---'] = L10n::t('Custom'); + $files = glob('view/theme/frio/scheme/*.php'); if ($files) { foreach ($files as $file) { - $f = basename($file, ".php"); + $f = basename($file, '.php'); if ($f != 'default') { - $scheme_name = $f; + $scheme_name = ucfirst($f); $scheme_choices[$f] = $scheme_name; } } } - $background_image_help = "" . L10n::t("Note"). ": ".L10n::t("Check image permissions if all users are allowed to visit the image"); + $background_image_help = '' . L10n::t('Note') . ': ' . L10n::t('Check image permissions if all users are allowed to see the image'); $t = get_markup_template('theme_settings.tpl'); $ctx = [ '$submit' => L10n::t('Submit'), '$baseurl' => System::baseUrl(), - '$title' => L10n::t("Theme settings"), - '$schema' => ['frio_schema', L10n::t("Select scheme"), $arr["schema"], '', $scheme_choices], - '$nav_bg' => array_key_exists("nav_bg", $disable) ? "" : ['frio_nav_bg', L10n::t('Navigation bar background color'), $arr['nav_bg'], '', false], - '$nav_icon_color' => array_key_exists("nav_icon_color", $disable) ? "" : ['frio_nav_icon_color', L10n::t('Navigation bar icon color '), $arr['nav_icon_color'], '', false], - '$link_color' => array_key_exists("link_color", $disable) ? "" : ['frio_link_color', L10n::t('Link color'), $arr['link_color'], '', false], - '$bgcolor' => array_key_exists("bgcolor", $disable) ? "" : ['frio_background_color', L10n::t('Set the background color'), $arr['bgcolor'], '', false], - '$contentbg_transp' => array_key_exists("contentbg_transp", $disable) ? "" : ['frio_contentbg_transp', L10n::t("Content background opacity"), ((isset($arr["contentbg_transp"]) && $arr["contentbg_transp"] != "") ? $arr["contentbg_transp"] : 100), ''], - '$background_image' => array_key_exists("background_image", $disable) ? "" : ['frio_background_image', L10n::t('Set the background image'), $arr['background_image'], $background_image_help, false], + '$title' => L10n::t('Theme settings'), + '$scheme' => ['frio_scheme', L10n::t('Select color scheme'), $arr['scheme'], '', $scheme_choices], + '$nav_bg' => array_key_exists('nav_bg', $disable) ? '' : ['frio_nav_bg', L10n::t('Navigation bar background color'), $arr['nav_bg'], '', false], + '$nav_icon_color' => array_key_exists('nav_icon_color', $disable) ? '' : ['frio_nav_icon_color', L10n::t('Navigation bar icon color '), $arr['nav_icon_color'], '', false], + '$link_color' => array_key_exists('link_color', $disable) ? '' : ['frio_link_color', L10n::t('Link color'), $arr['link_color'], '', false], + '$background_color' => array_key_exists('background_color', $disable) ? '' : ['frio_background_color', L10n::t('Set the background color'), $arr['background_color'], '', false], + '$contentbg_transp' => array_key_exists('contentbg_transp', $disable) ? '' : ['frio_contentbg_transp', L10n::t('Content background opacity'), defaults($arr, 'contentbg_transp', 100), ''], + '$background_image' => array_key_exists('background_image', $disable) ? '' : ['frio_background_image', L10n::t('Set the background image'), $arr['background_image'], $background_image_help, false], + '$bg_image_options_title' => L10n::t('Background image style'), '$bg_image_options' => Image::get_options($arr), ]; - if (array_key_exists("login_bg_image", $arr) && !array_key_exists("login_bg_image", $disable)) { - $ctx['$login_bg_image'] = ['frio_login_bg_image', L10n::t('Login page background image'), $arr['login_bg_image'], $background_image_help, false]; - } - if (array_key_exists("login_bg_color", $arr) && !array_key_exists("login_bg_color", $disable)) { - $ctx['$login_bg_color'] = ['frio_login_bg_color', L10n::t('Login page background color'), $arr['login_bg_color'], L10n::t('Leave background image and color empty for theme defaults'), false]; + if (array_key_exists('login_bg_image', $arr) && !array_key_exists('login_bg_image', $disable)) { + $ctx['$login_bg_image'] = ['frio_login_bg_image', L10n::t('Login page background image'), $arr['login_bg_image'], $background_image_help, false]; } + if (array_key_exists('login_bg_color', $arr) && !array_key_exists('login_bg_color', $disable)) { + $ctx['$login_bg_color'] = ['frio_login_bg_color', L10n::t('Login page background color'), $arr['login_bg_color'], L10n::t('Leave background image and color empty for theme defaults'), false]; + } $o = replace_macros($t, $ctx); diff --git a/view/theme/frio/css/mod_admin.css b/view/theme/frio/css/mod_admin.css index cbcd53453b..b690577d11 100644 --- a/view/theme/frio/css/mod_admin.css +++ b/view/theme/frio/css/mod_admin.css @@ -1,17 +1,20 @@ -#admin-users.adminpage { padding-left:0; padding-right: 0;} #admin-users.adminpage > h1 { padding: 0 15px; } - -#admin-users td { word-break: break-all; } +#admin-users.adminpage .panel-collapse { margin-left: -15px; margin-right: -15px; } #admin-users #users th:first-of-type { width: 1em; } #admin-users #users th:nth-of-type(2) { width: 40px; } #admin-users #users th:last-of-type { width: 1em; } +#admin-users .admin-settings-footer-elements { padding-left: 8px; padding-right: 8px; } #admin-users #deleted th:first-of-type { width: 40px; } #admin-users #users img.avatar-nano, #deleted img.avatar-nano { height: 24px; width: 24px; } .opened .caret { transform: rotate(180deg); } tr.details td, -tr.details th -{ border-top: 0!important; } +tr.details th { + border-top: 0!important; +} + +.adminpage td > .checkbox { margin: 0; } +.adminpage td { word-break: break-all; } \ No newline at end of file diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index 6f2a71ca44..18b2f42088 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -24,9 +24,10 @@ and open the template in the editor. body { padding-top: 110px; - background-color: $bgcolor; + background-color: $background_color; background-image: url("$background_image"); background-size: $background_size_img; + background-repeat: $background_repeat; background-attachment: fixed; color: #777; /*color: #555;*/ @@ -2115,9 +2116,10 @@ ul.dropdown-menu li:hover { .allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper, .directory-content-wrapper, .manage-content-wrapper, .notes-content-wrapper, .message-content-wrapper, .apps-content-wrapper, .photos-content-wrapper, -#adminpage, .viewcontacts-content-wrapper, .dfrn_request-content-wrapper, +#adminpage, .delegate-content-wrapper, .uexport-content-wrapper, +.viewcontacts-content-wrapper, .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper, -.profperm-content-wrapper { +.profperm-content-wrapper, .invite-content-wrapper { min-height: calc(100vh - 150px); padding: 15px; padding-bottom: 20px; @@ -2409,10 +2411,13 @@ ul li:hover .contact-wrapper .contact-action-link:hover { height: 48px; width: 48px; } - #prvmail-end { clear:both; } +#modal #prvmail-text-edit-bb .bb-img { + display: none; +} + /* photos */ .photo-album-actions { margin-bottom: 10px; @@ -2650,7 +2655,8 @@ ul li:hover .contact-wrapper .contact-action-link:hover { margin-left: -15px; margin-right: -15px; } -.panel-group-settings > .panel { +.panel-group-settings > .panel, +.panel-group-settings > form > .panel { padding-left: 15px; padding-right: 15px; } @@ -2935,6 +2941,22 @@ section.help-content-wrapper li { #adminpage .plugin .desc { padding-left: 10px; } +.adminpage .admin-settings-action-link, +.adminpage .admin-settings-action-link:hover { + color: #555; +} +.adminpage .admin-settings-action-link:hover { + opacity: 1; +} +.adminpage .admin-settings-action-link { + opacity: 0.8; +} +#admin-users tr.blocked { + background-color: #f8efc0; +} +.adminpage .table-hover > tbody > tr:hover + tr.details { + background-color: #f5f5f5; +} /* Register Page*/ #register-openid-wrapper, #register-name-wrapper, #register-invite-wrapper, #profile-publish-wrapper { @@ -3115,12 +3137,30 @@ section .profile-match-wrapper { * Login page */ #login-submit-wrapper { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; + float: right; } #lost-password-link { flex-grow: 2; } +#login-lost-password-link { + margin-bottom: 10px; + float: right; +} +#div_id_remember { + float: left; +} +#id_password_wrapper { + margin-bottom: unset; +} +#login_openid { + clear: both; +} +#register-link { + color: white; + background: #8ad0a1; + width: 100%; +} +#login-end { + clear: both; +} .mod-home.is-not-singleuser, .mod-login { @@ -3145,12 +3185,15 @@ section .profile-match-wrapper { margin-top: 2.5%; } +.mod-home.is-not-singleuser .login-form > #login-extra-links { + margin-top: 4em; +} + .mod-home.is-not-singleuser .login-form > #login-form label, .mod-login #content #login-form label { color: #eee; } - .mod-home.is-not-singleuser .login-panel-content, .mod-login .login-panel-content { background-color: rgba(255,255,255,.85); @@ -3164,11 +3207,15 @@ section .profile-match-wrapper { } .mod-home.is-not-singleuser .login-form > #login-form, + .mod-home.is-not-singleuser .login-form > #login-extra-links, .mod-login #content #login-form { background-color: #fff; padding: 1em; position: relative; - margin-top: 4em; + } + .mod-home.is-not-singleuser .login-form > #login-extra-links { + margin-top: unset; + background-color: white; } .mod-home.is-not-singleuser .login-form > #login-form label, @@ -3176,7 +3223,7 @@ section .profile-match-wrapper { color: #444; } - .mod-home.is-not-singleuser .login-form > #login-form::before, + .mod-home.is-not-singleuser .login-form::before, .mod-login #content #login-form::before { display: block; position: absolute; @@ -3189,7 +3236,7 @@ section .profile-match-wrapper { z-index: -1; } - .mod-home.is-not-singleuser .login-form > #login-form::after, + .mod-home.is-not-singleuser .login-form::after, .mod-login #content #login-form::after { display: block; position: absolute; diff --git a/view/theme/frio/img/screenshots/screenshot-schema-love-music.png b/view/theme/frio/img/screenshots/screenshot-scheme-love-music.png similarity index 100% rename from view/theme/frio/img/screenshots/screenshot-schema-love-music.png rename to view/theme/frio/img/screenshots/screenshot-scheme-love-music.png diff --git a/view/theme/frio/img/screenshots/screenshot-schema-red.png b/view/theme/frio/img/screenshots/screenshot-scheme-red.png similarity index 100% rename from view/theme/frio/img/screenshots/screenshot-schema-red.png rename to view/theme/frio/img/screenshots/screenshot-scheme-red.png diff --git a/view/theme/frio/js/filebrowser.js b/view/theme/frio/js/filebrowser.js index 92f1412911..270172072d 100644 --- a/view/theme/frio/js/filebrowser.js +++ b/view/theme/frio/js/filebrowser.js @@ -231,7 +231,6 @@ var FileBrowser = { $(".fbrowser .fbswitcher [data-mode=" + FileBrowser.type + "]").addClass("active"); // We need to add the AjaxUpload to the button FileBrowser.uploadButtons(); - }, // Load new content (e.g. change photo album) diff --git a/view/theme/frio/js/mod_admin.js b/view/theme/frio/js/mod_admin.js index dc8abe054b..188b480986 100644 --- a/view/theme/frio/js/mod_admin.js +++ b/view/theme/frio/js/mod_admin.js @@ -9,7 +9,9 @@ $(function() { selectnone($(this).data('selectNone')); }); - $('body').on('change', 'input[type=checkbox].select', function() { + // Toggle checkbox status to all or none for all checkboxes of a specific + // css class. + $('body').on('change', 'input[type=checkbox].selecttoggle', function() { $this = $(this); if ($this.prop('checked')) { selectall($this.data('selectClass')); @@ -20,6 +22,26 @@ $(function() { } }); + // Use AJAX calls to reorder the table (so we don't need to reload the page). + $('body').on('click', '.table-order', function(e) { + e.preventDefault(); + + // Get the parent table element. + var table = $(this).parents('table'); + var orderUrl = this.getAttribute("data-order-url"); + table.fadeTo("fast", 0.33); + + $("body").css("cursor", "wait"); + + $.get(orderUrl, function(data) { + // Find the table element in the html we got. + var result = $(data).find('#' + table[0].id); + // And add the new table html to the parent. + $(table).parent().html(result); + + $("body").css("cursor", "auto"); + }); + }); function selectall(cls) { $('.' + cls).prop('checked', true); @@ -39,7 +61,7 @@ function confirm_delete(msg, uname){ } function details(uid) { - $("#user-"+uid+"-detail").toggleClass("hidden"); - $("#user-"+uid).toggleClass("opened"); + $("#user-" + uid + "-detail").toggleClass("hidden"); + $("#user-" + uid).toggleClass("opened"); return false; } diff --git a/view/theme/frio/js/modal.js b/view/theme/frio/js/modal.js index 2b60049f1d..46bb1e5143 100644 --- a/view/theme/frio/js/modal.js +++ b/view/theme/frio/js/modal.js @@ -152,6 +152,7 @@ Dialog._load = function(url) { var jsbrowser = function() { FileBrowser.init(nickname, type, hash); }; + loadScript("view/js/ajaxupload.js"); loadScript("view/theme/frio/js/filebrowser.js", jsbrowser); }; @@ -206,6 +207,10 @@ function addToModal(url) { //Get first element with the class "heading" //and use it as title. loadModalTitle(); + + // We need to initialize autosize again for new + // modal conent. + autosize($('.modal .text-autosize')); } }); } diff --git a/view/theme/frio/js/theme.js b/view/theme/frio/js/theme.js index a8787a6eb5..859df01613 100644 --- a/view/theme/frio/js/theme.js +++ b/view/theme/frio/js/theme.js @@ -446,8 +446,16 @@ function justifyPhotosAjax() { $('#photo-album-contents').justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; }); } +// Load a js script to the html head. function loadScript(url, callback) { - // Adding the script tag to the head as suggested before + // Check if the script is already in the html head. + var oscript = $('head script[src="' + url + '"]'); + + // Delete the old script from head. + if (oscript.length > 0) { + oscript.remove(); + } + // Adding the script tag to the head as suggested before. var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; @@ -458,7 +466,7 @@ function loadScript(url, callback) { script.onreadystatechange = callback; script.onload = callback; - // Fire the loading + // Fire the loading. head.appendChild(script); } diff --git a/view/theme/frio/php/Image.php b/view/theme/frio/php/Image.php index 2dc0345c7b..72026cf024 100644 --- a/view/theme/frio/php/Image.php +++ b/view/theme/frio/php/Image.php @@ -21,14 +21,10 @@ class Image public static function get_options($arr) { $bg_image_options = [ - 'repeat' => [ - 'frio_bg_image_option', L10n::t("Repeat the image"), "repeat", L10n::t("Will repeat your image to fill the background."), ($arr["bg_image_option"] == "repeat")], - 'stretch' => [ - 'frio_bg_image_option', L10n::t("Stretch"), "stretch", L10n::t("Will stretch to width/height of the image."), ($arr["bg_image_option"] == "stretch")], - 'cover' => [ - 'frio_bg_image_option', L10n::t("Resize fill and-clip"), "cover", L10n::t("Resize to fill and retain aspect ratio."), ($arr["bg_image_option"] == "cover")], - 'contain' => [ - 'frio_bg_image_option', L10n::t("Resize best fit"), "contain", L10n::t("Resize to best fit and retain aspect ratio."), ($arr["bg_image_option"] == "contain")], + 'stretch' => ['frio_bg_image_option', L10n::t('Top Banner'), 'stretch', L10n::t('Resize image to the width of the screen and show background color below on long pages.'), ($arr['bg_image_option'] == 'stretch')], + 'cover' => ['frio_bg_image_option', L10n::t('Full screen'), 'cover', L10n::t('Resize image to fill entire screen, clipping either the right or the bottom.'), ($arr['bg_image_option'] == 'cover')], + 'contain' => ['frio_bg_image_option', L10n::t('Single row mosaic'), 'contain', L10n::t('Resize image to repeat it on a single row, either vertical or horizontal.'), ($arr['bg_image_option'] == 'contain')], + 'repeat' => ['frio_bg_image_option', L10n::t('Mosaic'), 'repeat', L10n::t('Repeat image to fill the screen.'), ($arr['bg_image_option'] == 'repeat')], ]; return $bg_image_options; diff --git a/view/theme/frio/php/default.php b/view/theme/frio/php/default.php index c78fdd265c..428d887883 100644 --- a/view/theme/frio/php/default.php +++ b/view/theme/frio/php/default.php @@ -26,40 +26,43 @@ if (!isset($minimal)) { profile_uid; - if (is_null($uid)) { - $uid = Profile::getThemeUid(); - } - $schema = PConfig::get($uid, 'frio', 'schema'); - if (($schema) && ($schema != '---')) { - if (file_exists('view/theme/frio/schema/' . $schema . '.php')) { - $schemefile = 'view/theme/frio/schema/' . $schema . '.php'; - require_once $schemefile; - } - } else { - $nav_bg = PConfig::get($uid, 'frio', 'nav_bg'); - } - if (!$nav_bg) { - $nav_bg = "#708fa0"; - } - echo ' - '; + $basepath = $a->path ? "/" . $a->path . "/" : "/"; + $frio = "view/theme/frio"; - $is_singleuser = Config::get('system','singleuser'); - $is_singleuser_class = $is_singleuser ? "is-singleuser" : "is-not-singleuser"; + // Because we use minimal for modals the header and the included js stuff should be only loaded + // if the page is an standard page (so we don't have it twice for modals) + // + /// @todo Think about to move js stuff in the footer + if (!$minimal && x($page, 'htmlhead')) { + echo $page['htmlhead']; + } + + // Add the theme color meta + // It makes mobile Chrome UI match Frio's top bar color. + $uid = $a->profile_uid; + if (is_null($uid)) { + $uid = Profile::getThemeUid(); + } + $scheme = PConfig::get($uid, 'frio', 'scheme', PConfig::get($uid, 'frio', 'schema')); + if (($scheme) && ($scheme != '---')) { + if (file_exists('view/theme/frio/scheme/' . $scheme . '.php')) { + $schemefile = 'view/theme/frio/scheme/' . $scheme . '.php'; + require_once $schemefile; + } + } else { + $nav_bg = PConfig::get($uid, 'frio', 'nav_bg'); + } + if (!$nav_bg) { + $nav_bg = "#708fa0"; + } + echo ' + '; + + $is_singleuser = Config::get('system','singleuser'); + $is_singleuser_class = $is_singleuser ? "is-singleuser" : "is-not-singleuser"; ?> + "> Skip to main content
'; if (x($page, 'aside')) { @@ -107,18 +110,18 @@ if (!isset($minimal)) {
'; - if (x($page, 'content')) { - echo $page['content']; - } - echo ' -
+ echo $a->argv[0]; + echo '-content-wrapper">'; + if (x($page, 'content')) { + echo $page['content']; + } + echo ' +
'; - } else { - echo ' + } else { + echo '
'; if (x($page, 'content')) { echo $page['content']; @@ -126,7 +129,7 @@ if (!isset($minimal)) { echo '
'; - } + } ?>
diff --git a/view/theme/frio/php/schema.php b/view/theme/frio/php/schema.php deleted file mode 100644 index 83aad53b7e..0000000000 --- a/view/theme/frio/php/schema.php +++ /dev/null @@ -1,74 +0,0 @@ - Author Name - * 'description' => Schema description - * 'version' => Schema version - * 'overwrites' => Variables which overwriting custom settings - */ - -use Friendica\Core\PConfig; - -function get_schema_info($schema){ - - $theme = current_theme(); - $themepath = "view/theme/" . $theme . "/"; - $schema = PConfig::get(local_user(),'frio', 'schema'); - - $info=[ - 'name' => $schema, - 'description' => "", - 'author' => [], - 'version' => "", - 'overwrites' => [] - ]; - - if (!is_file($themepath . "schema/" . $schema . ".php")) return $info; - - $f = file_get_contents($themepath . "schema/" . $schema . ".php"); - - $r = preg_match("|/\*.*\*/|msU", $f, $m); - - if ($r){ - $ll = explode("\n", $m[0]); - foreach( $ll as $l ) { - $l = trim($l,"\t\n\r */"); - if ($l!=""){ - list($k,$v) = array_map("trim", explode(":",$l,2)); - $k= strtolower($k); - if ($k=="author"){ - $r=preg_match("|([^<]+)<([^>]+)>|", $v, $m); - if ($r) { - $info['author'][] = ['name'=>$m[1], 'link'=>$m[2]]; - } else { - $info['author'][] = ['name'=>$v]; - } - } elseif ($k == "overwrites") { - $theme_settings = explode(',',str_replace(' ','', $v)); - foreach ($theme_settings as $key => $value) { - $info["overwrites"][$value] = true; - } - } else { - if (array_key_exists($k,$info)){ - $info[$k]=$v; - } - } - - } - } - - } - return $info; -} diff --git a/view/theme/frio/php/scheme.php b/view/theme/frio/php/scheme.php new file mode 100644 index 0000000000..02de0a0359 --- /dev/null +++ b/view/theme/frio/php/scheme.php @@ -0,0 +1,71 @@ + Author Name + * 'description' => Scheme description + * 'version' => Scheme version + * 'overwrites' => Variables which overwriting custom settings + */ +use Friendica\Core\PConfig; + +function get_scheme_info($scheme) +{ + $theme = current_theme(); + $themepath = 'view/theme/' . $theme . '/'; + $scheme = PConfig::get(local_user(), 'frio', 'scheme', PConfig::get(local_user(), 'frio', 'scheme')); + + $info = [ + 'name' => $scheme, + 'description' => '', + 'author' => [], + 'version' => '', + 'overwrites' => [] + ]; + + if (!is_file($themepath . 'scheme/' . $scheme . '.php')) return $info; + + $f = file_get_contents($themepath . 'scheme/' . $scheme . '.php'); + + $r = preg_match('|/\*.*\*/|msU', $f, $m); + + if ($r) { + $ll = explode("\n", $m[0]); + foreach ($ll as $l) { + $l = trim($l, "\t\n\r */"); + if ($l != '') { + list($k, $v) = array_map('trim', explode(':', $l, 2)); + $k = strtolower($k); + if ($k == 'author') { + $r = preg_match('|([^<]+)<([^>]+)>|', $v, $m); + if ($r) { + $info['author'][] = ['name' => $m[1], 'link' => $m[2]]; + } else { + $info['author'][] = ['name' => $v]; + } + } elseif ($k == 'overwrites') { + $theme_settings = explode(',', str_replace(' ', '', $v)); + foreach ($theme_settings as $key => $value) { + $info['overwrites'][$value] = true; + } + } else { + if (array_key_exists($k, $info)) { + $info[$k] = $v; + } + } + } + } + } + + return $info; +} diff --git a/view/theme/frio/php/standard.php b/view/theme/frio/php/standard.php index edfec573b0..64c4544cd8 100644 --- a/view/theme/frio/php/standard.php +++ b/view/theme/frio/php/standard.php @@ -16,7 +16,7 @@ -"; + Skip to main content module !== 'install') { PConfig::load($uid, 'frio'); // Load the profile owners pconfig. - $schema = PConfig::get($uid, "frio", "schema"); - $nav_bg = PConfig::get($uid, "frio", "nav_bg"); - $nav_icon_color = PConfig::get($uid, "frio", "nav_icon_color"); - $link_color = PConfig::get($uid, "frio", "link_color"); - $bgcolor = PConfig::get($uid, "frio", "background_color"); - $contentbg_transp = PConfig::get($uid, "frio", "contentbg_transp"); - $background_image = PConfig::get($uid, "frio", "background_image"); - $bg_image_option = PConfig::get($uid, "frio", "bg_image_option"); - $modified = PConfig::get($uid, "frio", "css_modified"); + $scheme = PConfig::get($uid, 'frio', 'scheme', PConfig::get($uid, 'frio', 'schema')); + $nav_bg = PConfig::get($uid, 'frio', 'nav_bg'); + $nav_icon_color = PConfig::get($uid, 'frio', 'nav_icon_color'); + $link_color = PConfig::get($uid, 'frio', 'link_color'); + $background_color = PConfig::get($uid, 'frio', 'background_color'); + $contentbg_transp = PConfig::get($uid, 'frio', 'contentbg_transp'); + $background_image = PConfig::get($uid, 'frio', 'background_image'); + $bg_image_option = PConfig::get($uid, 'frio', 'bg_image_option'); + $modified = PConfig::get($uid, 'frio', 'css_modified'); // There is maybe the case that the user did never modify the theme settings. // In this case we store the present time. @@ -38,17 +38,17 @@ if ($a->module !== 'install') { Config::load('frio'); // Load frios system config. - $schema = Config::get("frio", "schema"); - $nav_bg = Config::get("frio", "nav_bg"); - $nav_icon_color = Config::get("frio", "nav_icon_color"); - $link_color = Config::get("frio", "link_color"); - $bgcolor = Config::get("frio", "background_color"); - $contentbg_transp = Config::get("frio", "contentbg_transp"); - $background_image = Config::get("frio", "background_image"); - $bg_image_option = Config::get("frio", "bg_image_option"); - $login_bg_image = Config::get("frio", "login_bg_image"); - $login_bg_color = Config::get("frio", "login_bg_color"); - $modified = Config::get("frio", "css_modified"); + $scheme = Config::get('frio', 'scheme', Config::get('frio', 'schema')); + $nav_bg = Config::get('frio', 'nav_bg'); + $nav_icon_color = Config::get('frio', 'nav_icon_color'); + $link_color = Config::get('frio', 'link_color'); + $background_color = Config::get('frio', 'background_color'); + $contentbg_transp = Config::get('frio', 'contentbg_transp'); + $background_image = Config::get('frio', 'background_image'); + $bg_image_option = Config::get('frio', 'bg_image_option'); + $login_bg_image = Config::get('frio', 'login_bg_image'); + $login_bg_color = Config::get('frio', 'login_bg_color'); + $modified = Config::get('frio', 'css_modified'); // There is maybe the case that the user did never modify the theme settings. // In this case we store the present time. @@ -59,60 +59,59 @@ if ($a->module !== 'install') { } // Now load the scheme. If a value is changed above, we'll keep the settings -// If not, we'll keep those defined by the schema -// Setting $schema to '' wasn't working for some reason, so we'll check it's +// If not, we'll keep those defined by the scheme +// Setting $scheme to '' wasn't working for some reason, so we'll check it's // not --- like the mobile theme does instead. -// Allow layouts to over-ride the schema. -if (x($_REQUEST, 'schema')) { - $schema = $_REQUEST['schema']; +// Allow layouts to over-ride the scheme. +if (x($_REQUEST, 'scheme')) { + $scheme = $_REQUEST['scheme']; } // Sanitize the data. -$schema = !empty($schema) ? basename($schema) : ""; +$scheme = !empty($scheme) ? basename($scheme) : ''; -if (($schema) && ($schema != '---')) { - if (file_exists('view/theme/frio/schema/' . $schema . '.php')) { - $schemefile = 'view/theme/frio/schema/' . $schema . '.php'; +if (($scheme) && ($scheme != '---')) { + if (file_exists('view/theme/frio/scheme/' . $scheme . '.php')) { + $schemefile = 'view/theme/frio/scheme/' . $scheme . '.php'; require_once $schemefile; } - if (file_exists('view/theme/frio/schema/' . $schema . '.css')) { - $schemecssfile = 'view/theme/frio/schema/' . $schema . '.css'; + if (file_exists('view/theme/frio/scheme/' . $scheme . '.css')) { + $schemecssfile = 'view/theme/frio/scheme/' . $scheme . '.css'; } } -// If we haven't got a schema, load the default. We shouldn't touch this - we +// If we haven't got a scheme, load the default. We shouldn't touch this - we // should leave it for admins to define for themselves. -// default.php and default.css MUST be symlinks to existing schema files. -if (! $schema) { - if (file_exists('view/theme/frio/schema/default.php')) { - $schemefile = 'view/theme/frio/schema/default.php'; +// default.php and default.css MUST be symlinks to existing scheme files. +if (!$scheme) { + if (file_exists('view/theme/frio/scheme/default.php')) { + $schemefile = 'view/theme/frio/scheme/default.php'; require_once $schemefile; } - if (file_exists('view/theme/frio/schema/default.css')) { - $schemecssfile = 'view/theme/frio/schema/default.css'; + if (file_exists('view/theme/frio/scheme/default.css')) { + $schemecssfile = 'view/theme/frio/scheme/default.css'; } } //Set some defaults - we have to do this after pulling owner settings, and we have to check for each setting //individually. If we don't, we'll have problems if a user has set one, but not all options. -$nav_bg = (empty($nav_bg) ? "#708fa0" : $nav_bg); -$nav_icon_color = (empty($nav_icon_color) ? "#fff" : $nav_icon_color); -$link_color = (empty($link_color) ? "#6fdbe8" : $link_color); -$bgcolor = (empty($bgcolor) ? "#ededed" : $bgcolor); +$nav_bg = (empty($nav_bg) ? '#708fa0' : $nav_bg); +$nav_icon_color = (empty($nav_icon_color) ? '#fff' : $nav_icon_color); +$link_color = (empty($link_color) ? '#6fdbe8' : $link_color); +$background_color = (empty($background_color) ? '#ededed' : $background_color); // The background image can not be empty. So we use a dummy jpg if no image was set. $background_image = (empty($background_image) ? 'img/none.jpg' : $background_image); -$modified = (empty($modified) ? time() :$modified); +$modified = (empty($modified) ? time() : $modified); // set a default login bg image if no custom image and no custom bg color are set. if (empty($login_bg_image) && empty($login_bg_color)) { - $login_bg_image = (empty($login_bg_image) ? 'img/login_bg.jpg' : $login_bg_image); + $login_bg_image = 'img/login_bg.jpg'; } -$login_bg_color = (empty($login_bg_color) ? "#ededed" : $login_bg_color); +$login_bg_color = (empty($login_bg_color) ? '#ededed' : $login_bg_color); - -$contentbg_transp = ((isset($contentbg_transp) && $contentbg_transp != "") ? $contentbg_transp : 100); +$contentbg_transp = ((isset($contentbg_transp) && $contentbg_transp != '') ? $contentbg_transp : 100); // Calculate some colors in dependance of existing colors. // Some colors are calculated to don't have too many selection @@ -153,29 +152,35 @@ if (!isset($link_hover_color)) { if (!isset($bg_image_option)) { $bg_image_option = null; } + switch ($bg_image_option) { - case "stretch": - $background_size_img = "100%"; + case 'stretch': + $background_size_img = '100%'; + $background_repeat = 'no-repeat'; break; - case "cover": - $background_size_img ="cover"; + case 'cover': + $background_size_img = 'cover'; + $background_repeat = 'no-repeat'; break; - case "repeat": - $background_size_img = "auto"; + case 'repeat': + $background_size_img = 'auto'; + $background_repeat = 'repeat'; break; - case "contain": - $background_size_img = "contain"; + case 'contain': + $background_size_img = 'contain'; + $background_repeat = 'repeat'; break; default: - $background_size_img = "auto"; + $background_size_img = 'auto'; + $background_repeat = 'no-repeat'; break; } // Convert transparency level from percentage to opacity value. $contentbg_transp = $contentbg_transp / 100; -$options = [ +$options = [ '$nav_bg' => $nav_bg, '$nav_icon_color' => $nav_icon_color, '$nav_icon_hover_color' => $nav_icon_hover_color, @@ -184,10 +189,11 @@ $options = [ '$menu_background_hover_color' => $menu_background_hover_color, '$btn_primary_color' => $nav_icon_color, '$btn_primary_hover_color' => $menu_background_hover_color, - '$bgcolor' => $bgcolor, + '$background_color' => $background_color, '$contentbg_transp' => $contentbg_transp, '$background_image' => $background_image, '$background_size_img' => $background_size_img, + '$background_repeat' => $background_repeat, '$login_bg_image' => $login_bg_image, '$login_bg_color' => $login_bg_color ]; @@ -214,13 +220,13 @@ $etag = md5($css); // Set a header for caching. header('Cache-Control: public'); -header('ETag: "'.$etag.'"'); -header('Last-Modified: '.$modified); +header('ETag: "' . $etag . '"'); +header('Last-Modified: ' . $modified); // Only send the CSS file if it was changed. if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) { $cached_modified = gmdate('r', strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])); - $cached_etag = str_replace(['"', "-gzip"], ['', ''], + $cached_etag = str_replace(['"', '-gzip'], ['', ''], stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])); if (($cached_modified == $modified) && ($cached_etag == $etag)) { diff --git a/view/theme/frio/templates/admin/contactblock.tpl b/view/theme/frio/templates/admin/contactblock.tpl index f330854bc9..3173c238b6 100644 --- a/view/theme/frio/templates/admin/contactblock.tpl +++ b/view/theme/frio/templates/admin/contactblock.tpl @@ -1,60 +1,105 @@ -
+ + +

{{$title}} - {{$page}}

{{$description}}

-
- -

{{$h_contacts}}

- {{if $contacts}} - - - - - {{foreach $th_contacts as $th}} - - {{/foreach}} - - - - - {{foreach $contacts as $contact}} - - - - - - - {{/foreach}} - - - - - - - -
- {{$th}} -
{{$contact.nickname}}{{$contact.name}}{{$contact.url}}
- {{$total_contacts}} -
-
- {{$paginate}} - {{else}} -

{{$no_data|escape:'html'}}

- {{/if}} -
+ {{* We organize the settings in collapsable panel-groups *}} +
+ {{* The form for entering user profile which should be blocked *}} +
+ -

{{$h_newblock}}

-
- - - - - - - -
{{include file="field_input.tpl" field=$contacturl}}
-
-
+
+
+ + + {{include file="field_input.tpl" field=$contacturl}} + +
+ +
+
+
+
+
+ + {{* The list of blocked user profiles with the possibility to unblock them *}} +
+ + +
+
+ + + {{if $contacts}} + + + + + {{foreach $th_contacts as $th}} + + {{/foreach}} + + + + + {{foreach $contacts as $contact}} + + + + + + + {{/foreach}} + + + + + + + +
+ {{$th}} +
+
+ + +
+
{{$contact.nickname}}{{$contact.name}}{{$contact.url}}
+ {{* Checkbox to select all blocked contacts *}} +
+ + +
+
+ {{$total_contacts}} +
+ +
+
+
+ + {{$paginate}} + + {{else}} +

{{$no_data|escape:'html'}}

+ {{/if}} +
+
+
+
diff --git a/view/theme/frio/templates/admin/users.tpl b/view/theme/frio/templates/admin/users.tpl index 784d46b207..92ef9be6fa 100644 --- a/view/theme/frio/templates/admin/users.tpl +++ b/view/theme/frio/templates/admin/users.tpl @@ -1,285 +1,345 @@ -
+

{{$title}} - {{$page}}

+ {{* We organize the settings in collapsable panel-groups *}} +
- -
-

{{$h_pending}}

+ +
+ - {{if $pending}} - - - - - {{foreach $th_pending as $th}}{{/foreach}} - - - - - {{foreach $pending as $u}} - - - - - - - - - - - - - {{/foreach}} - -
{{$th}}
{{$u.created}}{{$u.name}}{{$u.email}} - - -
{{$pendingnotetext}}{{$u.note}}
- diff --git a/view/theme/frio/templates/field_colorinput.tpl b/view/theme/frio/templates/field_colorinput.tpl index 886d647e9c..704db346d2 100644 --- a/view/theme/frio/templates/field_colorinput.tpl +++ b/view/theme/frio/templates/field_colorinput.tpl @@ -6,6 +6,8 @@ {{if $field.4}}{{$field.4}}{{/if}}
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/field_custom.tpl b/view/theme/frio/templates/field_custom.tpl index 20f529278d..158073a64e 100644 --- a/view/theme/frio/templates/field_custom.tpl +++ b/view/theme/frio/templates/field_custom.tpl @@ -2,5 +2,7 @@
{{$field.2}} - {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/field_fileinput.tpl b/view/theme/frio/templates/field_fileinput.tpl index 721a6535fb..c5f8ac86d2 100644 --- a/view/theme/frio/templates/field_fileinput.tpl +++ b/view/theme/frio/templates/field_fileinput.tpl @@ -6,6 +6,8 @@ {{if $field.4}}{{$field.4}}{{/if}}
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/field_input.tpl b/view/theme/frio/templates/field_input.tpl index bbd7535e54..62a7d72e83 100644 --- a/view/theme/frio/templates/field_input.tpl +++ b/view/theme/frio/templates/field_input.tpl @@ -2,6 +2,8 @@
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/field_intcheckbox.tpl b/view/theme/frio/templates/field_intcheckbox.tpl index 8863d14c4d..f898c87faf 100644 --- a/view/theme/frio/templates/field_intcheckbox.tpl +++ b/view/theme/frio/templates/field_intcheckbox.tpl @@ -2,6 +2,8 @@
- {{$field.4}} + {{if $field.4}} + {{$field.4}} + {{/if}}
diff --git a/view/theme/frio/templates/field_openid.tpl b/view/theme/frio/templates/field_openid.tpl index 8081f9cf11..66f8c9e809 100644 --- a/view/theme/frio/templates/field_openid.tpl +++ b/view/theme/frio/templates/field_openid.tpl @@ -2,6 +2,8 @@
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/field_password.tpl b/view/theme/frio/templates/field_password.tpl index 31defaf33c..7bef420a18 100644 --- a/view/theme/frio/templates/field_password.tpl +++ b/view/theme/frio/templates/field_password.tpl @@ -2,6 +2,8 @@
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/field_radio.tpl b/view/theme/frio/templates/field_radio.tpl index 42c145e3a8..725e1c96af 100644 --- a/view/theme/frio/templates/field_radio.tpl +++ b/view/theme/frio/templates/field_radio.tpl @@ -4,7 +4,9 @@
-
\ No newline at end of file + diff --git a/view/theme/frio/templates/field_select.tpl b/view/theme/frio/templates/field_select.tpl index 9c03151214..594b91002e 100644 --- a/view/theme/frio/templates/field_select.tpl +++ b/view/theme/frio/templates/field_select.tpl @@ -4,5 +4,7 @@ - {{$field.3}} - \ No newline at end of file + {{if $field.3}} + {{$field.3}} + {{/if}} + diff --git a/view/theme/frio/templates/field_select_raw.tpl b/view/theme/frio/templates/field_select_raw.tpl index d4f4768603..52b63079c1 100644 --- a/view/theme/frio/templates/field_select_raw.tpl +++ b/view/theme/frio/templates/field_select_raw.tpl @@ -4,5 +4,7 @@ - {{$field.3}} - \ No newline at end of file + {{if $field.3}} + {{$field.3}} + {{/if}} + diff --git a/view/theme/frio/templates/field_textarea.tpl b/view/theme/frio/templates/field_textarea.tpl index 8ef56babb7..1aea484de7 100644 --- a/view/theme/frio/templates/field_textarea.tpl +++ b/view/theme/frio/templates/field_textarea.tpl @@ -2,6 +2,8 @@
- {{$field.3}} + {{if $field.3}} + {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/field_themeselect.tpl b/view/theme/frio/templates/field_themeselect.tpl index 3b2cb780c8..fc1f7243af 100644 --- a/view/theme/frio/templates/field_themeselect.tpl +++ b/view/theme/frio/templates/field_themeselect.tpl @@ -5,6 +5,8 @@ + {{if $field.3}} {{$field.3}} + {{/if}} {{if $field.5=="preview"}}
{{/if}} - \ No newline at end of file + diff --git a/view/theme/frio/templates/field_yesno.tpl b/view/theme/frio/templates/field_yesno.tpl index 85096c70e3..47649fe676 100644 --- a/view/theme/frio/templates/field_yesno.tpl +++ b/view/theme/frio/templates/field_yesno.tpl @@ -14,6 +14,8 @@ + {{if $field.3}} {{$field.3}} + {{/if}}
diff --git a/view/theme/frio/templates/invite.tpl b/view/theme/frio/templates/invite.tpl new file mode 100644 index 0000000000..9ff20240ae --- /dev/null +++ b/view/theme/frio/templates/invite.tpl @@ -0,0 +1,19 @@ + +
+ +

{{$title}}

+ +
+ + +
+ {{include file="field_textarea.tpl" field=$recipients}} + {{include file="field_textarea.tpl" field=$message}} + +
+ +
+
+
+
+
diff --git a/view/theme/frio/templates/login.tpl b/view/theme/frio/templates/login.tpl index aaa42d24b4..ae586a3e6a 100644 --- a/view/theme/frio/templates/login.tpl +++ b/view/theme/frio/templates/login.tpl @@ -8,6 +8,10 @@
{{include file="field_input.tpl" field=$lname}} {{include file="field_password.tpl" field=$lpassword}} + +
{{if $openid}} @@ -19,10 +23,7 @@ {{include file="field_checkbox.tpl" field=$lremember}}
- {{$lostlink}} -
- {{if $register}}{{$register.desc}}{{/if}}
@@ -32,7 +33,15 @@ {{/foreach}} +
+{{if $register}} + +{{/if}} + diff --git a/view/theme/frio/templates/peoplefind.tpl b/view/theme/frio/templates/peoplefind.tpl index 5a84f26c8f..21b3e47e83 100644 --- a/view/theme/frio/templates/peoplefind.tpl +++ b/view/theme/frio/templates/peoplefind.tpl @@ -1,22 +1,23 @@ -
-

{{$findpeople}}

+

{{$nv.findpeople}}

{{* The search field *}} - +
+ {{* Directory links *}} + + {{* Additional links *}} - - + + - {{if $inv}} - + {{if $nv.inv}} + {{/if}}
- diff --git a/view/theme/frio/templates/prv_message.tpl b/view/theme/frio/templates/prv_message.tpl index d80fcf6a12..4c90dcae6d 100644 --- a/view/theme/frio/templates/prv_message.tpl +++ b/view/theme/frio/templates/prv_message.tpl @@ -33,7 +33,7 @@