aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Module/Display.php6
-rw-r--r--Zotlabs/Module/Editpost.php2
-rw-r--r--Zotlabs/Module/Item.php3
-rw-r--r--Zotlabs/Module/Like.php4
-rw-r--r--Zotlabs/Module/Photos.php10
-rw-r--r--Zotlabs/Module/Profiles.php2
-rw-r--r--Zotlabs/Module/React.php1
-rw-r--r--Zotlabs/Module/Settings/Oauth.php11
-rw-r--r--Zotlabs/Module/Settings/Oauth2.php160
-rw-r--r--Zotlabs/Module/Well_known.php5
-rw-r--r--Zotlabs/Storage/Browser.php2
-rw-r--r--Zotlabs/Widget/Settings_menu.php10
-rw-r--r--doc/dnt-policy.txt218
-rw-r--r--doc/feature/additional/access.md41
-rw-r--r--doc/feature/additional/composition.md67
-rw-r--r--doc/feature/additional/filtering.md57
-rw-r--r--doc/feature/additional/general.md130
-rw-r--r--doc/feature/additional/overview.md33
-rw-r--r--doc/feature/additional/posts.md57
-rw-r--r--doc/toc.html3
-rw-r--r--include/api.php30
-rw-r--r--include/bbcode.php48
-rw-r--r--include/channel.php2
-rw-r--r--include/conversation.php2
-rw-r--r--include/features.php13
-rw-r--r--include/help.php2
-rw-r--r--include/import.php4
-rw-r--r--include/network.php1
-rw-r--r--include/text.php17
-rw-r--r--include/zot.php11
-rw-r--r--view/js/autocomplete.js2
-rw-r--r--view/tpl/cloud_header.tpl2
-rwxr-xr-xview/tpl/photo_album.tpl2
-rwxr-xr-xview/tpl/photos_recent.tpl2
-rwxr-xr-xview/tpl/settings_oauth2.tpl35
-rwxr-xr-xview/tpl/settings_oauth2_edit.tpl21
-rwxr-xr-xview/tpl/settings_oauth_edit.tpl1
37 files changed, 929 insertions, 88 deletions
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index 30f2a7f5f..06c9479b2 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -132,7 +132,7 @@ class Display extends \Zotlabs\Web\Controller {
$y = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item.id = %d limit 1",
intval($target_item['uid']),
- intval($target_item['id'])
+ intval($target_item['parent'])
);
if($x && $y) {
goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['v']);
@@ -149,7 +149,7 @@ class Display extends \Zotlabs\Web\Controller {
$y = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and item.id = %d limit 1",
intval($target_item['uid']),
- intval($target_item['id'])
+ intval($target_item['parent'])
);
if($x && $y) {
goaway(z_root() . '/articles/' . $x[0]['channel_address'] . '/' . $y[0]['v']);
@@ -166,7 +166,7 @@ class Display extends \Zotlabs\Web\Controller {
$y = q("select * from iconfig left join item on iconfig.iid = item.id
where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'CARD' and item.id = %d limit 1",
intval($target_item['uid']),
- intval($target_item['id'])
+ intval($target_item['parent'])
);
if($x && $y) {
goaway(z_root() . '/cards/' . $x[0]['channel_address'] . '/' . $y[0]['v']);
diff --git a/Zotlabs/Module/Editpost.php b/Zotlabs/Module/Editpost.php
index a54c42e7f..57a4cb97f 100644
--- a/Zotlabs/Module/Editpost.php
+++ b/Zotlabs/Module/Editpost.php
@@ -82,7 +82,7 @@ class Editpost extends \Zotlabs\Web\Controller {
'editor_autocomplete'=> true,
'bbco_autocomplete'=> 'bbcode',
'return_path' => $_SESSION['return_url'],
- 'button' => t('Edit'),
+ 'button' => t('Submit'),
'hide_voting' => true,
'hide_future' => true,
'hide_location' => true,
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index ed35fc20d..083ad50f7 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -468,6 +468,7 @@ class Item extends \Zotlabs\Web\Controller {
$private = intval($acl->is_private() || $parent_item['item_private']);
$public_policy = $parent_item['public_policy'];
$owner_hash = $parent_item['owner_xchan'];
+ $webpage = $parent_item['item_type'];
}
if((! $allow_empty) && (! strlen($body))) {
@@ -542,7 +543,7 @@ class Item extends \Zotlabs\Web\Controller {
// Look for tags and linkify them
$results = linkify_tags($a, $body, ($uid) ? $uid : $profile_uid);
-
+
if($results) {
// Set permissions based on tag replacements
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index 6d9fde17c..4e216f08b 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -296,10 +296,11 @@ class Like extends \Zotlabs\Web\Controller {
notice( t('Permission denied') . EOL);
killme();
}
-
+
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($item['owner_xchan'])
);
+
if($r)
$thread_owner = $r[0];
else
@@ -418,6 +419,7 @@ class Like extends \Zotlabs\Web\Controller {
$arr['item_origin'] = 1;
$arr['item_notshown'] = 1;
+ $arr['item_type'] = $item['item_type'];
if(intval($item['item_wall']))
$arr['item_wall'] = 1;
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 81af607ec..fa22c3f26 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -695,8 +695,8 @@ class Photos extends \Zotlabs\Web\Controller {
'$newalbum_label' => t('Enter an album name'),
'$newalbum_placeholder' => t('or select an existing album (doubleclick)'),
'$visible' => array('visible', t('Create a status post for this upload'), 0,'', array(t('No'), t('Yes')), 'onclick="showHideBodyTextarea();"'),
- '$caption' => array('description', t('Caption (optional):')),
- '$body' => array('body', t('Description (optional):'),'', 'Description will only appear in the status post'),
+ '$caption' => array('description', t('Title (optional)')),
+ '$body' => array('body', t('Description (optional)'),'', 'Description will only appear in the status post'),
'$albums' => $albums['albums'],
'$selname' => $selname,
'$permissions' => t('Permissions'),
@@ -841,7 +841,7 @@ class Photos extends \Zotlabs\Web\Controller {
'$album_id' => $datum,
'$album_edit' => array(t('Edit Album'), $album_edit),
'$can_post' => $can_post,
- '$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/upload/' . $datum),
+ '$upload' => array(t('Add Photos'), z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/upload/' . $datum),
'$order' => $order,
'$upload_form' => $upload_form,
'$usage' => $usage_message
@@ -1065,7 +1065,7 @@ class Photos extends \Zotlabs\Web\Controller {
'newalbum_placeholder' => t('or select an existing one (doubleclick)'),
'nickname' => \App::$data['channel']['channel_address'],
'resource_id' => $ph[0]['resource_id'],
- 'capt_label' => t('Caption'),
+ 'capt_label' => t('Title (optional)'),
'caption' => $caption_e,
'tag_label' => t('Add a Tag'),
'permissions' => t('Permissions'),
@@ -1378,7 +1378,7 @@ class Photos extends \Zotlabs\Web\Controller {
'$title' => t('Recent Photos'),
'$album_id' => bin2hex(t('Recent Photos')),
'$can_post' => $can_post,
- '$upload' => array(t('Upload'), z_root().'/photos/'.\App::$data['channel']['channel_address'].'/upload'),
+ '$upload' => array(t('Add Photos'), z_root().'/photos/'.\App::$data['channel']['channel_address'].'/upload'),
'$photos' => $photos,
'$upload_form' => $upload_form,
'$usage' => $usage_message
diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php
index e02cb33db..202ee462a 100644
--- a/Zotlabs/Module/Profiles.php
+++ b/Zotlabs/Module/Profiles.php
@@ -732,7 +732,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'$addthing' => t('Add profile things'),
'$personal' => t('Personal'),
'$location' => t('Location'),
- '$relation' => t('Relation'),
+ '$relation' => t('Relationship'),
'$miscellaneous'=> t('Miscellaneous'),
'$exportable' => feature_enabled(local_channel(),'profile_export'),
'$lbl_import' => t('Import profile from file'),
diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php
index 6473317c7..fbb760786 100644
--- a/Zotlabs/Module/React.php
+++ b/Zotlabs/Module/React.php
@@ -49,6 +49,7 @@ class React extends \Zotlabs\Web\Controller {
$n['aid'] = $channel['channel_account_id'];
$n['uid'] = $channel['channel_id'];
$n['item_origin'] = true;
+ $n['item_type'] = $i[0]['item_type'];
$n['parent'] = $postid;
$n['parent_mid'] = $i[0]['mid'];
$n['mid'] = item_message_id();
diff --git a/Zotlabs/Module/Settings/Oauth.php b/Zotlabs/Module/Settings/Oauth.php
index c612c7667..d6576c6de 100644
--- a/Zotlabs/Module/Settings/Oauth.php
+++ b/Zotlabs/Module/Settings/Oauth.php
@@ -23,11 +23,12 @@ class Oauth {
check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth');
- $name = ((x($_POST,'name')) ? $_POST['name'] : '');
- $key = ((x($_POST,'key')) ? $_POST['key'] : '');
- $secret = ((x($_POST,'secret')) ? $_POST['secret'] : '');
- $redirect = ((x($_POST,'redirect')) ? $_POST['redirect'] : '');
- $icon = ((x($_POST,'icon')) ? $_POST['icon'] : '');
+ $name = ((x($_POST,'name')) ? escape_tags($_POST['name']) : '');
+ $key = ((x($_POST,'key')) ? escape_tags($_POST['key']) : '');
+ $secret = ((x($_POST,'secret')) ? escape_tags($_POST['secret']) : '');
+ $redirect = ((x($_POST,'redirect')) ? escape_tags($_POST['redirect']) : '');
+ $icon = ((x($_POST,'icon')) ? escape_tags($_POST['icon']) : '');
+ $oauth2 = ((x($_POST,'oauth2')) ? intval($_POST['oauth2']) : 0);
$ok = true;
if($name == '') {
$ok = false;
diff --git a/Zotlabs/Module/Settings/Oauth2.php b/Zotlabs/Module/Settings/Oauth2.php
new file mode 100644
index 000000000..88bbea3b8
--- /dev/null
+++ b/Zotlabs/Module/Settings/Oauth2.php
@@ -0,0 +1,160 @@
+<?php
+
+namespace Zotlabs\Module\Settings;
+
+
+class Oauth2 {
+
+
+ function post() {
+
+ if(x($_POST,'remove')){
+ check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2');
+
+ $key = $_POST['remove'];
+ q("DELETE FROM tokens WHERE id='%s' AND uid=%d",
+ dbesc($key),
+ local_channel());
+ goaway(z_root()."/settings/oauth2/");
+ return;
+ }
+
+ if((argc() > 2) && (argv(2) === 'edit' || argv(2) === 'add') && x($_POST,'submit')) {
+
+ check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2');
+
+ $name = ((x($_POST,'name')) ? escape_tags(trim($_POST['name'])) : '');
+ $secret = ((x($_POST,'secret')) ? escape_tags(trim($_POST['secret'])) : '');
+ $redirect = ((x($_POST,'redirect')) ? escape_tags(trim($_POST['redirect'])) : '');
+ $grant = ((x($_POST,'grant')) ? escape_tags(trim($_POST['grant'])) : '');
+ $scope = ((x($_POST,'scope')) ? escape_tags(trim($_POST['scope'])) : '');
+
+ $ok = true;
+ if($name == '' || $secret == '') {
+ $ok = false;
+ notice( t('Name and Secret are required') . EOL);
+ }
+
+ if($ok) {
+ if ($_POST['submit']==t("Update")){
+ $r = q("UPDATE oauth_clients SET
+ client_id = '%s',
+ client_secret = '%s',
+ redirect_uri = '%s',
+ grant_types = '%s',
+ scope = '%s',
+ user_id = '%s'
+ WHERE client_id='%s'",
+ dbesc($name),
+ dbesc($secret),
+ dbesc($redirect),
+ dbesc($grant),
+ dbesc($scope),
+ dbesc(local_channel()),
+ dbesc($name));
+ } else {
+ $r = q("INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, grant_types, scope, user_id)
+ VALUES ('%s','%s','%s','%s','%s','%s')",
+ dbesc($name),
+ dbesc($secret),
+ dbesc($redirect),
+ dbesc($grant),
+ dbesc($scope),
+ dbesc(local_channel())
+ );
+ $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ",
+ dbesc($name),
+ intval(local_channel()),
+ dbesc('all')
+ );
+ }
+ }
+ goaway(z_root()."/settings/oauth2/");
+ return;
+ }
+ }
+
+ function get() {
+
+ if((argc() > 2) && (argv(2) === 'add')) {
+ $tpl = get_markup_template("settings_oauth2_edit.tpl");
+ $o .= replace_macros($tpl, array(
+ '$form_security_token' => get_form_security_token("settings_oauth2"),
+ '$title' => t('Add OAuth2 application'),
+ '$submit' => t('Submit'),
+ '$cancel' => t('Cancel'),
+ '$name' => array('name', t('Name'), '', t('Name of application')),
+ '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')),
+ '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')),
+ '$grant' => array('grant', t('Grant Types'), '', t('leave blank unless your application sepcifically requires this')),
+ '$scope' => array('scope', t('Authorization scope'), '', t('leave blank unless your application sepcifically requires this')),
+ ));
+ return $o;
+ }
+
+ if((argc() > 3) && (argv(2) === 'edit')) {
+ $r = q("SELECT * FROM oauth_clients WHERE client_id='%s' AND user_id= '%s'",
+ dbesc(argv(3)),
+ dbesc(local_channel())
+ );
+
+ if (! $r){
+ notice(t('OAuth2 Application not found.'));
+ return;
+ }
+
+ $app = $r[0];
+
+ $tpl = get_markup_template("settings_oauth2_edit.tpl");
+ $o .= replace_macros($tpl, array(
+ '$form_security_token' => get_form_security_token("settings_oauth2"),
+ '$title' => t('Add application'),
+ '$submit' => t('Update'),
+ '$cancel' => t('Cancel'),
+ '$name' => array('name', t('Name'), $app['client_id'], t('Name of application')),
+ '$secret' => array('secret', t('Consumer Secret'), $app['client_secret'], t('Automatically generated - change if desired. Max length 20')),
+ '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], t('Redirect URI - leave blank unless your application specifically requires this')),
+ '$grant' => array('grant', t('Grant Types'), $app['grant_types'], t('leave blank unless your application sepcifically requires this')),
+ '$scope' => array('scope', t('Authorization scope'), $app['scope'], t('leave blank unless your application sepcifically requires this')),
+ ));
+ return $o;
+ }
+
+ if((argc() > 3) && (argv(2) === 'delete')) {
+ check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2', 't');
+
+ $r = q("DELETE FROM oauth_clients WHERE client_id = '%s' AND user_id = '%s'",
+ dbesc(argv(3)),
+ dbesc(local_channel())
+ );
+ goaway(z_root()."/settings/oauth2/");
+ return;
+ }
+
+
+ $r = q("SELECT oauth_clients.*, oauth_access_tokens.access_token as oauth_token, (oauth_clients.user_id = '%s') AS my
+ FROM oauth_clients
+ LEFT JOIN oauth_access_tokens ON oauth_clients.client_id=oauth_access_tokens.client_id
+ WHERE oauth_clients.user_id IN ('%s',0)",
+ dbesc(local_channel()),
+ dbesc(local_channel())
+ );
+
+ $tpl = get_markup_template("settings_oauth2.tpl");
+ $o .= replace_macros($tpl, array(
+ '$form_security_token' => get_form_security_token("settings_oauth2"),
+ '$baseurl' => z_root(),
+ '$title' => t('Connected OAuth2 Apps'),
+ '$add' => t('Add application'),
+ '$edit' => t('Edit'),
+ '$delete' => t('Delete'),
+ '$consumerkey' => t('Client key starts with'),
+ '$noname' => t('No name'),
+ '$remove' => t('Remove authorization'),
+ '$apps' => $r,
+ ));
+ return $o;
+
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Module/Well_known.php b/Zotlabs/Module/Well_known.php
index b57666bff..177de2323 100644
--- a/Zotlabs/Module/Well_known.php
+++ b/Zotlabs/Module/Well_known.php
@@ -26,7 +26,6 @@ class Well_known extends \Zotlabs\Web\Controller {
killme();
}
-
switch(argv(1)) {
case 'zot-info':
\App::$argc -= 1;
@@ -52,6 +51,10 @@ class Well_known extends \Zotlabs\Web\Controller {
$module->init();
break;
+ case 'dnt-policy.txt':
+ echo file_get_contents('doc/dnt-policy.txt');
+ killme();
+
default:
if(file_exists(\App::$cmd)) {
echo file_get_contents(\App::$cmd);
diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php
index f1c95802b..508c39d22 100644
--- a/Zotlabs/Storage/Browser.php
+++ b/Zotlabs/Storage/Browser.php
@@ -274,7 +274,7 @@ class Browser extends DAV\Browser\Plugin {
'$actionspanel' => $output,
'$shared' => t('Shared'),
'$create' => t('Create'),
- '$upload' => t('Upload'),
+ '$upload' => t('Add Files'),
'$is_owner' => $is_owner,
'$parentpath' => $parentpath,
'$cpath' => bin2hex(\App::$query_string),
diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php
index 455fdcb9b..9574becc3 100644
--- a/Zotlabs/Widget/Settings_menu.php
+++ b/Zotlabs/Widget/Settings_menu.php
@@ -81,12 +81,20 @@ class Settings_menu {
if(feature_enabled(local_channel(),'oauth_clients')) {
$tabs[] = array(
- 'label' => t('Connected apps'),
+ 'label' => t('OAuth1 apps'),
'url' => z_root() . '/settings/oauth',
'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
);
}
+ if(feature_enabled(local_channel(),'oauth2_clients')) {
+ $tabs[] = array(
+ 'label' => t('OAuth2 apps'),
+ 'url' => z_root() . '/settings/oauth2',
+ 'selected' => ((argv(1) === 'oauth2') ? 'active' : ''),
+ );
+ }
+
if(feature_enabled(local_channel(),'access_tokens')) {
$tabs[] = array(
'label' => t('Guest Access Tokens'),
diff --git a/doc/dnt-policy.txt b/doc/dnt-policy.txt
new file mode 100644
index 000000000..ad946d1f8
--- /dev/null
+++ b/doc/dnt-policy.txt
@@ -0,0 +1,218 @@
+Do Not Track Compliance Policy
+
+Version 1.0
+
+This domain complies with user opt-outs from tracking via the "Do Not Track"
+or "DNT" header [http://www.w3.org/TR/tracking-dnt/]. This file will always
+be posted via HTTPS at https://example-domain.com/.well-known/dnt-policy.txt
+to indicate this fact.
+
+SCOPE
+
+This policy document allows an operator of a Fully Qualified Domain Name
+("domain") to declare that it respects Do Not Track as a meaningful privacy
+opt-out of tracking, so that privacy-protecting software can better determine
+whether to block or anonymize communications with this domain. This policy is
+intended first and foremost to be posted on domains that publish ads, widgets,
+images, scripts and other third-party embedded hypertext (for instance on
+widgets.example.com), but it can be posted on any domain, including those users
+visit directly (such as www.example.com). The policy may be applied to some
+domains used by a company, site, or service, and not to others. Do Not Track
+may be sent by any client that uses the HTTP protocol, including websites,
+mobile apps, and smart devices like TVs. Do Not Track also works with all
+protocols able to read HTTP headers, including SPDY.
+
+NOTE: This policy contains both Requirements and Exceptions. Where possible
+terms are defined in the text, but a few additional definitions are included
+at the end.
+
+REQUIREMENTS
+
+When this domain receives Web requests from a user who enables DNT by actively
+choosing an opt-out setting in their browser or by installing software that is
+primarily designed to protect privacy ("DNT User"), we will take the following
+measures with respect to those users' data, subject to the Exceptions, also
+listed below:
+
+1. END USER IDENTIFIERS:
+
+ a. If a DNT User has logged in to our service, all user identifiers, such as
+ unique or nearly unique cookies, "supercookies" and fingerprints are
+ discarded as soon as the HTTP(S) response is issued.
+
+ Data structures which associate user identifiers with accounts may be
+ employed to recognize logged in users per Exception 4 below, but may not
+ be associated with records of the user's activities unless otherwise
+ excepted.
+
+ b. If a DNT User is not logged in to our service, we will take steps to ensure
+ that no user identifiers are transmitted to us at all.
+
+2. LOG RETENTION:
+
+ a. Logs with DNT Users' identifiers removed (but including IP addresses and
+ User Agent strings) may be retained for a period of 10 days or less,
+ unless an Exception (below) applies. This period of time balances privacy
+ concerns with the need to ensure that log processing systems have time to
+ operate; that operations engineers have time to monitor and fix technical
+ and performance problems; and that security and data aggregation systems
+ have time to operate.
+
+ b. These logs will not be used for any other purposes.
+
+3. OTHER DOMAINS:
+
+ a. If this domain transfers identifiable user data about DNT Users to
+ contractors, affiliates or other parties, or embeds from or posts data to
+ other domains, we will either:
+
+ b. ensure that the operators of those domains abide by this policy overall
+ by posting it at /.well-known/dnt-policy.txt via HTTPS on the domains in
+ question,
+
+ OR
+
+ ensure that the recipient's policies and practices require the recipient
+ to respect the policy for our DNT Users' data.
+
+ OR
+
+ obtain a contractual commitment from the recipient to respect this policy
+ for our DNT Users' data.
+
+ NOTE: if an “Other Domain” does not receive identifiable user information
+ from the domain because such information has been removed, because the
+ Other Domain does not log that information, or for some other reason, these
+ requirements do not apply.
+
+ c. "Identifiable" means any records which are not Anonymized or otherwise
+ covered by the Exceptions below.
+
+4. PERIODIC REASSERTION OF COMPLIANCE:
+
+ At least once every 12 months, we will take reasonable steps commensurate
+ with the size of our organization and the nature of our service to confirm
+ our ongoing compliance with this document, and we will publicly reassert our
+ compliance.
+
+5. USER NOTIFICATION:
+
+ a. If we are required by law to retain or disclose user identifiers, we will
+ attempt to provide the users with notice (unless we are prohibited or it
+ would be futile) that a request for their information has been made in
+ order to give the users an opportunity to object to the retention or
+ disclosure.
+
+ b. We will attempt to provide this notice by email, if the users have given
+ us an email address, and by postal mail if the users have provided a
+ postal address.
+
+ c. If the users do not challenge the disclosure request, we may be legally
+ required to turn over their information.
+
+ d. We may delay notice if we, in good faith, believe that an emergency
+ involving danger of death or serious physical injury to any person
+ requires disclosure without delay of information relating to the
+ emergency.
+
+EXCEPTIONS
+
+Data from DNT Users collected by this domain may be logged or retained only in
+the following specific situations:
+
+1. CONSENT / "OPT BACK IN"
+
+ a. DNT Users are opting out from tracking across the Web. It is possible
+ that for some feature or functionality, we will need to ask a DNT User to
+ "opt back in" to be tracked by us across the entire Web.
+
+ b. If we do that, we will take reasonable steps to verify that the users who
+ select this option have genuinely intended to opt back in to tracking.
+ One way to do this is by performing scientifically reasonable user
+ studies with a representative sample of our users, but smaller
+ organizations can satisfy this requirement by other means.
+
+ c. Where we believe that we have opt back in consent, our server will
+ send a tracking value status header "Tk: C" as described in section 6.2
+ of the W3C Tracking Preference Expression draft:
+
+ http://www.w3.org/TR/tracking-dnt/#tracking-status-value
+
+2. TRANSACTIONS
+
+ If a DNT User actively and knowingly enters a transaction with our
+ services (for instance, clicking on a clearly-labeled advertisement,
+ posting content to a widget, or purchasing an item), we will retain
+ necessary data for as long as required to perform the transaction. This
+ may for example include keeping auditing information for clicks on
+ advertising links; keeping a copy of posted content and the name of the
+ posting user; keeping server-side session IDs to recognize logged in
+ users; or keeping a copy of the physical address to which a purchased
+ item will be shipped. By their nature, some transactions will require data
+ to be retained indefinitely.
+
+3. TECHNICAL AND SECURITY LOGGING:
+
+ a. If, during the processing of the initial request (for unique identifiers)
+ or during the subsequent 10 days (for IP addresses and User Agent strings),
+ we obtain specific information that causes our employees or systems to
+ believe that a request is, or is likely to be, part of a security attack,
+ spam submission, or fraudulent transaction, then logs of those requests
+ are not subject to this policy.
+
+ b. If we encounter technical problems with our site, then, in rare
+ circumstances, we may retain logs for longer than 10 days, if that is
+ necessary to diagnose and fix those problems, but this practice will not be
+ routinized and we will strive to delete such logs as soon as possible.
+
+4. AGGREGATION:
+
+ a. We may retain and share anonymized datasets, such as aggregate records of
+ readership patterns; statistical models of user behavior; graphs of system
+ variables; data structures to count active users on monthly or yearly
+ bases; database tables mapping authentication cookies to logged in
+ accounts; non-unique data structures constructed within browsers for tasks
+ such as ad frequency capping or conversion tracking; or logs with truncated
+ and/or encrypted IP addresses and simplified User Agent strings.
+
+ b. "Anonymized" means we have conducted risk mitigation to ensure
+ that the dataset, plus any additional information that is in our
+ possession or likely to be available to us, does not allow the
+ reconstruction of reading habits, online or offline activity of groups of
+ fewer than 5000 individuals or devices.
+
+ c. If we generate anonymized datasets under this exception we will publicly
+ document our anonymization methods in sufficient detail to allow outside
+ experts to evaluate the effectiveness of those methods.
+
+5. ERRORS:
+
+From time to time, there may be errors by which user data is temporarily
+logged or retained in violation of this policy. If such errors are
+inadvertent, rare, and made in good faith, they do not constitute a breach
+of this policy. We will delete such data as soon as practicable after we
+become aware of any error and take steps to ensure that it is deleted by any
+third-party who may have had access to the data.
+
+ADDITIONAL DEFINITIONS
+
+"Fully Qualified Domain Name" means a domain name that addresses a computer
+connected to the Internet. For instance, example1.com; www.example1.com;
+ads.example1.com; and widgets.example2.com are all distinct FQDNs.
+
+"Supercookie" means any technology other than an HTTP Cookie which can be used
+by a server to associate identifiers with the clients that visit it. Examples
+of supercookies include Flash LSO cookies, DOM storage, HTML5 storage, or
+tricks to store information in caches or etags.
+
+"Risk mitigation" means an engineering process that evaluates the possibility
+and likelihood of various adverse outcomes, considers the available methods of
+making those adverse outcomes less likely, and deploys sufficient mitigations
+to bring the probability and harm from adverse outcomes below an acceptable
+threshold.
+
+"Reading habits" includes amongst other things lists of visited DNS names, if
+those domains pertain to specific topics or activities, but records of visited
+DNS names are not reading habits if those domain names serve content of a very
+diverse and general nature, thereby revealing minimal information about the
+opinions, interests or activities of the user.
diff --git a/doc/feature/additional/access.md b/doc/feature/additional/access.md
new file mode 100644
index 000000000..3581ca11d
--- /dev/null
+++ b/doc/feature/additional/access.md
@@ -0,0 +1,41 @@
+## Access Control and Permissions
+
+
+### Privacy Groups
+
+Enable management and selection of privacy groups.
+<!-- TODO: full description for Privacy Groups -->
+
+Minimum required technical skill level to see this feature: 0
+
+
+### Multiple Profiles
+
+Ability to create multiple profiles.
+<!-- TODO: full description for Multiple Profiles -->
+
+Minimum required technical skill level to see this feature: 3
+
+
+### Permission Groups
+
+Provide alternate connection permission roles.
+<!-- TODO: full description for Permission Groups -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### OAuth Clients
+
+Manage authenticatication tokens for mobile and remote apps.
+<!-- TODO: full description for OAuth Clients -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Access Tokens
+
+Create access tokens so that non-members can access private content.
+<!-- TODO: full description for Access Tokens -->
+
+Minimum required technical skill level to see this feature: 2
diff --git a/doc/feature/additional/composition.md b/doc/feature/additional/composition.md
new file mode 100644
index 000000000..1256f7501
--- /dev/null
+++ b/doc/feature/additional/composition.md
@@ -0,0 +1,67 @@
+## Post Composition Features
+
+
+### Large Photos
+
+Include large (1024px) photo thumbnails in posts.
+If not enabled, use small (640px) photo thumbnails
+<!-- TODO: full description for Large Photos -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Channel Sources
+
+Automatically import channel content from other channels or feeds
+<!-- TODO: full description for Channel Sources -->
+
+Minimum required technical skill level to see this feature: 3
+
+
+### Even More Encryption
+
+Allow optional encryption of content end-to-end with a shared secret key
+<!-- TODO: full description for Even More Encryption -->
+
+Minimum required technical skill level to see this feature: 3
+
+
+### Enable Voting Tools
+
+Provide a class of post which others can vote on
+<!-- TODO: full description for Enable Voting Tools -->
+
+Minimum required technical skill level to see this feature: 3
+
+
+### Disable Comments
+
+Provide the option to disable comments for a post
+<!-- TODO: full description for Disable Comments -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Delayed Posting
+
+Allow posts to be published at a later date
+<!-- TODO: full description for Delayed Posting -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Content Expiration
+
+Remove posts/comments and/or private messages at a future time
+<!-- TODO: full description for Content Expiration -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Suppress Duplicate Posts/Comments
+
+Prevent posts with identical content to be published
+with less than two minutes in between submissions.
+<!-- TODO: full description for Suppress Duplicate Posts/Comments -->
+
+Minimum required technical skill level to see this feature: 1
diff --git a/doc/feature/additional/filtering.md b/doc/feature/additional/filtering.md
new file mode 100644
index 000000000..ba8e1e29f
--- /dev/null
+++ b/doc/feature/additional/filtering.md
@@ -0,0 +1,57 @@
+## Network and Stream Filtering
+
+
+### Search by Date
+
+Ability to select posts by date ranges
+<!-- TODO: full description for Search by Date -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Saved Searches
+
+Save search terms for re-use
+<!-- TODO: full description for Saved Searches -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Network Personal Tab
+
+Enable tab to display only Network posts that you've interacted on
+<!-- TODO: full description for Network Personal Tab -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Network New Tab
+
+Enable tab to display all new Network activity
+<!-- TODO: full description for Network New Tab -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Affinity Tool
+
+Filter stream activity by depth of relationships
+<!-- TODO: full description for Affinity Tool -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Suggest Channels
+
+Show friend and connection suggestions
+<!-- TODO: full description for Suggest Channels -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Connection Filtering
+
+Filter incoming posts from connections based on keywords/content
+<!-- TODO: full description for Connection Filtering -->
+
+Minimum required technical skill level to see this feature: 3
diff --git a/doc/feature/additional/general.md b/doc/feature/additional/general.md
new file mode 100644
index 000000000..a1b712b12
--- /dev/null
+++ b/doc/feature/additional/general.md
@@ -0,0 +1,130 @@
+## General Features
+
+
+### New Member Links
+
+Display new member quick links menu.
+<!-- TODO: full description for New Member Links -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Advanced Profiles
+
+Additional profile sections and selections
+<!-- TODO: full description for Advanced Profiles -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Profile Import/Export
+
+Save and load profile details across sites/channels
+<!-- TODO: full description for Profile Import/Export -->
+
+Minimum required technical skill level to see this feature: 3
+
+
+### Web Pages
+
+Provide managed web pages on your channel
+<!-- TODO: full description for Web Pages -->
+
+Minimum required technical skill level to see this feature: 3
+
+
+### Wiki
+
+Provide a wiki for your channel
+<!-- TODO: full description for Wiki -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Private Notes
+
+Enables a tool to store notes and reminders (note: not encrypted)
+<!-- TODO: full description for Private Notes -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Cards
+
+Create personal planning cards
+<!-- TODO: full description for Cards -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Articles
+
+Create interactive articles
+<!-- TODO: full description for Articles -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Navigation Channel Select
+
+Change channels directly from within the navigation dropdown menu
+<!-- TODO: full description for Navigation Channel Select -->
+
+Minimum required technical skill level to see this feature: 3
+
+
+### Photo Location
+
+If location data is available on uploaded photos, link this to a map.
+<!-- TODO: full description for Photo Location -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Access Controlled Chatrooms
+
+Provide chatrooms and chat services with access control.
+<!-- TODO: full description for Access Controlled Chatrooms -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Smart Birthdays
+
+Make birthday events timezone aware in case your friends are scattered across the planet.
+<!-- TODO: full description for Smart Birthdays -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Event Timezone Selection
+
+Allow event creation in timezones other than your own.
+<!-- TODO: full description for Event Timezone Selection -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Premium Channel
+
+Allows you to set restrictions and terms
+on those that connect with your channel
+<!-- TODO: full description for Premium Channel -->
+
+Minimum required technical skill level to see this feature: 4
+
+
+### Advanced Directory Search
+
+Allows creation of complex directory search queries
+<!-- TODO: full description for Advanced Directory Search -->
+
+Minimum required technical skill level to see this feature: 4
+
+
+### Advanced Theme and Layout Settings
+
+Allows fine tuning of themes and page layouts
+<!-- TODO: full description for Advanced Theme and Layout Settings -->
+
+Minimum required technical skill level to see this feature: 4
diff --git a/doc/feature/additional/overview.md b/doc/feature/additional/overview.md
new file mode 100644
index 000000000..b51f60bcd
--- /dev/null
+++ b/doc/feature/additional/overview.md
@@ -0,0 +1,33 @@
+[chset]: /settings "Channel Settings"
+[ftset]: /settings/features "Additional Features Settings"
+[ftgen]: /help/feature/additional/general "General Features"
+[ftacc]: /help/feature/additional/access "Access Control and Permissions"
+[ftcom]: /help/feature/additional/composition "Post Composition Features"
+[ftfil]: /help/feature/additional/filtering "Network and Stream Filtering"
+[ftpos]: /help/feature/additional/posts "Post/Comment Tools"
+
+
+# Additional Features
+
+<!-- TODO: Introduction to additional features -->
+
+<!-- TODO: Short info and crosslink on techlevels -->
+
+You can switch the features on and off from the
+[Additional Features][ftset] link in the [Channel Settings][chset].
+
+<!-- TODO: Infos about feature visibility and causes/dependencies -->
+
+The following pages decribe all the available features
+grouped in the same way as they are with the accordion tabs on the
+[Additional Features][ftset] settings page:
+
+[General Features][ftgen]
+
+[Access Control and Permissions][ftacc]
+
+[Post Composition Features][ftcom]
+
+[Network and Stream Filtering][ftfil]
+
+[Post/Comment Tools][ftpos]
diff --git a/doc/feature/additional/posts.md b/doc/feature/additional/posts.md
new file mode 100644
index 000000000..d3f6b37db
--- /dev/null
+++ b/doc/feature/additional/posts.md
@@ -0,0 +1,57 @@
+## Post/Comment Tools
+
+
+### Community Tagging
+
+Ability to tag existing posts
+<!-- TODO: full description for Community Tagging -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Post Categories
+
+Add categories to your posts
+<!-- TODO: full description for Post Categories -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Emoji Reactions
+
+Add emoji reaction ability to posts
+<!-- TODO: full description for Emoji Reactions -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Saved Folders
+
+Ability to file posts under folders
+<!-- TODO: full description for Saved Folders -->
+
+Minimum required technical skill level to see this feature: 2
+
+
+### Dislike Posts
+
+Ability to dislike posts/comments
+<!-- TODO: full description for Dislike Posts -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Star Posts
+
+Ability to mark special posts with a star indicator
+<!-- TODO: full description for Star Posts -->
+
+Minimum required technical skill level to see this feature: 1
+
+
+### Tag Cloud
+
+Provide a personal tag cloud on your channel page
+<!-- TODO: full description for Tag Cloud -->
+
+Minimum required technical skill level to see this feature: 2
diff --git a/doc/toc.html b/doc/toc.html
index f6ade61c7..9c3d22ab8 100644
--- a/doc/toc.html
+++ b/doc/toc.html
@@ -21,7 +21,8 @@
<div class="flex-column">
<a class="nav-link" href="/help/member/member_guide">Guide</a>
<a class="nav-link" href="/help/member/bbcode">BBcode Reference</a>
- <a class="nav-link" href="/help/bugs">Reporting Bugs</a>
+ <a class="nav-link" href="/help/feature/additional/overview">Additional Features</a>
+ <a class="nav-link" href="/help/bugs">Reporting Bugs</a>
<a class="nav-link" href="/help/member/member_faq">FAQ</a>
</div>
</div>
diff --git a/include/api.php b/include/api.php
index c91590070..6a05a40a5 100644
--- a/include/api.php
+++ b/include/api.php
@@ -193,26 +193,18 @@ require_once('include/api_zot.php');
$redirect = trim($_REQUEST['redirect_uris'][0]);
else
$redirect = trim($_REQUEST['redirect_uris']);
+ $grant_types = trim($_REQUEST['grant_types']);
+ $scope = trim($_REQUEST['scope']);
$icon = trim($_REQUEST['logo_uri']);
- if($oauth2) {
- $r = q("INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, grant_types, scope, user_id)
- VALUES ( '%s', '%s', '%s', null, null, null ) ",
- dbesc($key),
- dbesc($secret),
- dbesc($redirect)
- );
- }
- else {
- $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid)
- VALUES ('%s','%s','%s','%s','%s',%d)",
- dbesc($key),
- dbesc($secret),
- dbesc($name),
- dbesc($redirect),
- dbesc($icon),
- intval(0)
- );
- }
+ $r = q("INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, grant_types, scope, user_id)
+ VALUES ( '%s', '%s', '%s', '%s', '%s', '%s' ) ",
+ dbesc($key),
+ dbesc($secret),
+ dbesc($redirect),
+ dbesc($grant_types),
+ dbesc($scope),
+ dbesc((string) api_user())
+ );
$ret['client_id'] = $key;
$ret['client_secret'] = $secret;
diff --git a/include/bbcode.php b/include/bbcode.php
index 67f40dd23..152e4888f 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -780,10 +780,16 @@ function parseIdentityAwareHTML($Text) {
function bbcode($Text, $options = []) {
+ if(! is_array($options)) {
+ $options = [];
+ }
+
$preserve_nl = ((array_key_exists('preserve_nl',$options)) ? $options['preserve_nl'] : false);
$tryoembed = ((array_key_exists('tryoembed',$options)) ? $options['tryoembed'] : true);
$cache = ((array_key_exists('cache',$options)) ? $options['cache'] : false);
+ $newwin = ((array_key_exists('newwin',$options)) ? $options['newwin'] : true);
+ $target = (($newwin) ? ' target="_blank" ' : '');
call_hooks('bbcode_filter', $Text);
@@ -934,7 +940,7 @@ function bbcode($Text, $options = []) {
if($tryoembed) {
$Text = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", 'tryoembed', $Text);
}
- $Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" target="_blank" rel="nofollow noopener">$2</a>', $Text);
+ $Text = preg_replace("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/$urlchars+)/ismu", '$1<a href="$2" ' . $target . ' rel="nofollow noopener">$2</a>', $Text);
}
if (strpos($Text,'[/share]') !== false) {
@@ -946,16 +952,16 @@ function bbcode($Text, $options = []) {
}
}
if (strpos($Text,'[/url]') !== false) {
- $Text = preg_replace("/\#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\#\^\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
- $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\#\^\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<span class="bookmark-identifier">#^</span><a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}
if (strpos($Text,'[/zrl]') !== false) {
- $Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
- $Text = preg_replace("/\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<span class="bookmark-identifier">#^</span><a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}
if (get_account_techlevel() < 2)
@@ -963,8 +969,8 @@ function bbcode($Text, $options = []) {
// Perform MAIL Search
if (strpos($Text,'[/mail]') !== false) {
- $Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- $Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1" target="_blank" rel="nofollow noopener" >$2</a>', $Text);
+ $Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
}
@@ -1286,28 +1292,18 @@ function bbcode($Text, $options = []) {
// if video couldn't be embedded, link to it instead.
if (strpos($Text,'[/video]') !== false) {
- $Text = preg_replace("/\[video\](.*?)\[\/video\]/", '<a href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[video\](.*?)\[\/video\]/", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
}
if (strpos($Text,'[/audio]') !== false) {
- $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '<a href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
}
if (strpos($Text,'[/zvideo]') !== false) {
- $Text = preg_replace("/\[zvideo\](.*?)\[\/zvideo\]/", '<a class="zid" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
+ $Text = preg_replace("/\[zvideo\](.*?)\[\/zvideo\]/", '<a class="zid" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
}
if (strpos($Text,'[/zaudio]') !== false) {
- $Text = preg_replace("/\[zaudio\](.*?)\[\/zaudio\]/", '<a class="zid" href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
- }
-
-// if ($tryoembed){
-// if (strpos($Text,'[/iframe]') !== false) {
-// $Text = preg_replace_callback("/\[iframe\](.*?)\[\/iframe\]/ism", 'bb_iframe', $Text);
-// }
-// } else {
-// if (strpos($Text,'[/iframe]') !== false) {
-// $Text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<a href="$1" target="_blank" rel="nofollow noopener" >$1</a>', $Text);
-// }
-// }
+ $Text = preg_replace("/\[zaudio\](.*?)\[\/zaudio\]/", '<a class="zid" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
+ }
// oembed tag
$Text = oembed_bbcode2html($Text);
diff --git a/include/channel.php b/include/channel.php
index 460c818da..4a87ef602 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -780,7 +780,7 @@ function identity_basic_export($channel_id, $sections = null) {
}
}
- if(in_array('channel',$sections)) {
+ if(in_array('channel',$sections) || in_array('profile',$sections)) {
$r = q("select * from profile where uid = %d",
intval($channel_id)
);
diff --git a/include/conversation.php b/include/conversation.php
index 22eb2f6ad..93f7e11a7 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -1615,7 +1615,7 @@ function prepare_page($item) {
// prepare_body calls unobscure() as a side effect. Do it here so that
// the template will get passed an unobscured title.
- $body = prepare_body($item, true);
+ $body = prepare_body($item, [ 'newwin' => false ]);
if(App::$page['template'] == 'none') {
$tpl = 'page_display_empty.tpl';
diff --git a/include/features.php b/include/features.php
index 5481c37a4..4859a01db 100644
--- a/include/features.php
+++ b/include/features.php
@@ -246,14 +246,23 @@ function get_features($filtered = true) {
[
'oauth_clients',
- t('OAuth Clients'),
- t('Manage authenticatication tokens for mobile and remote apps.'),
+ t('OAuth1 Clients'),
+ t('Manage OAuth1 authenticatication tokens for mobile and remote apps.'),
false,
get_config('feature_lock','oauth_clients'),
feature_level('oauth_clients',1),
],
[
+ 'oauth2_clients',
+ t('OAuth2 Clients'),
+ t('Manage OAuth2 authenticatication tokens for mobile and remote apps.'),
+ false,
+ get_config('feature_lock','oauth2_clients'),
+ feature_level('oauth2_clients',1),
+ ],
+
+ [
'access_tokens',
t('Access Tokens'),
t('Create access tokens so that non-members can access private content.'),
diff --git a/include/help.php b/include/help.php
index 0dc37e517..ce389b4db 100644
--- a/include/help.php
+++ b/include/help.php
@@ -306,7 +306,7 @@ function store_doc_file($s) {
require_once('include/html2plain.php');
- $item['body'] = html2plain(prepare_text(file_get_contents($s),$mimetype, true));
+ $item['body'] = html2plain(prepare_text(file_get_contents($s),$mimetype, [ 'cache' => true ]));
$item['mimetype'] = 'text/plain';
$item['plink'] = z_root() . '/' . str_replace('doc','help',$s);
diff --git a/include/import.php b/include/import.php
index d8b7030b6..0d3fb8c32 100644
--- a/include/import.php
+++ b/include/import.php
@@ -99,7 +99,7 @@ function import_channel($channel, $account_id, $seize) {
}
if($clean) {
- create_table_from_array('channel',$clean);
+ channel_store_lowlevel($clean);
}
$r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1",
@@ -180,7 +180,7 @@ function import_profiles($channel, $profiles) {
$profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']);
}
- create_table_from_array('profile', $profile);
+ profile_store_lowlevel($profile);
}
}
}
diff --git a/include/network.php b/include/network.php
index a49e5920d..db9a7d00a 100644
--- a/include/network.php
+++ b/include/network.php
@@ -1607,6 +1607,7 @@ function get_site_info() {
'register_policy' => $register_policy[get_config('system','register_policy')],
'invitation_only' => (bool) intval(get_config('system','invitation_only')),
'directory_mode' => $directory_mode[get_config('system','directory_mode')],
+ 'directory_server' => get_config('system','directory_server'),
'language' => get_config('system','language'),
'rss_connections' => (bool) intval(get_config('system','feed_contacts')),
'expiration' => $site_expire,
diff --git a/include/text.php b/include/text.php
index f634f0d55..255d02c7c 100644
--- a/include/text.php
+++ b/include/text.php
@@ -1588,7 +1588,7 @@ function generate_named_map($location) {
}
-function prepare_body(&$item,$attach = false) {
+function prepare_body(&$item,$attach = false,$opts = false) {
call_hooks('prepare_body_init', $item);
@@ -1616,7 +1616,7 @@ function prepare_body(&$item,$attach = false) {
$s .= prepare_binary($item);
}
else {
- $s .= prepare_text($item['body'],$item['mimetype'], false);
+ $s .= prepare_text($item['body'],$item['mimetype'], $opts);
}
$event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event_obj($item['obj']) : false);
@@ -1698,7 +1698,8 @@ function prepare_binary($item) {
*
* @return string
*/
-function prepare_text($text, $content_type = 'text/bbcode', $cache = false) {
+function prepare_text($text, $content_type = 'text/bbcode', $opts = false) {
+
switch($content_type) {
case 'text/plain':
@@ -1742,7 +1743,7 @@ function prepare_text($text, $content_type = 'text/bbcode', $cache = false) {
if(stristr($text,'[nosmile]'))
$s = bbcode($text, [ 'cache' => $cache ]);
else
- $s = smilies(bbcode($text, [ 'cache' => $cache ]));
+ $s = smilies(bbcode($text, ((is_array($opts)) ? $opts : [] )));
$s = zidify_links($s);
@@ -2576,6 +2577,9 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
// The @! tag will alter permissions
$exclusive = (((! $grouptag) && (strpos($tag,'!') === 1) && (! $diaspora)) ? true : false);
+ if(($grouptag) && (strpos($tag,'!!') === 0)) {
+ $exclusive = true;
+ }
//is it already replaced?
if(strpos($tag,'[zrl='))
@@ -2748,8 +2752,8 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
$profile = str_replace(',','%2c',$profile);
$url = $profile;
if($grouptag) {
- $newtag = '!' . '[zrl=' . $profile . ']' . $newname . '[/zrl]';
- $body = str_replace('!' . $name, $newtag, $body);
+ $newtag = '!' . (($exclusive) ? '!' : '') . '[zrl=' . $profile . ']' . $newname . '[/zrl]';
+ $body = str_replace('!' . (($exclusive) ? '!' : '') . $name, $newtag, $body);
}
else {
$newtag = '@' . (($exclusive) ? '!' : '') . '[zrl=' . $profile . ']' . $newname . (($forum && ! $trailing_plus_name) ? '+' : '') . '[/zrl]';
@@ -2799,6 +2803,7 @@ function linkify_tags($a, &$body, $uid, $diaspora = false) {
continue;
$success = handle_tag($a, $body, $access_tag, $str_tags, ($uid) ? $uid : App::$profile_uid , $tag, $diaspora);
+
$results[] = array('success' => $success, 'access_tag' => $access_tag);
if($success['replaced']) $tagged[] = $tag;
}
diff --git a/include/zot.php b/include/zot.php
index 25ea9b8fb..2ad43f0e5 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -3855,11 +3855,14 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
intval($channel['channel_id'])
);
if(! $x) {
- q("insert into profile ( profile_guid, aid, uid ) values ('%s', %d, %d)",
- dbesc($profile['profile_guid']),
- intval($channel['channel_account_id']),
- intval($channel['channel_id'])
+ profile_store_lowlevel(
+ [
+ 'aid' => $channel['channel_account_id'],
+ 'uid' => $channel['channel_id'],
+ 'profile_guid' => $profile['profile_guid'],
+ ]
);
+
$x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1",
dbesc($profile['profile_guid']),
intval($channel['channel_id'])
diff --git a/view/js/autocomplete.js b/view/js/autocomplete.js
index 7a1a7673d..07b9bc449 100644
--- a/view/js/autocomplete.js
+++ b/view/js/autocomplete.js
@@ -198,7 +198,7 @@ function string2bb(element) {
// Autocomplete forums
forums = {
- match: /(^|\s)(\!)([^ \n]+)$/,
+ match: /(^|\s)(\!\!*)([^ \n]+)$/,
index: 3,
search: function(term, callback) { contact_search(term, callback, backend_url, 'f', extra_channels, spinelement=false); },
replace: editor_replace,
diff --git a/view/tpl/cloud_header.tpl b/view/tpl/cloud_header.tpl
index 307dc8956..642fb1866 100644
--- a/view/tpl/cloud_header.tpl
+++ b/view/tpl/cloud_header.tpl
@@ -6,7 +6,7 @@
<a href="/sharedwithme" class="btn btn-sm btn-outline-secondary"><i class="fa fa-cloud-download"></i>&nbsp;{{$shared}}</a>
{{/if}}
<button id="files-create-btn" class="btn btn-sm btn-primary" onclick="openClose('files-mkdir-tools'); closeMenu('files-upload-tools');"><i class="fa fa-folder-o"></i>&nbsp;{{$create}}</button>
- <button id="files-upload-btn" class="btn btn-sm btn-success" onclick="openClose('files-upload-tools'); closeMenu('files-mkdir-tools');"><i class="fa fa-arrow-circle-o-up"></i>&nbsp;{{$upload}}</button>
+ <button id="files-upload-btn" class="btn btn-sm btn-success" onclick="openClose('files-upload-tools'); closeMenu('files-mkdir-tools');"><i class="fa fa-plus-circle"></i>&nbsp;{{$upload}}</button>
{{/if}}
</div>
diff --git a/view/tpl/photo_album.tpl b/view/tpl/photo_album.tpl
index 678e790ac..de59809f4 100755
--- a/view/tpl/photo_album.tpl
+++ b/view/tpl/photo_album.tpl
@@ -9,7 +9,7 @@
<i class="fa fa-pencil btn btn-outline-secondary btn-sm" title="{{$album_edit.0}}" onclick="openClose('photo-album-edit-wrapper'); closeMenu('photo-upload-form');"></i>
{{/if}}
{{if $can_post}}
- <button class="btn btn-sm btn-success btn-sm" title="{{$usage}}" onclick="openClose('photo-upload-form'); {{if $album_edit.1}}closeMenu('photo-album-edit-wrapper');{{/if}}"><i class="fa fa-arrow-circle-o-up"></i>&nbsp;{{$upload.0}}</button>
+ <button class="btn btn-sm btn-success btn-sm" title="{{$usage}}" onclick="openClose('photo-upload-form'); {{if $album_edit.1}}closeMenu('photo-album-edit-wrapper');{{/if}}"><i class="fa fa-plus-circle"></i>&nbsp;{{$upload.0}}</button>
{{/if}}
</div>
</div>
diff --git a/view/tpl/photos_recent.tpl b/view/tpl/photos_recent.tpl
index a9574aade..d24b362f8 100755
--- a/view/tpl/photos_recent.tpl
+++ b/view/tpl/photos_recent.tpl
@@ -2,7 +2,7 @@
<div class="section-title-wrapper">
<div class="pull-right">
{{if $can_post}}
- <button class="btn btn-sm btn-success acl-form-trigger" title="{{$usage}}" onclick="openClose('photo-upload-form');" data-form_id="photos-upload-form"><i class="fa fa-arrow-circle-o-up"></i>&nbsp;{{$upload.0}}</button>
+ <button class="btn btn-sm btn-success acl-form-trigger" title="{{$usage}}" onclick="openClose('photo-upload-form');" data-form_id="photos-upload-form"><i class="fa fa-plus-circle"></i>&nbsp;{{$upload.0}}</button>
{{/if}}
</div>
<h2>{{$title}}</h2>
diff --git a/view/tpl/settings_oauth2.tpl b/view/tpl/settings_oauth2.tpl
new file mode 100755
index 000000000..882d34ea9
--- /dev/null
+++ b/view/tpl/settings_oauth2.tpl
@@ -0,0 +1,35 @@
+<div class="generic-content-wrapper">
+<div class="section-title-wrapper">
+ <h2>{{$title}}</h2>
+</div>
+
+<div class="section-content-tools-wrapper">
+<form action="settings/oauth2" method="post" autocomplete="off">
+<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
+
+ <div id="profile-edit-links">
+ <ul>
+ <li>
+ <a id="profile-edit-view-link" href="{{$baseurl}}/settings/oauth2/add">{{$add}}</a>
+ </li>
+ </ul>
+ </div>
+
+ {{foreach $apps as $app}}
+ <div class='oauthapp'>
+ {{if $app.client_id}}<h4>{{$app.client_id}}</h4>{{else}}<h4>{{$noname}}</h4>{{/if}}
+ {{if $app.my}}
+ {{if $app.oauth_token}}
+ <div class="settings-submit-wrapper" ><button class="settings-submit" type="submit" name="remove" value="{{$app.oauth_token}}">{{$remove}}</button></div>
+ {{/if}}
+ {{/if}}
+ {{if $app.my}}
+ <a href="{{$baseurl}}/settings/oauth2/edit/{{$app.client_id}}" title="{{$edit}}"><i class="fa fa-pencil btn btn-outline-secondary"></i></a>
+ <a href="{{$baseurl}}/settings/oauth2/delete/{{$app.client_id}}?t={{$form_security_token}}" title="{{$delete}}"><i class="fa fa-trash-o btn btn-outline-secondary"></i></a>
+ {{/if}}
+ </div>
+ {{/foreach}}
+
+</form>
+</div>
+</div>
diff --git a/view/tpl/settings_oauth2_edit.tpl b/view/tpl/settings_oauth2_edit.tpl
new file mode 100755
index 000000000..399c64977
--- /dev/null
+++ b/view/tpl/settings_oauth2_edit.tpl
@@ -0,0 +1,21 @@
+<div class="generic-content-wrapper">
+ <div class="section-title-wrapper">
+ <h2>{{$title}}</h2>
+ </div>
+<div class="section-content-tools-wrapper">
+<form method="POST">
+<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
+{{include file="field_input.tpl" field=$name}}
+{{include file="field_input.tpl" field=$secret}}
+{{include file="field_input.tpl" field=$redirect}}
+{{include file="field_input.tpl" field=$grant}}
+{{include file="field_input.tpl" field=$scope}}
+
+<div class="settings-submit-wrapper" >
+<input type="submit" name="submit" class="settings-submit" value="{{$submit}}" />
+<input type="submit" name="cancel" class="settings-submit" value="{{$cancel}}" />
+</div>
+
+</form>
+</div>
+</div>
diff --git a/view/tpl/settings_oauth_edit.tpl b/view/tpl/settings_oauth_edit.tpl
index b94dec48a..e44b44723 100755
--- a/view/tpl/settings_oauth_edit.tpl
+++ b/view/tpl/settings_oauth_edit.tpl
@@ -5,7 +5,6 @@
<div class="section-content-tools-wrapper">
<form method="POST">
<input type='hidden' name='form_security_token' value='{{$form_security_token}}'>
-
{{include file="field_input.tpl" field=$name}}
{{include file="field_input.tpl" field=$key}}
{{include file="field_input.tpl" field=$secret}}