aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/account.php143
-rw-r--r--include/acl_selectors.php2
-rw-r--r--include/api_zot.php3
-rw-r--r--include/attach.php149
-rw-r--r--include/auth.php52
-rw-r--r--include/bbcode.php31
-rw-r--r--include/channel.php45
-rw-r--r--include/cli_startup.php4
-rw-r--r--include/config.php67
-rw-r--r--include/connections.php19
-rw-r--r--include/contact_widgets.php3
-rw-r--r--include/conversation.php75
-rw-r--r--include/crypto.php8
-rw-r--r--include/datetime.php41
-rw-r--r--include/dba/dba_pdo.php112
-rw-r--r--include/event.php138
-rw-r--r--include/features.php90
-rw-r--r--include/feedutils.php67
-rw-r--r--include/help.php203
-rw-r--r--include/html2bbcode.php33
-rw-r--r--include/html2plain.php8
-rw-r--r--include/hubloc.php9
-rw-r--r--include/import.php11
-rw-r--r--include/items.php674
-rw-r--r--include/js_strings.php31
-rw-r--r--include/language.php11
-rw-r--r--include/markdown.php16
-rw-r--r--include/menu.php7
-rw-r--r--include/nav.php42
-rw-r--r--include/network.php228
-rw-r--r--include/oauth.php60
-rw-r--r--include/oauth2.php10
-rw-r--r--include/oembed.php37
-rw-r--r--include/permissions.php12
-rw-r--r--include/photo/photo_driver.php7
-rw-r--r--include/photos.php70
-rw-r--r--include/plugin.php40
-rw-r--r--include/security.php115
-rw-r--r--include/socgraph.php3
-rw-r--r--include/statistics_fns.php22
-rw-r--r--include/taxonomy.php4
-rw-r--r--include/text.php137
-rw-r--r--include/xchan.php6
-rw-r--r--include/zid.php44
44 files changed, 1580 insertions, 1309 deletions
diff --git a/include/account.php b/include/account.php
index a1fb0f159..615c802f4 100644
--- a/include/account.php
+++ b/include/account.php
@@ -4,6 +4,7 @@
* @brief Somme account related functions.
*/
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Crypto;
require_once('include/config.php');
@@ -83,8 +84,8 @@ function check_account_invite($invite_code) {
$result = array('error' => false, 'message' => '');
// [hilmar ->
- $using_invites = (get_config('system','invitation_only')
- || get_config('system','invitation_also'));
+ $using_invites = (Config::Get('system','invitation_only')
+ || Config::Get('system','invitation_also'));
if($using_invites) {
@@ -118,7 +119,7 @@ function check_account_invite($invite_code) {
function check_account_admin($arr) {
if(is_site_admin())
return true;
- $admin_email = trim(get_config('system','admin_email'));
+ $admin_email = trim(Config::Get('system','admin_email'));
if(strlen($admin_email) && $admin_email === trim($arr['email']))
return true;
return false;
@@ -182,7 +183,7 @@ function create_account_IS_OBSOLETE($arr) {
$roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 );
$expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE);
- $default_service_class = get_config('system','default_service_class');
+ $default_service_class = Config::Get('system','default_service_class');
if($default_service_class === false)
$default_service_class = '';
@@ -209,10 +210,10 @@ function create_account_IS_OBSOLETE($arr) {
// Ensure that there is a host keypair.
- if ((! get_config('system', 'pubkey')) && (! get_config('system', 'prvkey'))) {
+ if ((! Config::Get('system', 'pubkey')) && (! Config::Get('system', 'prvkey'))) {
$hostkey = Crypto::new_keypair(4096);
- set_config('system', 'pubkey', $hostkey['pubkey']);
- set_config('system', 'prvkey', $hostkey['prvkey']);
+ Config::Set('system', 'pubkey', $hostkey['pubkey']);
+ Config::Set('system', 'prvkey', $hostkey['prvkey']);
}
$invite_result = check_account_invite($invite_code);
@@ -319,7 +320,7 @@ function create_account_from_register($arr) {
// account
$expires = NULL_DATE;
- $default_service_class = get_config('system','default_service_class');
+ $default_service_class = Config::Get('system','default_service_class');
if($default_service_class === false)
$default_service_class = '';
@@ -420,7 +421,7 @@ function verify_email_address($arr) {
$email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'),
[
- '$sitename' => get_config('system','sitename'),
+ '$sitename' => Config::Get('system','sitename'),
'$siteurl' => z_root(),
'$email' => $arr['email'],
'$uid' => 1,
@@ -432,7 +433,7 @@ function verify_email_address($arr) {
$res = z_mail(
[
'toEmail' => $arr['email'],
- 'messageSubject' => sprintf( t('Registration confirmation for %s'), get_config('system','sitename')),
+ 'messageSubject' => sprintf( t('Registration confirmation for %s'), Config::Get('system','sitename')),
'textVersion' => $email_msg,
]
);
@@ -488,7 +489,7 @@ function verify_email_addressNOP($arr) {
$email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'),
[
- '$sitename' => get_config('system','sitename'),
+ '$sitename' => Config::Get('system','sitename'),
'$siteurl' => z_root(),
'$email' => $arr['email'],
'$uid' => $account['account_id'],
@@ -500,7 +501,7 @@ function verify_email_addressNOP($arr) {
$res = z_mail(
[
'toEmail' => $arr['email'],
- 'messageSubject' => sprintf( t('Registration confirmation for %s'), get_config('system','sitename')),
+ 'messageSubject' => sprintf( t('Registration confirmation for %s'), Config::Get('system','sitename')),
'textVersion' => $email_msg,
]
);
@@ -564,7 +565,7 @@ function send_reg_approval_email($arr) {
push_lang('en');
$email_msg = replace_macros(get_intltext_template('register_verify_eml.tpl'), array(
- '$sitename' => get_config('system','sitename'),
+ '$sitename' => Config::Get('system','sitename'),
'$siteurl' => z_root(),
'$email' => $arr['email'],
'$uid' => $arr['account']['account_id'],
@@ -575,7 +576,7 @@ function send_reg_approval_email($arr) {
$res = z_mail(
[
'toEmail' => $admin['email'],
- 'messageSubject' => sprintf( t('Registration request at %s'), get_config('system','sitename')),
+ 'messageSubject' => sprintf( t('Registration request at %s'), Config::Get('system','sitename')),
'textVersion' => $email_msg,
]
);
@@ -594,7 +595,7 @@ function send_reg_approval_email($arr) {
function send_register_success_email($email,$password) {
$email_msg = replace_macros(get_intltext_template('register_open_eml.tpl'), array(
- '$sitename' => get_config('system','sitename'),
+ '$sitename' => Config::Get('system','sitename'),
'$siteurl' => z_root(),
'$email' => $email,
'$password' => t('your registration password'),
@@ -603,7 +604,7 @@ function send_register_success_email($email,$password) {
$res = z_mail(
[
'toEmail' => $email,
- 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')),
+ 'messageSubject' => sprintf( t('Registration details for %s'), Config::Get('system','sitename')),
'textVersion' => $email_msg,
]
);
@@ -612,59 +613,45 @@ function send_register_success_email($email,$password) {
}
/**
- * @brief Allows a user registration.
+ * Mark a pending registration as approved, and notify the account
+ * holder by email.
*
- * @param string $hash
- * @return array|boolean
+ * @param string $hash The registration hash of the entry to approve
+ *
+ * @return bool
*/
-function account_allow($hash) {
-
- $ret = array('success' => false);
+function account_allow(string $hash): bool {
$register = q("SELECT * FROM register WHERE reg_hash = '%s' LIMIT 1",
dbesc($hash)
);
- if(! $register)
- return $ret;
+ if (! $register) {
+ logger(
+ "Entry with hash '{$hash}' was not found in the register table.",
+ LOGGER_NORMAL,
+ LOG_ERR
+ );
+ return false;
+ }
- $account = q("SELECT * FROM account WHERE account_id = %d LIMIT 1",
- intval($register[0]['reg_uid'])
- );
+ $account = get_account_by_id($register[0]['reg_uid']);
- // a register entry without account assigned to
- if(! $account)
- return $ret;
+ if (! $account) {
+ logger(
+ "Account '{$register[0]['reg_uid']}' mentioned by registration hash '{$hash}' was not found.",
+ LOGGER_NORMAL,
+ LOG_ERR
+ );
+ return false;
+ }
- // [hilmar ->
+ $transaction = new DbaTransaction(DBA::$dba);
- q("START TRANSACTION");
- //q("DELETE FROM register WHERE reg_hash = '%s'",
- // dbesc($register[0]['reg_hash'])
- //);
$r1 = q("UPDATE register SET reg_vital = 0 WHERE reg_hash = '%s'",
dbesc($register[0]['reg_hash'])
);
- /* instead of ...
-
- // unblock
- q("UPDATE account SET account_flags = (account_flags & ~%d) "
- . " WHERE (account_flags & %d)>0 AND account_id = %d",
- intval(ACCOUNT_BLOCKED),
- intval(ACCOUNT_BLOCKED),
- intval($register[0]['reg_uid'])
- );
-
- // unpend
- q("UPDATE account SET account_flags = (account_flags & ~%d) "
- . " WHERE (account_flags & %d)>0 AND account_id = %d",
- intval(ACCOUNT_PENDING),
- intval(ACCOUNT_PENDING),
- intval($register[0]['reg_uid'])
- );
-
- */
// together unblock and unpend
$r2 = q("UPDATE account SET account_flags = %d WHERE account_id = %d",
intval($account['account_flags']
@@ -673,45 +660,43 @@ function account_allow($hash) {
);
if($r1 && $r2) {
- q("COMMIT");
-
- // <- hilmar]
+ $transaction->commit();
push_lang($register[0]['reg_lang']);
$email_tpl = get_intltext_template("register_open_eml.tpl");
$email_msg = replace_macros($email_tpl, array(
- '$sitename' => get_config('system','sitename'),
+ '$sitename' => Config::Get('system','sitename'),
'$siteurl' => z_root(),
- '$username' => $account[0]['account_email'],
- '$email' => $account[0]['account_email'],
+ '$username' => $account['account_email'],
+ '$email' => $account['account_email'],
'$password' => '',
- '$uid' => $account[0]['account_id']
+ '$uid' => $account['account_id']
));
$res = z_mail(
[
- 'toEmail' => $account[0]['account_email'],
- 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')),
+ 'toEmail' => $account['account_email'],
+ 'messageSubject' => sprintf( t('Registration details for %s'), Config::Get('system','sitename')),
'textVersion' => $email_msg,
]
);
- pop_lang();
+ if (! $res) {
+ info(t("Sending account approval email to {$account['email']} failed..."));
+ }
- if(get_config('system', 'auto_channel_create', 1))
- auto_channel_create($register[0]['uid']);
+ pop_lang();
- if ($res) {
- info( t('Account approved.') . EOL );
- return true;
+ if(Config::Get('system', 'auto_channel_create', 1)) {
+ auto_channel_create($register[0]['reg_uid']);
}
- // [hilmar ->
- } else {
- q("ROLLBACK");
+ info( t('Account approved.') . EOL );
+ return true;
}
- // <- hilmar]
+
+ return false;
}
@@ -844,7 +829,7 @@ function account_approve($hash) {
if(! $account)
return $ret;
- if(get_config('system','auto_channel_create'))
+ if(Config::Get('system','auto_channel_create'))
auto_channel_create($register[0]['reg_uid']);
else {
$_SESSION['login_return_url'] = 'new_channel';
@@ -992,7 +977,7 @@ function downgrade_accounts() {
if(! $r)
return;
- $basic = get_config('system','default_service_class');
+ $basic = Config::Get('system','default_service_class');
foreach($r as $rr) {
if(($basic) && ($rr['account_service_class']) && ($rr['account_service_class'] != $basic)) {
@@ -1135,7 +1120,7 @@ function service_class_fetch($uid, $property) {
if(! x($service_class))
return false; // everything is allowed
- $arr = get_config('service_class', $service_class);
+ $arr = Config::Get('service_class', $service_class);
if(! is_array($arr) || (! count($arr)))
return false;
@@ -1169,7 +1154,7 @@ function account_service_class_fetch($aid, $property) {
if(! isset($service_class))
return false; // everything is allowed
- $arr = get_config('service_class', $service_class);
+ $arr = Config::Get('service_class', $service_class);
if(! is_array($arr) || (! count($arr)))
return false;
@@ -1179,7 +1164,7 @@ function account_service_class_fetch($aid, $property) {
function upgrade_link($bbcode = false) {
- $l = get_config('service_class', 'upgrade_link');
+ $l = Config::Get('service_class', 'upgrade_link');
if(! $l)
return '';
if($bbcode)
@@ -1208,7 +1193,7 @@ function get_account_techlevel($account_id = 0) {
function zar_log($msg='') {
- if(get_config('system', 'register_logfile', 0)) {
+ if(Config::Get('system', 'register_logfile', 0)) {
file_put_contents('./zar.log',
date('Y-m-d_H:i:s') . ' ' . $msg . ', ip: § ' . $_SERVER['REMOTE_ADDR'] . ' §' . "\n", FILE_APPEND);
}
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index f158a439b..f0e0140dc 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -26,7 +26,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
$allow_cid = $allow_gid = $deny_cid = $deny_gid = false;
$showall_origin = '';
- $showall_icon = 'fa-globe';
+ $showall_icon = 'bi-globe';
$role = get_pconfig(local_channel(), 'system', 'permissions_role');
if(! $emptyACL_description) {
diff --git a/include/api_zot.php b/include/api_zot.php
index 22692b962..56cec005d 100644
--- a/include/api_zot.php
+++ b/include/api_zot.php
@@ -546,6 +546,7 @@
return false;
}
+
logger('api_red_item_store: REQUEST ' . print_r($_REQUEST,true));
logger('api_red_item_store: FILES ' . print_r($_FILES,true));
@@ -561,7 +562,7 @@
$mod = new Zotlabs\Module\Wall_attach();
$media = $mod->post();
if($media)
- $_REQUEST['body'] = $media . "\n\n" . $_REQUEST['body'];
+ $_REQUEST['body'] = $media . "\n" . $_REQUEST['body'];
}
$mod = new Zotlabs\Module\Item();
diff --git a/include/attach.php b/include/attach.php
index e5a2900b3..bda4905f1 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -11,11 +11,12 @@
* @todo Also an 'append' option to the storage function might be a useful addition.
*/
-use Zotlabs\Lib\Libsync;
-use Zotlabs\Lib\Activity;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\AccessList;
+use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Config;
+use Zotlabs\Lib\Libsync;
require_once('include/permissions.php');
require_once('include/security.php');
@@ -112,7 +113,6 @@ function z_mime_content_type($filename) {
'odf' => 'application/vnd.oasis.opendocument.formula',
'odi' => 'application/vnd.oasis.opendocument.image',
'odm' => 'application/vnd.oasis.opendocument.text-master',
- 'odb' => 'application/vnd.oasis.opendocument.base',
'odb' => 'application/vnd.oasis.opendocument.database',
'ott' => 'application/vnd.oasis.opendocument.text-template',
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
@@ -801,7 +801,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
// Check storage limits
if($options !== 'update') {
- $maxfilesize = get_config('system','maxfilesize');
+ $maxfilesize = Config::Get('system','maxfilesize');
if(($maxfilesize) && ($filesize > $maxfilesize)) {
logger('quota_exceeded');
@@ -1606,8 +1606,7 @@ function attach_drop_photo($channel_id,$resource) {
if($x) {
$stage = (($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
- $interactive = (($x[0]['item_hidden']) ? false : true);
- drop_item($x[0]['id'], $interactive, $stage);
+ drop_item($x[0]['id'], $stage);
}
$r = q("SELECT content FROM photo WHERE resource_id = '%s' AND uid = %d AND os_storage = 1",
@@ -1636,8 +1635,7 @@ function attach_drop_item($channel_id,$resource) {
if($x) {
$stage = (($x[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
- $interactive = (($x[0]['item_hidden']) ? false : true);
- drop_item($x[0]['id'], $interactive, $stage);
+ drop_item($x[0]['id'], $stage);
}
}
@@ -1855,8 +1853,6 @@ function pipe_streams($in, $out, $bufsize = 16384) {
}
function attach_store_item($channel, $observer, $file) {
-
-
if(is_string($file)) {
$r = q("SELECT * FROM attach WHERE uid = %d AND hash = '%s' LIMIT 1",
intval($channel['channel_id']),
@@ -1906,10 +1902,11 @@ function attach_store_item($channel, $observer, $file) {
$post = item_store($arr);
- $item_id = $post['item_id'];
-
- if($item_id) {
- Master::Summon(['Notifier', 'activity', $item_id]);
+ if ($post['success']) {
+ Master::Summon(['Notifier', 'activity', $post['item_id']]);
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'activity', $post['approval_id']]);
+ }
}
*/
@@ -1919,8 +1916,11 @@ function attach_store_item($channel, $observer, $file) {
}
$stage = (($r[0]['item_hidden']) ? DROPITEM_NORMAL : DROPITEM_PHASE1);
- $interactive = (($r[0]['item_hidden']) ? false : true);
- drop_item($r[0]['id'], $interactive, $stage);
+ drop_item($r[0]['id'], $stage);
+
+ if (empty($r[0]['item_hidden'])) {
+ Master::Summon(['Notifier', 'drop', $r[0]['id']]);
+ }
}
@@ -1945,6 +1945,12 @@ function attach_store_item($channel, $observer, $file) {
$mid = z_root() . '/item/' . $uuid;
+ $target = [
+ 'id' => z_root() . '/conversation/' . $uuid,
+ 'type' => 'Collection',
+ 'attributedTo' => channel_url($channel),
+ ];
+
$arr = []; // Initialize the array of parameters for the post
$arr['aid'] = $channel['channel_account_id'];
$arr['uuid'] = $uuid;
@@ -1965,6 +1971,8 @@ function attach_store_item($channel, $observer, $file) {
$arr['item_thread_top'] = 1;
$arr['item_private'] = (($file['allow_cid'] || $file['allow_gid'] || $file['deny_cid'] || $file['deny_gid']) ? 1 : 0);
$arr['verb'] = 'Create';
+ $arr['target'] = $target;
+ $arr['target_type'] = 'Collection';
$arr['obj_type'] = $type;
$arr['title'] = $file['filename'];
@@ -1982,14 +1990,13 @@ function attach_store_item($channel, $observer, $file) {
}
$body_str = sprintf((($type === 'Image') ? t('%s shared an %s with you') : t('%s shared a %s with you')), '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]', '[zrl=' . $path . ']' . (($type === 'Image') ? t('image') : t('file')) . '[/zrl]');
- $arr['body'] .= $body_str;
+ $arr['body'] .= "\r\n" . $body_str;
$meta = [
'name' => $file['filename'],
'type' => $file['filetype'],
'size' => $file['filesize'],
'revision' => $file['revision'],
- 'size' => $file['filesize'],
'created' => $file['created'],
'edited' => $file['edited'],
'path' => $path
@@ -1999,10 +2006,11 @@ function attach_store_item($channel, $observer, $file) {
$post = item_store($arr);
- $item_id = $post['item_id'];
-
- if($item_id) {
- Master::Summon(['Notifier', 'activity', $item_id]);
+ if ($post['success']) {
+ Master::Summon(['Notifier', 'activity', $post['item_id']]);
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'activity', $post['approval_id']]);
+ }
}
}
@@ -2466,8 +2474,8 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat
* @param int $channel_id
* @param int $resource_id
* @param string $new_folder_hash
- * @param (optional) string $newname
- * @param (optional) boolean $recurse
+ * @param string (optional) $newname
+ * @param boolean (optional) $recurse
* @return array Associative array with:
* * \e boolean \b success
* * \e string \b resource_id
@@ -2599,33 +2607,31 @@ function attach_move($channel_id, $resource_id, $new_folder_hash, $newname = '',
intval($r[0]['id'])
);
- if($r[0]['is_photo']) {
- q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
- where resource_id = '%s' and uid = %d",
- dbesc($newalbumname),
- dbesc($filename),
- dbesc($x['os_path']),
- dbesc($x['path']),
- dbesc($resource_id),
- intval($channel_id)
- );
-
- q("update photo set content = CASE imgscale WHEN 0 THEN %s ELSE CONCAT(%s, '-', imgscale) END where resource_id = '%s' and uid = %d and os_storage = 1",
- dbescbin($newstorepath),
- dbescbin($newstorepath),
- dbesc($resource_id),
- intval($channel_id)
- );
-
- // now rename the thumbnails in os_storage - the original should have been copied before already
- $ps = q("SELECT content, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 and os_storage = 1",
+ if ($r[0]['is_photo']) {
+ // update the photo DB entries and copy the thumbnails
+ $ps = q("SELECT imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and os_storage = 1",
intval($channel_id),
dbesc($resource_id)
);
if ($recurse) {
foreach($ps as $p) {
- rename($oldstorepath . '-' . $p['imgscale'], $p['content']);
+ q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s', content = '%s'
+ where resource_id = '%s' and imgscale = %d and uid = %d",
+ dbesc($newalbumname),
+ dbesc($filename),
+ dbesc($x['os_path']),
+ dbesc($x['path']),
+ dbescbin($newstorepath . ((intval($p['imgscale']) > 0) ? '-' . $p['imgscale'] : '')),
+ dbesc($resource_id),
+ intval($p['imgscale']),
+ intval($channel_id)
+ );
+
+ // the original should have been copied already
+ if (intval($p['imgscale']) > 0) {
+ rename($oldstorepath . '-' . $p['imgscale'], $newstorepath . '-' . $p['imgscale']);
+ }
}
}
}
@@ -2667,8 +2673,8 @@ function attach_move($channel_id, $resource_id, $new_folder_hash, $newname = '',
* @param int $channel_id
* @param int $resource_id
* @param string $new_folder_hash
- * @param (optional) string $newname
- * @param (optional) boolean $recurse
+ * @param string (optional) $newname
+ * @param boolean (optional) $recurse
* @return array Associative array with:
* * \e boolean \b success
* * \e string \b resource_id of the new resource
@@ -2935,41 +2941,6 @@ function attach_syspaths($channel_id,$attach_hash) {
return [ 'os_path' => $os_path, 'path' => $path ];
}
-/**
- * in earlier releases we did not fill in os_path and display_path in the attach DB structure.
- * (It was not needed or used). Going forward we intend to make use of these fields.
- * A cron task checks for empty values (as older attachments may have arrived at our site
- * in a clone operation) and executes attach_syspaths() to generate these field values and correct
- * the attach table entry. The operation is limited to 100 DB entries at a time so as not to
- * overload the system in any cron run. Eventually it will catch up with old attach structures
- * and switch into maintenance mode to correct any that might arrive in clone packets from older
- * sites.
- */
-
-
-
-function attach_upgrade() {
- $r = q("SELECT id, uid, hash FROM attach WHERE os_path = '' OR display_path = '' LIMIT 100");
- if($r) {
- foreach($r as $rv) {
- $x = attach_syspaths($rv['uid'],$rv['hash']);
- if($x) {
- q("update attach set os_path = '%s', display_path = '%s' where id = %d",
- dbesc($x['os_path']),
- dbesc($x['path']),
- intval($rv['id'])
- );
- q("update photo set os_path = '%s', display_path = '%s' where uid = %d and resource_id = '%s'",
- dbesc($x['os_path']),
- dbesc($x['path']),
- intval($rv['uid']),
- dbesc($rv['hash'])
- );
- }
- }
- }
-}
-
/**
* Chunked uploader for integration with the blueimp jquery-uploader
@@ -2981,11 +2952,17 @@ function save_chunk($channel,$start,$end,$len) {
$result = [];
- $tmp_path = $_FILES['files']['tmp_name'];
+ $file = $_FILES['files'] ?? $_FILES['userfile'] ?? [];
+
+ if (!$file) {
+ return $result;
+ }
+
+ $tmp_path = $file['tmp_name'];
$new_base = 'store/[data]/' . $channel['channel_address'] . '/tmp';
os_mkdir($new_base,STORAGE_DEFAULT_PERMISSIONS,true);
- $new_path = $new_base . '/' . $_FILES['files']['name'];
+ $new_path = $new_base . '/' . $file['name'];
if(file_exists($new_path) && intval($start) === 0) {
$result['partial'] = true;
@@ -3007,8 +2984,8 @@ function save_chunk($channel,$start,$end,$len) {
}
if(($len - 1) == $end) {
unlink($tmp_path);
- $result['name'] = $_FILES['files']['name'];
- $result['type'] = $_FILES['files']['type'];
+ $result['name'] = $file['name'];
+ $result['type'] = $file['type'];
$result['tmp_name'] = $new_path;
$result['error'] = 0;
$result['size'] = $len;
diff --git a/include/auth.php b/include/auth.php
index 5956b89e2..1fc2cc556 100644
--- a/include/auth.php
+++ b/include/auth.php
@@ -9,8 +9,9 @@
* Also provides a function for OpenID identiy matching.
*/
-use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\AConfig;
+use Zotlabs\Lib\Config;
+use Zotlabs\Lib\Libzot;
use Zotlabs\Module\Totp_check;
require_once('include/api_auth.php');
@@ -43,8 +44,8 @@ function account_verify_password($login, $pass) {
$ret = [ 'account' => null, 'channel' => null, 'xchan' => null ];
$login = punify($login);
- $email_verify = get_config('system', 'verify_email');
- $register_policy = get_config('system', 'register_policy');
+ $email_verify = Config::Get('system', 'verify_email');
+ $register_policy = Config::Get('system', 'register_policy');
if(!$login || !$pass)
return null;
@@ -170,11 +171,45 @@ function account_verify_password($login, $pass) {
* Error message to display for failed login.
*/
function log_failed_login($errormsg) {
- $authlog = get_config('system', 'authlog');
+ $authlog = Config::Get('system', 'authlog');
if ($authlog)
@file_put_contents($authlog, datetime_convert() . ':' . session_id() . ' ' . $errormsg . PHP_EOL, FILE_APPEND);
}
+
+/**
+ * Determines if checking for multifactor authentication needs to be checked.
+ *
+ * Checks that multi factor authentication is enabled for the given account_id,
+ * and whether it's already authenticated or not.
+ *
+ * Some modules needs to be excluded from the mfa checks for various reasons:
+ *
+ * - `totp_check` is used by the mfa module itself.
+ * - `dav` provides WebDAV access, and has no way of providing a mfa code.
+ * - `cdav` is accessed both via CardDAV which has the same limitations as
+ * the `dav` module, but may also be accessed via a web browser over http.
+ * We only exclude it if it's not being accessed via a web browser.
+ *
+ * @param int $account_id The id of the account we're verifying.
+ * @param string $module The requested module.
+ * @param string $arg The first arg passed to the module (or empty if none.)
+ *
+ * @return bool `true` if mfa status needs to be checked, `false` otherwise.
+ */
+function requires_mfa_check(int $account_id, string $module, string $arg): bool {
+ if (in_array($module, ['totp_check', 'dav'], true)) {
+ return false;
+ }
+
+ if ($module === 'cdav' && !in_array($arg, ['addressbook', 'calendar'], true)) {
+ return false;
+ }
+
+ $multiFactor = AConfig::Get($account_id, 'system', 'mfa_enabled');
+ return $multiFactor && empty($_SESSION['2FA_VERIFIED']);
+}
+
/**
* Inline - not a function
* look for auth parameters or re-validate an existing session
@@ -208,10 +243,10 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
if(x($_SESSION, 'visitor_id') && (! x($_SESSION, 'uid'))) {
// if our authenticated guest is allowed to take control of the admin channel, make it so.
- $admins = get_config('system', 'remote_admin');
+ $admins = Config::Get('system', 'remote_admin');
if($admins && is_array($admins) && in_array($_SESSION['visitor_id'], $admins)) {
$x = q("select * from account where account_email = '%s' and account_email != '' and ( account_flags & %d )>0 limit 1",
- dbesc(get_config('system', 'admin_email')),
+ dbesc(Config::Get('system', 'admin_email')),
intval(ACCOUNT_ROLE_ADMIN)
);
if($x) {
@@ -266,8 +301,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
$login_refresh = true;
}
- $multiFactor = AConfig::Get(App::$account['account_id'], 'system', 'mfa_enabled');
- if ($multiFactor && empty($_SESSION['2FA_VERIFIED']) && App::$module !== 'totp_check') {
+ if (requires_mfa_check(App::$account['account_id'], App::$module, argv(1))) {
$o = new Totp_check;
echo $o->get();
killme();
@@ -328,7 +362,7 @@ else {
$error = 'authenticate: failed login attempt: ' . notags(trim($username)) . ' from IP ' . $_SERVER['REMOTE_ADDR'];
logger($error);
// Also log failed logins to a separate auth log to reduce overhead for server side intrusion prevention
- $authlog = get_config('system', 'authlog');
+ $authlog = Config::Get('system', 'authlog');
if ($authlog)
@file_put_contents($authlog, datetime_convert() . ':' . session_id() . ' ' . $error . "\n", FILE_APPEND);
notice( t('Login failed.') . EOL );
diff --git a/include/bbcode.php b/include/bbcode.php
index d7ed3a243..65bda1b7b 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -4,8 +4,9 @@
* @brief BBCode related functions for parsing, etc.
*/
-use Zotlabs\Lib\SvgSanitizer;
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Libzot;
+use Zotlabs\Lib\SvgSanitizer;
require_once('include/oembed.php');
require_once('include/event.php');
@@ -111,7 +112,7 @@ function tryzrlvideo($match) {
if($zrl)
$link = zid($link);
- $static_link = get_config('system','video_default_poster','images/video_poster.jpg');
+ $static_link = Config::Get('system','video_default_poster','images/video_poster.jpg');
if($static_link)
$poster = 'poster="' . escape_tags($static_link) . '" ' ;
@@ -1125,9 +1126,11 @@ function parseIdentityAwareHTML($Text) {
if ($observer) {
$s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
$s2 = '</span>';
- $obsBaseURL = $observer['xchan_connurl'];
- $obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
- $Text = str_replace('[observer.baseurl]', $obsBaseURL, $Text);
+
+ $parsed = parse_url($observer['xchan_url']);
+ $observer_base_url = unparse_url($parsed, ['scheme', 'host', 'port']);
+
+ $Text = str_replace('[observer.baseurl]', $observer_base_url, $Text);
$Text = str_replace('[observer.url]',$observer['xchan_url'], $Text);
$Text = str_replace('[observer.name]',$s1 . $observer['xchan_name'] . $s2, $Text);
$Text = str_replace('[observer.address]',$s1 . $observer['xchan_addr'] . $s2, $Text);
@@ -1142,7 +1145,7 @@ function parseIdentityAwareHTML($Text) {
$Text = str_replace('[observer.photo]','', $Text);
}
- $Text = str_replace(array('[baseurl]','[sitename]'),array(z_root(),get_config('system','sitename')),$Text);
+ $Text = str_replace(array('[baseurl]','[sitename]'),array(z_root(),Config::Get('system','sitename')),$Text);
// Unhide all [noparse] contained bbtags unspacefying them
@@ -1249,7 +1252,7 @@ function bbcode($text, $options = []) {
$text = $x['body'];
$saved_images = $x['images'];
- $text = str_replace(array('[baseurl]','[sitename]'),array(z_root(),get_config('system','sitename')),$text);
+ $text = str_replace(array('[baseurl]','[sitename]'),array(z_root(),Config::Get('system','sitename')),$text);
// Replace any html brackets with HTML Entities to prevent executing HTML or script
// Don't use strip_tags here because it breaks [url] search by replacing & with amp
@@ -1310,9 +1313,11 @@ function bbcode($text, $options = []) {
if ($observer) {
$s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">';
$s2 = '</span>';
- $obsBaseURL = $observer['xchan_connurl'];
- $obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
- $text = str_replace('[observer.baseurl]', $obsBaseURL, $text);
+
+ $parsed = parse_url($observer['xchan_url']);
+ $observer_base_url = unparse_url($parsed, ['scheme', 'host', 'port']);
+
+ $text = str_replace('[observer.baseurl]', $observer_base_url, $text);
$text = str_replace('[observer.url]',$observer['xchan_url'], $text);
$text = str_replace('[observer.name]',$s1 . $observer['xchan_name'] . $s2, $text);
$text = str_replace('[observer.address]',$s1 . $observer['xchan_addr'] . $s2, $text);
@@ -1407,7 +1412,7 @@ function bbcode($text, $options = []) {
}
// Check for strike-through text
if (strpos($text,'[s]') !== false) {
- $text = preg_replace("(\[s\](.*?)\[\/s\])ism", '<span style="text-decoration: line-through;">$1</span>', $text);
+ $text = preg_replace("(\[s\](.*?)\[\/s\])ism", '<del>$1</del>', $text);
}
// Check for over-line text
if (strpos($text,'[o]') !== false) {
@@ -1744,10 +1749,8 @@ function bbcode($text, $options = []) {
// oembed tag
if (strpos($text,'[/embed]') !== false) {
+ $text = str_replace(["[/embed]\r", "[/embed]\n"], '[/embed]', $text);
$text = oembed_bbcode2html($text);
-
- // Avoid triple linefeeds through oembed
- $text = str_replace("<br style='clear:left'></span><br /><br />", "<br style='clear:left'></span>", $text);
}
// If we found an event earlier, strip out all the event code and replace with a reformatted version.
diff --git a/include/channel.php b/include/channel.php
index a82794bfd..a3ba1a765 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -9,6 +9,7 @@ use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Master;
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Crypto;
use Zotlabs\Lib\System;
use Zotlabs\Render\Comanche;
@@ -95,6 +96,8 @@ function validate_channelname($name) {
if (x($arr, 'message'))
return $arr['message'];
+
+ return null;
}
@@ -108,11 +111,11 @@ function create_sys_channel() {
// Ensure that there is a host keypair.
- if ((! get_config('system', 'pubkey')) && (! get_config('system', 'prvkey'))) {
+ if ((! Config::Get('system', 'pubkey')) && (! Config::Get('system', 'prvkey'))) {
require_once('include/crypto.php');
$hostkey = Crypto::new_keypair(4096);
- set_config('system', 'pubkey', $hostkey['pubkey']);
- set_config('system', 'prvkey', $hostkey['prvkey']);
+ Config::Set('system', 'pubkey', $hostkey['pubkey']);
+ Config::Set('system', 'prvkey', $hostkey['prvkey']);
}
create_identity([
@@ -198,8 +201,8 @@ function create_identity($arr) {
$ret = array('success' => false);
- if(! $arr['account_id']) {
- $ret['message'] = t('No account identifier');
+ if(empty($arr['account_id'])) {
+ $ret['message'] = t('No account identifier');
return $ret;
}
$ret = identity_check_service_class($arr['account_id']);
@@ -357,10 +360,10 @@ function create_identity($arr) {
'hubloc_primary' => intval($primary),
'hubloc_url' => z_root(),
'hubloc_url_sig' => Libzot::sign(z_root(),$ret['channel']['channel_prvkey']),
- 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey')),
+ 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),Config::Get('system','pubkey')),
'hubloc_host' => App::get_hostname(),
'hubloc_callback' => z_root() . '/zot',
- 'hubloc_sitekey' => get_config('system','pubkey'),
+ 'hubloc_sitekey' => Config::Get('system','pubkey'),
'hubloc_network' => 'zot6',
'hubloc_updated' => datetime_convert()
]
@@ -493,7 +496,7 @@ function create_identity($arr) {
// otherwise it could get annoying. Don't make this list too big
// or it will impact registration time.
- $accts = get_config('system','auto_follow');
+ $accts = Config::Get('system','auto_follow');
if(($accts) && (! $total_identities)) {
if(! is_array($accts))
$accts = array($accts);
@@ -1591,7 +1594,7 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $details =
$reddress = true;
$connect_url = '';
$connect = '';
- $default_cover = get_config('system', 'default_cover_photo', 'hubzilla');
+ $default_cover = Config::Get('system', 'default_cover_photo', 'hubzilla');
$default_cover_url = z_root() . '/images/default_cover_photos/' . $default_cover . '/425.png';
@@ -2040,7 +2043,7 @@ function get_theme_uid() {
* @return string with path to profile photo
*/
function get_default_profile_photo($size = 300) {
- $scheme = get_config('system','default_profile_photo');
+ $scheme = Config::Get('system','default_profile_photo');
if(! $scheme)
$scheme = 'rainbow_man';
@@ -2171,7 +2174,7 @@ function is_public_profile() {
if(! local_channel())
return false;
- if(intval(get_config('system','block_public')))
+ if(intval(Config::Get('system','block_public')))
return false;
$channel = App::get_channel();
@@ -2186,7 +2189,7 @@ function is_public_profile() {
function get_profile_fields_basic($filter = 0) {
- $profile_fields_basic = (($filter == 0) ? get_config('system','profile_fields_basic') : null);
+ $profile_fields_basic = (($filter == 0) ? Config::Get('system','profile_fields_basic') : null);
if(! $profile_fields_basic)
$profile_fields_basic = array('fullname','pdesc','chandesc','comms','gender','dob','dob_tz','region','country_name','marital','sexual','homepage','hometown','keywords','about','contact');
@@ -2202,7 +2205,7 @@ function get_profile_fields_basic($filter = 0) {
function get_profile_fields_advanced($filter = 0) {
$basic = get_profile_fields_basic($filter);
- $profile_fields_advanced = (($filter == 0) ? get_config('system','profile_fields_advanced') : null);
+ $profile_fields_advanced = (($filter == 0) ? Config::Get('system','profile_fields_advanced') : null);
if(! $profile_fields_advanced)
$profile_fields_advanced = array('address','locality','postal_code','partner','howlong','politic','religion','likes','dislikes','interest','channels','music','book','film','tv','romance','employment','education');
@@ -2423,11 +2426,11 @@ function get_zcard($channel, $observer_hash = '', $args = array()) {
$cover = $r[0];
$cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale'];
} else {
- $default_cover = get_config('system', 'default_cover_photo', 'hubzilla');
+ $default_cover = Config::Get('system', 'default_cover_photo', 'hubzilla');
$cover = [ 'href' => z_root() . '/images/default_cover_photos/' . $default_cover . '/' . $cover_width . '.png' ];
}
- $o .= replace_macros(get_markup_template('zcard.tpl'), array(
+ return replace_macros(get_markup_template('zcard.tpl'), array(
'$maxwidth' => $maxwidth,
'$scale' => $scale,
'$translate' => $translate,
@@ -2436,8 +2439,6 @@ function get_zcard($channel, $observer_hash = '', $args = array()) {
'$pphoto' => $pphoto,
'$zcard' => $zcard
));
-
- return $o;
}
@@ -2500,21 +2501,17 @@ function get_zcard_embed($channel, $observer_hash = '', $args = array()) {
$cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale'];
}
else {
- $default_cover = get_config('system', 'default_cover_photo', 'hubzilla');
+ $default_cover = Config::Get('system', 'default_cover_photo', 'hubzilla');
$cover = [ 'href' => z_root() . '/images/default_cover_photos/' . $default_cover . '/' . $cover_width . '.png' ];
}
- $o .= replace_macros(get_markup_template('zcard_embed.tpl'),array(
+ return replace_macros(get_markup_template('zcard_embed.tpl'),array(
'$maxwidth' => $maxwidth,
- '$scale' => $scale,
- '$translate' => $translate,
'$size' => $size,
'$cover' => $cover,
'$pphoto' => $pphoto,
'$zcard' => $zcard
));
-
- return $o;
}
/**
@@ -3105,7 +3102,7 @@ function pchan_to_chan($pchan) {
}
function channel_url($channel) {
- return (($channel) ? z_root() . '/channel/' . $channel['channel_address'] : z_root());
+ return ((isset($channel['channel_address'])) ? z_root() . '/channel/' . $channel['channel_address'] : z_root());
}
function get_channel_hashes() {
diff --git a/include/cli_startup.php b/include/cli_startup.php
index b9e7d124d..012b29fbf 100644
--- a/include/cli_startup.php
+++ b/include/cli_startup.php
@@ -2,11 +2,13 @@
require_once('boot.php');
+use Zotlabs\Lib\Config;
+
// Everything we need to boot standalone 'background' processes
function cli_startup() {
sys_boot();
- App::set_baseurl(get_config('system','baseurl'));
+ App::set_baseurl(Config::Get('system','baseurl'));
}
diff --git a/include/config.php b/include/config.php
index ec3547a82..50fe60eb0 100644
--- a/include/config.php
+++ b/include/config.php
@@ -31,18 +31,81 @@
use Zotlabs\Lib as Zlib;
+/**
+ * Loads the hub's configuration from database to a cached storage.
+ *
+ * Retrieve a category ($family) of config variables from database to a cached
+ * storage in the global App::$config[$family].
+ *
+ * @param string $family The category of the configuration value
+ *
+ * @deprecated
+ * This function is deprecated, use Zotlabs\Lib\Config::Load
+ * instead.
+ */
function load_config($family) {
Zlib\Config::Load($family);
}
+/**
+ * Get a particular config variable given the category name ($family)
+ * and a key.
+ *
+ * Get a particular config variable from the given category ($family) and the
+ * $key from a cached storage in App::$config[$family]. If a key is found in the
+ * DB but does not exist in local config cache, pull it into the cache so we
+ * do not have to hit the DB again for this item.
+ *
+ * Returns false if not set.
+ *
+ * @param string $family The category of the configuration value
+ * @param string $key The configuration key to query
+ * @param string $default (optional) default false
+ *
+ * @return mixed|false Return value or false on error or if not set
+ *
+ * @deprecated
+ * This function is deprecated, use Zotlabs\Lib\Config::Get
+ * instead.
+ */
function get_config($family, $key, $default = false) {
return Zlib\Config::Get($family,$key,$default);
}
+/**
+ * Sets a configuration value for the hub.
+ *
+ * Stores a config value ($value) in the category ($family) under the key ($key).
+ *
+ * @param string $family The category of the configuration value
+ * @param string $key The configuration key to set
+ * @param mixed $value The value to store in the configuration
+ *
+ * @return mixed|false Return the set value, or false if the database update failed
+ *
+ * @deprecated
+ * This function is deprecated, use Zotlabs\Lib\Config::Set
+ * instead.
+ */
function set_config($family, $key, $value) {
return Zlib\Config::Set($family,$key,$value);
}
+/**
+ * Deletes the given key from the hub's configuration database.
+ *
+ * Removes the configured value from the stored cache in App::$config[$family]
+ * and removes it from the database.
+ *
+ * @param string $family The category of the configuration value
+ * @param string $key The configuration key to delete
+ *
+ * @return mixed
+ *
+ * @deprecated
+ * This function is deprecated, use Zotlabs\Lib\Config::Delete
+ * instead.
+ */
function del_config($family, $key) {
return Zlib\Config::Delete($family,$key);
}
@@ -55,8 +118,8 @@ function get_pconfig($uid, $family, $key, $default = false) {
return Zlib\PConfig::Get($uid,$family,$key,$default);
}
-function set_pconfig($uid, $family, $key, $value) {
- return Zlib\PConfig::Set($uid,$family,$key,$value);
+function set_pconfig($uid, $family, $key, $value, $updated = NULL) {
+ return Zlib\PConfig::Set($uid, $family, $key, $value, $updated);
}
function del_pconfig($uid, $family, $key, $updated = NULL) {
diff --git a/include/connections.php b/include/connections.php
index 9a6ee7d8d..b3e9ba89d 100644
--- a/include/connections.php
+++ b/include/connections.php
@@ -1,6 +1,7 @@
<?php /** @file */
use Zotlabs\Daemon\Master;
+use Zotlabs\Lib\Config;
function abook_store_lowlevel($arr) {
@@ -67,6 +68,14 @@ function rconnect_url($channel_id,$xchan) {
}
+/**
+ * @brief returns deliverable xchans for a channel.
+ *
+ * @param intval $channel_id
+ * @param array $filter (optional)
+ * @param boolean $flatten (optional)
+ */
+
function deliverable_abook_xchans($channel_id, $filter = [], $flatten = true) {
$filter_sql = '';
@@ -238,7 +247,7 @@ function abook_toggle_flag($abook,$flag) {
function mark_orphan_hubsxchans() {
- $dirmode = intval(get_config('system','directory_mode'));
+ $dirmode = intval(Config::Get('system','directory_mode'));
if($dirmode == DIRECTORY_MODE_NORMAL)
return;
@@ -333,7 +342,7 @@ function remove_all_xchan_resources($xchan, $channel_id = 0) {
if($r) {
foreach($r as $rr) {
- drop_item($rr['id'],false);
+ drop_item($rr['id']);
}
}
@@ -504,15 +513,15 @@ function remove_abook_items($channel_id, $xchan_hash) {
continue;
}
- drop_item($rr['id'],false);
+ drop_item($rr['id'], uid: $channel_id);
}
}
function random_profile() {
$randfunc = db_getfunc('rand');
- $checkrandom = get_config('randprofile','check'); // False by default
- $retryrandom = intval(get_config('randprofile','retry'));
+ $checkrandom = Config::Get('randprofile','check'); // False by default
+ $retryrandom = intval(Config::Get('randprofile','retry'));
if($retryrandom == 0) $retryrandom = 5;
for($i = 0; $i < $retryrandom; $i++) {
diff --git a/include/contact_widgets.php b/include/contact_widgets.php
index e3fbc1057..84f688d36 100644
--- a/include/contact_widgets.php
+++ b/include/contact_widgets.php
@@ -1,11 +1,12 @@
<?php /** @file */
use Zotlabs\Lib\Cache;
+use Zotlabs\Lib\Config;
use Zotlabs\Daemon\Master;
function findpeople_widget() {
- if(get_config('system','invitation_only')) {
+ if(Config::Get('system','invitation_only')) {
$x = get_pconfig(local_channel(),'system','invites_remaining');
if($x || is_site_admin()) {
App::$page['aside'] .= '<div class="side-link" id="side-invite-remain">'
diff --git a/include/conversation.php b/include/conversation.php
index 79fe12d54..6dfefa707 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -1,7 +1,9 @@
<?php /** @file */
-use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Config;
+use Zotlabs\Lib\PConfig;
require_once('include/items.php');
@@ -437,17 +439,22 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
$uploading = false;
- if(local_channel()) {
- $cur_channel = App::get_channel();
- if($cur_channel['channel_allow_cid'] === '' && $cur_channel['channel_allow_gid'] === ''
- && $cur_channel['channel_deny_cid'] === '' && $cur_channel['channel_deny_gid'] === ''
+ $channel = App::get_channel();
+ $observer = App::get_observer();
+
+ if (local_channel()) {
+ // Allow uploading if there is no default privacy and the view_storage permission is set to PERMS_PUBLIC
+ if ($channel['channel_allow_cid'] === '' && $channel['channel_allow_gid'] === ''
+ && $channel['channel_deny_cid'] === '' && $channel['channel_deny_gid'] === ''
&& intval(\Zotlabs\Access\PermissionLimits::Get(local_channel(),'view_storage')) === PERMS_PUBLIC) {
$uploading = true;
}
- }
- $channel = App::get_channel();
- $observer = App::get_observer();
+ // Allow uploading if OCAP tokens are enabled
+ if (PConfig::Get(local_channel(), 'system', 'ocap_enabled')) {
+ $uploading = true;
+ }
+ }
if (!$update) {
$_SESSION['return_url'] = App::$query_string;
@@ -816,7 +823,7 @@ function thread_action_menu($item,$mode = '') {
$menu[] = [
'menu' => 'unfollow_thread',
'title' => t('Unfollow Thread'),
- 'icon' => 'minus',
+ 'icon' => 'dash',
'action' => 'dounsubthread(' . $item['id'] . '); return false;',
'href' => '#'
];
@@ -998,10 +1005,10 @@ function builtin_activity_puller($item, &$conv_responses) {
$name = (($item['author']['xchan_name']) ? $item['author']['xchan_name'] : t('Unknown'));
- $moderate = ((intval($item['item_blocked']) === ITEM_MODERATED) ? '<a href="moderate/' . $item['id'] . '/approve" onclick="moderate_approve(' . $item['id'] . '); return false;" class="text-success pe-2" title="' . t('Approve this item') . '"><i class="fa fa-check" ></i></a><a href="moderate/' . $item['id'] . '/drop" onclick="moderate_drop(' . $item['id'] . '); return false;" class="text-danger pe-2" title="' . t('Delete this item') . '"><i class="fa fa-trash-o" ></i></a>' : '');
+ $moderate = ((intval($item['item_blocked']) === ITEM_MODERATED) ? '<a href="moderate/' . $item['id'] . '/approve" onclick="moderate_approve(' . $item['id'] . '); return false;" class="text-success pe-2" title="' . t('Approve this item') . '"><i class="bi bi-check-lg" ></i></a><a href="moderate/' . $item['id'] . '/drop" onclick="moderate_drop(' . $item['id'] . '); return false;" class="text-danger pe-2" title="' . t('Delete this item') . '"><i class="bi bi-trash" ></i></a>' : '');
$url = (($item['author_xchan'] && $item['author']['xchan_photo_s'])
- ? '<div class="dropdown-item">' . $moderate . '<a href="' . chanlink_hash($item['author_xchan']) . '" class="text-reset">' . '<img class="menu-img-1" src="' . zid($item['author']['xchan_photo_s']) . '" alt="' . urlencode($name) . '" /> ' . $name . '</a></div>'
+ ? '<div class="dropdown-item">' . $moderate . '<a href="' . chanlink_hash($item['author_xchan']) . '" class="text-reset">' . '<img class="menu-img-1" src="' . $item['author']['xchan_photo_s'] . '" alt="' . urlencode($name) . '" loading="lazy" /> ' . $name . '</a></div>'
: '<a class="dropdown-item" href="#" class="disabled">' . $name . '</a>'
);
@@ -1182,6 +1189,7 @@ function hz_status_editor($x, $popup = false) {
'$modalerroralbum' => t('Error getting album'),
'$nocomment_enabled' => t('Comments enabled'),
'$nocomment_disabled' => t('Comments disabled'),
+ '$confirmdelete' => t('Confirm delete'),
'$auto_save_draft' => $feature_auto_save_draft,
'$reset' => $reset,
'$popup' => $popup
@@ -1247,6 +1255,7 @@ function hz_status_editor($x, $popup = false) {
'$writefiles' => $writefiles,
'$bold' => t('Bold'),
'$italic' => t('Italic'),
+ '$highlighter' => t('Highlight selected text'),
'$underline' => t('Underline'),
'$quote' => t('Quote'),
'$code' => t('Code'),
@@ -1262,7 +1271,7 @@ function hz_status_editor($x, $popup = false) {
'$poll_option_label' => t('Option'),
'$poll_add_option_label' => t('Add option'),
'$poll_expire_unit_label' => [t('Minutes'), t('Hours'), t('Days')],
- '$multiple_answers' => ['poll_multiple_answers', t("Allow multiple answers"), '', '', [t('No'), t('Yes')]],
+ '$multiple_answers' => ['poll_multiple_answers', t("Allow multiple answers"), '', '', [t('No'), t('Yes')],null,null],
'$consensus' => ((array_key_exists('item',$x)) ? $x['item']['item_consensus'] : 0),
'$nocommenttitle' => t('Disable comments'),
'$nocommenttitlesub' => t('Toggle comments'),
@@ -1336,7 +1345,7 @@ function get_item_children($arr, $parent) {
$children = array();
foreach($arr as $item) {
if($item['id'] != $item['parent']) {
- if(get_config('system','thread_allow')) {
+ if(Config::Get('system','thread_allow')) {
// Fallback to parent_mid if thr_parent is not set
$thr_parent = $item['thr_parent'];
if($thr_parent == '')
@@ -1465,14 +1474,18 @@ function render_location_default($item) {
$location = $item['location'];
$coord = $item['coord'];
- if($coord) {
+ if ($coord) {
if($location)
- $location .= '&nbsp;<span class="smalltext">(' . $coord . ')</span>';
+ $location .= '&nbsp;(' . $coord . ')';
else
- $location = '<span class="smalltext">' . $coord . '</span>';
+ $location = $coord;
}
- return $location;
+ if (!$location) {
+ return '';
+ }
+
+ return '<i class="bi bi-geo-alt" title="' . $location . '"></i>';
}
@@ -1523,6 +1536,12 @@ function get_responses($conv_responses,$response_verbs,$ob,$item) {
$ret = array();
foreach($response_verbs as $v) {
+ if ($v === 'answer') {
+ // we require the structure to collect the response hashes
+ // but we do not use them for display - do not collect them.
+ continue;
+ }
+
$ret[$v] = [];
$ret[$v]['count'] = $conv_responses[$v][$item['mid']] ?? 0;
$ret[$v]['list'] = ((isset($conv_responses[$v][$item['mid']])) ? $conv_responses[$v][$item['mid'] . '-l'] : '');
@@ -1531,14 +1550,6 @@ function get_responses($conv_responses,$response_verbs,$ob,$item) {
$ret[$v]['modal'] = (($ret[$v]['count'] > MAX_LIKERS) ? true : false);
}
- $count = 0;
- foreach ($ret as $key) {
- if ($key['count'] == true)
- $count++;
- }
-
- $ret['count'] = $count;
-
//logger('ret: ' . print_r($ret,true));
return $ret;
@@ -1547,25 +1558,25 @@ function get_responses($conv_responses,$response_verbs,$ob,$item) {
function get_response_button_text($v,$count) {
switch($v) {
case 'like':
- return ['label' => tt('Like','Likes',$count,'noun'), 'icon' => 'thumbs-o-up', 'class' => 'like'];
+ return ['label' => tt('Like','Likes',$count,'noun'), 'icon' => 'hand-thumbs-up', 'class' => 'like', 'onclick' => 'dolike'];
break;
case 'announce':
- return ['label' => tt('Repeat','Repeats',$count,'noun'), 'icon' => 'retweet', 'class' => 'announce'];
+ return ['label' => tt('Repeat','Repeats',$count,'noun'), 'icon' => 'repeat', 'class' => 'announce', 'onclick' => 'jotShare'];
break;
case 'dislike':
- return ['label' => tt('Dislike','Dislikes',$count,'noun'), 'icon' => 'thumbs-o-down', 'class' => 'dislike'];
+ return ['label' => tt('Dislike','Dislikes',$count,'noun'), 'icon' => 'hand-thumbs-down', 'class' => 'dislike', 'onclick' => 'dolike'];
break;
case 'attendyes':
- return ['label' => tt('Attending','Attending',$count,'noun'), 'icon' => 'calendar-check-o', 'class' => 'attendyes'];
+ return ['label' => tt('Attending','Attending',$count,'noun'), 'icon' => 'calendar-check', 'class' => 'attendyes', 'onclick' => 'dolike'];
break;
case 'attendno':
- return ['label' => tt('Not Attending','Not Attending',$count,'noun'), 'icon' => 'calendar-times-o', 'class' => 'attendno'];
+ return ['label' => tt('Not Attending','Not Attending',$count,'noun'), 'icon' => 'calendar-x', 'class' => 'attendno', 'onclick' => 'dolike'];
break;
case 'attendmaybe':
- return ['label' => tt('Undecided','Undecided',$count,'noun'), 'icon' => 'calendar-o', 'class' => 'attendmaybe'];
+ return ['label' => tt('Undecided','Undecided',$count,'noun'), 'icon' => 'calendar', 'class' => 'attendmaybe', 'onclick' => 'dolike'];
break;
default:
- return '';
+ return [];
break;
}
}
diff --git a/include/crypto.php b/include/crypto.php
index 40e68a4e7..4d50310fb 100644
--- a/include/crypto.php
+++ b/include/crypto.php
@@ -1,5 +1,7 @@
<?php /** @file */
+use Zotlabs\Lib\Config;
+
require_once('library/ASNValue.class.php');
require_once('library/asn1.php');
@@ -282,7 +284,7 @@ function new_keypair($bits) {
'encrypt_key' => false
);
- $conf = get_config('system','openssl_conf_file');
+ $conf = Config::Get('system','openssl_conf_file');
if($conf)
$openssl_options['config'] = $conf;
@@ -460,12 +462,12 @@ function convert_salmon_key($key) {
function z_obscure($s) {
- return json_encode(crypto_encapsulate($s,get_config('system','pubkey')));
+ return json_encode(crypto_encapsulate($s,Config::Get('system','pubkey')));
}
function z_unobscure($s) {
if(strpos($s,"{\"") !== 0)
return $s;
- return crypto_unencapsulate(json_decode($s,true),get_config('system','prvkey'));
+ return crypto_unencapsulate(json_decode($s,true),Config::Get('system','prvkey'));
}
diff --git a/include/datetime.php b/include/datetime.php
index 4c7105138..89e2876d0 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -264,6 +264,45 @@ function relative_date($posted_date, $format = null) {
return sprintf($format, $r, plural_dates($str,$r));
}
}
+
+ return $abs;
+}
+
+/**
+ * @brief Returns a relative time string like 3 seconds ago.
+ * @param string $posted_date (UTC)
+ * @param DateTime $now (optional)
+ * @return string with relative time
+ */
+function relative_time($timestamp, $now = new DateTime()) {
+ $localtime = datetime_convert('UTC', date_default_timezone_get(), $timestamp);
+ $time = new DateTime($localtime);
+
+ $interval = $now->diff($time);
+
+ $prefix = '';
+ $appendix = ' ' . t('ago');
+
+ if ($time > $now) {
+ $prefix = t('in') . ' ';
+ $appendix = '';
+ }
+
+ if ($interval->y > 0) {
+ return $prefix . $interval->y . ' ' . plural_dates('y', $interval->y) . $appendix;
+ } elseif ($interval->m > 0) {
+ return $prefix . $interval->m . ' ' . plural_dates('m', $interval->m) . $appendix;
+ } elseif ($interval->d > 0) {
+ return $prefix . $interval->d . ' ' . plural_dates('d', $interval->d) . $appendix;
+ } elseif ($interval->h > 0) {
+ return $prefix . $interval->h . ' ' . plural_dates('h', $interval->h) . $appendix;
+ } elseif ($interval->i > 0) {
+ return $prefix . $interval->i . ' ' . plural_dates('i', $interval->i) . $appendix;
+ } elseif ($interval->s > 0) {
+ return $prefix . $interval->s . ' ' . plural_dates('s', $interval->s) . $appendix;
+ } else {
+ return t('now');
+ }
}
function plural_dates($k,$n) {
@@ -525,7 +564,7 @@ function update_birthdays() {
$z = event_store_event($ev);
if ($z) {
- $item_id = event_store_item($ev, $z);
+ event_store_item($ev, $z, false);
q("update abook set abook_dob = '%s' where abook_id = %d",
dbesc(intval($rr['abook_dob']) + 1 . substr($rr['abook_dob'], 4)),
intval($rr['abook_id'])
diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php
index c8a1b6c85..a12629e19 100644
--- a/include/dba/dba_pdo.php
+++ b/include/dba/dba_pdo.php
@@ -10,6 +10,8 @@ class dba_pdo extends dba_driver {
public $driver_dbtype = null;
+ private string $server_version = '';
+
/**
* {@inheritDoc}
* @see dba_driver::connect()
@@ -37,6 +39,7 @@ class dba_pdo extends dba_driver {
try {
$this->db = new PDO($dsn,$user,$pass);
$this->db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
+ $this->server_version = $this->db->getAttribute(PDO::ATTR_SERVER_VERSION);
}
catch(PDOException $e) {
if(file_exists('dbfail.out')) {
@@ -73,9 +76,9 @@ class dba_pdo extends dba_driver {
}
}
- $result = null;
+ $result = false;
$this->error = '';
- $select = ((stripos($sql, 'select') === 0) ? true : false);
+ $select = stripos($sql, 'select') === 0 || stripos($sql, 'returning ') > 0;
try {
$result = $this->db->query($sql, PDO::FETCH_ASSOC);
@@ -115,6 +118,111 @@ class dba_pdo extends dba_driver {
return (($this->error) ? false : $r);
}
+ /**
+ * Insert a row into a table.
+ *
+ * The `$data` argument is an array of key/value pairs of the columns to
+ * insert, where the key is the column name. Values are automatically
+ * escaped if needed, and should be provided unescaped to this function.
+ *
+ * @note it is the callers responsibility to ensure that only valid
+ * column names are passed as keys in the array.
+ *
+ * The inserted row will be returned.
+ *
+ * @param string $table The table to insert the row into.
+ * @param array $data The data to insert as an array of column name => value pairs.
+ * @param string $idcol The column name for the primary key of the table. We need to
+ * specify this since we don't have a consistent naming of primary
+ * id for tables.
+ *
+ * @return array|bool The complete record as read back from the database, or false if we
+ * could not fetch it.
+ */
+ public function insert(string $table, array $data, string $idcol): array|bool {
+ $keys = array_keys($data);
+ $values = array_map(
+ fn ($v) => is_numeric($v) ? $v : "'" . dbesc($v) . "'",
+ array_values($data)
+ );
+
+ $query = "INSERT INTO {$table} ("
+ . implode(', ', $keys) . ') VALUES ('
+ . implode(', ', $values) . ')';
+
+ // MySQL is the only supported DB that don't support the returning
+ // clause. Since the driver type is 'mysql' also for MariaDB, we need
+ // to check the actual server version to be sure we only exclude actual
+ // MySQL systems.
+ if ($this->driver_dbtype !== 'mysql' || stripos($this->server_version, 'mariadb') !== false) {
+ $query .= ' RETURNING *';
+ }
+
+ $res = $this->q($query);
+
+ if (is_a($res, PDOStatement::class)) {
+ //
+ // Calling PDO::lastInsertId should be safe here.
+ // The last inserted id is kept for each connection, so we're not risking
+ // a race condition wrt inserts by other requests that happen simultaneously.
+ //
+ $id = $this->db->lastInsertId($table);
+
+ $res = $this->q("SELECT * FROM {$table} WHERE {$idcol} = {$id}");
+
+ if (is_a($res, PDOStatement::class)) {
+ db_logger('dba_pdo: PDOStatement returned, did not expect that.');
+ return false;
+ }
+ }
+
+ if (is_array($res)) {
+ // Since we should never have more than one result, unwrap the array
+ // so we only have the resulting row.
+ $res = $res[0];
+ }
+
+ return $res;
+ }
+
+ /**
+ * Update an existing row in a table.
+ *
+ * The `$data` argument is an array of key/value pairs of the columns to
+ * update, where the key is the column name. Values are automatically
+ * escaped if needed, and should be provided unescaped to this function.
+ *
+ * @note it is the callers responsibility to ensure that only valid
+ * column names are passed as keys in the array.
+ *
+ * The row to be updated is identified by `$idcol` and `$idval` as the
+ * column name and value respectively. This should normally be the unique
+ * id column of the table, but can in theory be any column with a unique
+ * value that identifies a specific row.
+ *
+ * @param string $table The table to update.
+ * @param array $data The columns to update as key => value pairs.
+ * @param string $idcol The name of the id column to check $idval against.
+ * @param mixed $idval The id of the row to update.
+ *
+ * @return bool True if the update succeeded, false otherwise.
+ */
+ public function update(string $table, array $data, string $idcol, mixed $idval): bool {
+ $set_statements = [];
+
+ foreach ($data as $k => $v) {
+ $set_statements[] = "set {$k}=" . (is_numeric($v) ? $v : "'" . dbesc($v) . "'");
+ }
+
+ $query = "UPDATE {$table} "
+ . implode(', ', $set_statements)
+ . " WHERE {$idcol} = {$idval}";
+
+ $res = $this->q($query);
+
+ return is_a($res, PDOStatement::class);
+ }
+
function escape($str) {
if($this->db && $this->connected) {
return substr(substr(@$this->db->quote($str),1),0,-1);
diff --git a/include/event.php b/include/event.php
index 701f3c330..b83a733b8 100644
--- a/include/event.php
+++ b/include/event.php
@@ -8,11 +8,12 @@
use Sabre\VObject;
use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Libsync;
use Zotlabs\Access\AccessList;
use Ramsey\Uuid\Uuid;
-use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use Ramsey\Uuid\Exception\UnableToBuildUuidException;
require_once('include/bbcode.php');
@@ -37,7 +38,7 @@ function format_event_html($ev) {
$o = '<div class="vevent">' . "\r\n";
- $o .= '<div class="event-title"><h3><i class="fa fa-calendar"></i>&nbsp;' . zidify_links(smilies(bbcode($ev['summary']))) . '</h3></div>' . "\r\n";
+ $o .= '<div class="event-title"><h3><i class="bi bi-calendar-date"></i>&nbsp;' . zidify_links(smilies(bbcode($ev['summary']))) . '</h3></div>' . "\r\n";
$o .= '<div class="event-start"><span class="event-label">' . t('Starts:') . '</span>&nbsp;<span class="dtstart" title="'
. datetime_convert('UTC', 'UTC', $ev['dtstart'], ((isset($ev['adjust']) && $ev['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' ))
@@ -101,7 +102,15 @@ function format_event_obj($jobject) {
if (is_array($object) && (array_key_exists('summary', $object) || array_key_exists('name', $object))) {
$dtend = ((array_key_exists('endTime', $object)) ? $object['endTime'] : NULL_DATE);
- $title = ((isset($object['summary']) && $object['summary']) ? zidify_links(smilies(bbcode($object['summary']))) : $object['name']);
+
+ $title = $object['name'] ?? '';
+ $content = html2bbcode($object['content']);
+
+ if (strpos($object['source']['content'], '[/event-description]') !== false) {
+ $bbdescription = [];
+ preg_match("/\[event\-description\](.*?)\[\/event\-description\]/ism", $object['source']['content'], $bbdescription);
+ $content = $bbdescription[1];
+ }
// mobilizon sets a timezone in the object
// we will assume that events with an timezone should be adjusted
@@ -145,15 +154,8 @@ function format_event_obj($jobject) {
'$event_tz' => ['label' => t('Timezone'), 'value' => (($tz === date_default_timezone_get()) ? '' : $tz)]
));
-
- $description = [];
-
- if (strpos($object['source']['content'], '[/event-description]') !== false) {
- preg_match("/\[event\-description\](.*?)\[\/event\-description\]/ism", $object['source']['content'], $description);
- }
-
$event['content'] = replace_macros(get_markup_template('event_item_content.tpl'), array(
- '$description' => ((isset($description[1]))? zidify_links(smilies(bbcode($description[1]))) : EMPTY_STR),
+ '$description' => zidify_links(smilies(bbcode($content, ['tryoembed' => false]))),
'$location_label' => t('Location:'),
'$location' => ((array_path_exists('location/name', $object)) ? zidify_links(smilies(bbcode($object['location']['name']))) : EMPTY_STR)
));
@@ -234,10 +236,10 @@ function ical_wrapper($ev) {
if(! ((is_array($ev)) && count($ev)))
return '';
- $o .= "BEGIN:VCALENDAR";
+ $o = "BEGIN:VCALENDAR";
$o .= "\r\nVERSION:2.0";
$o .= "\r\nMETHOD:PUBLISH";
- $o .= "\r\nPRODID:-//" . get_config('system','sitename') . "//" . Zotlabs\Lib\System::get_platform_name() . "//" . strtoupper(App::$language). "\r\n";
+ $o .= "\r\nPRODID:-//" . Config::Get('system','sitename') . "//" . Zotlabs\Lib\System::get_platform_name() . "//" . strtoupper(App::$language). "\r\n";
if(array_key_exists('dtstart', $ev))
$o .= format_event_ical($ev);
else {
@@ -271,9 +273,9 @@ function format_event_ical($ev) {
if($ev['adjust']) {
if($ev['dtstart'])
- $o .= "\r\nDTSTART$tzid:" . datetime_convert($tz,'UTC', $ev['dtstart'],'Ymd\\THis\\Z');
+ $o .= "\r\nDTSTART$tzid:" . datetime_convert('UTC', $tz, $ev['dtstart'],'Ymd\\THis');
if($ev['dtend'] && ! $ev['nofinish'])
- $o .= "\r\nDTEND$tzid:" . datetime_convert($tz,'UTC', $ev['dtend'],'Ymd\\THis\\Z');
+ $o .= "\r\nDTEND$tzid:" . datetime_convert('UTC', $tz, $ev['dtend'],'Ymd\\THis');
}
else {
if($ev['dtstart'])
@@ -646,7 +648,7 @@ function event_store_event($arr) {
else {
try {
$hash = Uuid::uuid4()->toString();
- } catch (UnsatisfiedDependencyException $e) {
+ } catch (UnableToBuildUuidException $e) {
$hash = random_string(48);
}
}
@@ -796,7 +798,7 @@ function parse_event_object($event_object_json) {
$tz = $object['timezone'] ?? 'UTC';
$ev['summary'] = $object['summary'] ?? $object['name'] ?? '';
- $ev['description'] = html2bbcode($content['content']) ?? '';
+ $ev['description'] = html2bbcode($object['content']) ?? '';
$ev['dtstart'] = $object['startTime'] ? datetime_convert('UTC', 'UTC', $object['startTime']) : '';
$ev['dtend'] = $object['endTime'] ? datetime_convert('UTC', 'UTC', $object['endTime']) : $ev['dtstart'];
$ev['location'] = $object['location']['name'] ?? '';
@@ -1069,7 +1071,7 @@ function event_import_ical($ical, $uid) {
logger('storing event: ' . print_r($ev,true), LOGGER_ALL);
$event = event_store_event($ev);
if($event) {
- $item_id = event_store_item($ev,$event);
+ event_store_item($ev, $event, false);
return true;
}
}
@@ -1204,7 +1206,7 @@ function event_import_ical_task($ical, $uid) {
logger('storing event: ' . print_r($ev,true), LOGGER_ALL);
$event = event_store_event($ev);
if($event) {
- $item_id = event_store_item($ev,$event);
+ event_store_item($ev, $event, false);
return true;
}
}
@@ -1213,8 +1215,7 @@ function event_import_ical_task($ical, $uid) {
}
-
-function event_store_item($arr, $event) {
+function event_store_item($arr, $event, $deliver = true) {
require_once('include/datetime.php');
require_once('include/items.php');
@@ -1233,7 +1234,7 @@ function event_store_item($arr, $event) {
}
- $item_arr = array();
+ $item_arr = [];
$prefix = '';
// $birthday = false;
@@ -1254,7 +1255,7 @@ function event_store_item($arr, $event) {
$item_arr['comment_policy'] = 'none';
}
- $r = q("SELECT * FROM item WHERE resource_id = '%s' AND resource_type = 'event' and uid = %d LIMIT 1",
+ $r = q("SELECT * FROM item left join xchan on author_xchan = xchan_hash WHERE resource_id = '%s' AND resource_type = 'event' and uid = %d LIMIT 1",
dbesc($event['event_hash']),
intval($arr['uid'])
);
@@ -1291,51 +1292,21 @@ function event_store_item($arr, $event) {
$object = json_encode($x);
- $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
-
- /**
- * @FIXME can only update sig if we have the author's channel on this site
- * Until fixed, set it to nothing so it won't give us signature errors.
- */
- $sig = '';
-
- q("UPDATE item SET title = '%s', body = '%s', obj = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', sig = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d",
- dbesc($arr['summary']),
- dbesc($prefix . format_event_bbcode($arr)),
- dbesc($object),
- dbesc($arr['allow_cid']),
- dbesc($arr['allow_gid']),
- dbesc($arr['deny_cid']),
- dbesc($arr['deny_gid']),
- dbesc($arr['edited']),
- dbesc($sig),
- intval($r[0]['item_flags']),
- intval($private),
- dbesc('Event'),
- intval($r[0]['id']),
- intval($arr['uid'])
- );
-
- q("delete from term where oid = %d and otype = %d",
- intval($r[0]['id']),
- intval(TERM_OBJ_POST)
- );
-
- if(($arr['term']) && (is_array($arr['term']))) {
- foreach($arr['term'] as $t) {
- q("insert into term (uid,oid,otype,ttype,term,url)
- values(%d,%d,%d,%d,'%s','%s') ",
- intval($arr['uid']),
- intval($r[0]['id']),
- intval(TERM_OBJ_POST),
- intval($t['ttype']),
- dbesc($t['term']),
- dbesc($t['url'])
- );
- }
- }
-
- $item_id = $r[0]['id'];
+ $item_arr['id'] = $r[0]['id'];
+ $item_arr['uid'] = $arr['uid'];
+ $item_arr['obj'] = $object;
+ $item_arr['edited'] = $arr['edited'];
+ $item_arr['allow_cid'] = $arr['allow_cid'];
+ $item_arr['allow_gid'] = $arr['allow_gid'];
+ $item_arr['deny_cid'] = $arr['deny_cid'];
+ $item_arr['deny_gid'] = $arr['deny_gid'];
+ $item_arr['item_private'] = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
+ $item_arr['title'] = $arr['summary'];
+ $item_arr['sig'] = '';
+ $item_arr['body'] = $prefix . format_event_bbcode($arr);
+ $item_arr['term'] = $arr['term'];
+
+ $post = item_store_update($item_arr, deliver: $deliver);
/**
* @hooks event_updated
@@ -1343,14 +1314,10 @@ function event_store_item($arr, $event) {
*/
call_hooks('event_updated', $event['id']);
- return $item_id;
+ return $post;
} else {
- $z = q("select * from channel where channel_id = %d limit 1",
- intval($arr['uid'])
- );
-
- $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
+ $z = channelx_by_n($arr['uid']);
$item_wall = 0;
$item_origin = 0;
@@ -1360,7 +1327,7 @@ function event_store_item($arr, $event) {
$item_arr['id'] = $item['id'];
}
else {
- $wall = (($z[0]['channel_hash'] == $event['event_xchan']) ? true : false);
+ $wall = (($z['channel_hash'] == $event['event_xchan']) ? true : false);
$item_thread_top = 1;
if($wall) {
$item_wall = 1;
@@ -1373,20 +1340,20 @@ function event_store_item($arr, $event) {
$arr['mid'] = z_root() . '/activity/' . $event['event_hash'];
}
- $item_arr['aid'] = $z[0]['channel_account_id'];
+ $item_arr['aid'] = $z['channel_account_id'];
$item_arr['uid'] = $arr['uid'];
$item_arr['uuid'] = $arr['uuid'];
$item_arr['author_xchan'] = $arr['event_xchan'];
$item_arr['mid'] = $arr['mid'];
$item_arr['parent_mid'] = $arr['mid'];
- $item_arr['owner_xchan'] = (($wall) ? $z[0]['channel_hash'] : $arr['event_xchan']);
+ $item_arr['owner_xchan'] = (($wall) ? $z['channel_hash'] : $arr['event_xchan']);
$item_arr['author_xchan'] = $arr['event_xchan'];
$item_arr['title'] = $arr['summary'];
$item_arr['allow_cid'] = $arr['allow_cid'];
$item_arr['allow_gid'] = $arr['allow_gid'];
$item_arr['deny_cid'] = $arr['deny_cid'];
$item_arr['deny_gid'] = $arr['deny_gid'];
- $item_arr['item_private'] = $private;
+ $item_arr['item_private'] = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0);
$item_arr['verb'] = 'Invite';
$item_arr['item_wall'] = $item_wall;
$item_arr['item_origin'] = $item_origin;
@@ -1451,16 +1418,21 @@ function event_store_item($arr, $event) {
$item_arr['obj'] = json_encode($y);
}
+ $item_arr['target'] = [
+ 'id' => str_replace('/item/', '/conversation/', $item_arr['parent_mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => z_root() . '/channel/' . $z['channel_address'],
+ ];
+ $item_arr['tgt_type'] = 'Collection';
+
// propagate the event resource_id so that posts containing it are easily searchable in downstream copies
// of the item which have not stored the actual event. Required for Diaspora event federation as Diaspora
// event_participation messages refer to the event resource_id as a parent, while out own event attendance
// activities refer to the item message_id as the parent.
- set_iconfig($item_arr, 'system','event_id',$event['event_hash'],true);
-
- $res = item_store($item_arr);
+ set_iconfig($item_arr, 'system', 'event_id', $event['event_hash'], true);
- $item_id = $res['item_id'];
+ $post = item_store($item_arr, deliver: $deliver);
/**
* @hooks event_created
@@ -1468,7 +1440,7 @@ function event_store_item($arr, $event) {
*/
call_hooks('event_created', $event['id']);
- return $item_id;
+ return $post;
}
}
diff --git a/include/features.php b/include/features.php
index e57859aa8..65ead6604 100644
--- a/include/features.php
+++ b/include/features.php
@@ -4,17 +4,15 @@
* Features management
*/
-
-
-
+use Zotlabs\Lib\Config;
function feature_enabled($uid,$feature) {
- $x = get_config('feature_lock',$feature);
+ $x = Config::Get('feature_lock',$feature);
if($x === false) {
$x = get_pconfig($uid,'feature',$feature);
if($x === false) {
- $x = get_config('feature',$feature);
+ $x = Config::Get('feature',$feature);
if($x === false)
$x = get_feature_default($feature);
}
@@ -38,7 +36,7 @@ function get_feature_default($feature) {
function feature_level($feature,$def) {
- $x = get_config('feature_level',$feature);
+ $x = Config::Get('feature_level',$feature);
if($x !== false)
return intval($x);
return $def;
@@ -86,7 +84,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Start calendar week on Monday'),
t('Default is Sunday'),
false,
- get_config('feature_lock','cal_first_day')
+ Config::Get('feature_lock','cal_first_day')
],
[
@@ -94,7 +92,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Event Timezone Selection'),
t('Allow event creation in timezones other than your own.'),
false,
- get_config('feature_lock','event_tz_select'),
+ Config::Get('feature_lock','event_tz_select'),
]
],
@@ -108,7 +106,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Search by Date'),
t('Ability to select posts by date ranges'),
false,
- get_config('feature_lock','archives')
+ Config::Get('feature_lock','archives')
],
[
@@ -116,7 +114,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Tag Cloud'),
t('Provide a personal tag cloud on your channel page'),
false,
- get_config('feature_lock','tagadelic'),
+ Config::Get('feature_lock','tagadelic'),
],
[
@@ -124,7 +122,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Use blog/list mode'),
t('Comments will be displayed separately'),
false,
- get_config('feature_lock','channel_list_mode'),
+ Config::Get('feature_lock','channel_list_mode'),
]
],
@@ -137,7 +135,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Connection Filtering'),
t('Filter incoming posts from connections based on keywords/content'),
false,
- get_config('feature_lock','connfilter')
+ Config::Get('feature_lock','connfilter')
]
],
@@ -150,7 +148,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Community Tagging'),
t('Ability to tag existing posts'),
false,
- get_config('feature_lock','commtag'),
+ Config::Get('feature_lock','commtag'),
],
*/
[
@@ -158,7 +156,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Emoji Reactions'),
t('Add emoji reaction ability to posts'),
true,
- get_config('feature_lock','emojis'),
+ Config::Get('feature_lock','emojis'),
],
[
@@ -166,15 +164,23 @@ function get_features($filtered = true, $level = (-1)) {
t('Dislike Posts'),
t('Ability to dislike posts/comments'),
false,
- get_config('feature_lock','dislike'),
+ Config::Get('feature_lock','dislike'),
],
[
'star_posts',
t('Star Posts'),
- t('Ability to mark special posts with a star indicator'),
+ t('Ability to mark conversations with a star'),
+ false,
+ Config::Get('feature_lock','star_posts'),
+ ],
+
+ [
+ 'filing',
+ t('File Posts'),
+ t('Ability to file posts'),
false,
- get_config('feature_lock','star_posts'),
+ Config::Get('feature_lock','filing'),
],
[
@@ -182,7 +188,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Reply on comment'),
t('Ability to reply on selected comment'),
false,
- get_config('feature_lock','reply_to'),
+ Config::Get('feature_lock','reply_to'),
]
],
@@ -196,7 +202,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Advanced Directory Search'),
t('Allows creation of complex directory search queries'),
false,
- get_config('feature_lock','advanced_dirsearch'),
+ Config::Get('feature_lock','advanced_dirsearch'),
]
],
@@ -210,7 +216,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Post Categories'),
t('Add categories to your posts'),
false,
- get_config('feature_lock','categories'),
+ Config::Get('feature_lock','categories'),
],
[
@@ -218,7 +224,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Large Photos'),
t('Include large (1024px) photo thumbnails in posts. If not enabled, use small (640px) photo thumbnails'),
false,
- get_config('feature_lock','large_photos'),
+ Config::Get('feature_lock','large_photos'),
],
[
@@ -226,7 +232,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Even More Encryption'),
t('Allow optional encryption of content end-to-end with a shared secret key'),
false,
- get_config('feature_lock','content_encrypt'),
+ Config::Get('feature_lock','content_encrypt'),
],
[
@@ -234,7 +240,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Disable Comments'),
t('Provide the option to disable comments for a post'),
false,
- get_config('feature_lock','disable_comments'),
+ Config::Get('feature_lock','disable_comments'),
],
[
@@ -242,7 +248,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Delayed Posting'),
t('Allow posts to be published at a later date'),
false,
- get_config('feature_lock','delayed_posting'),
+ Config::Get('feature_lock','delayed_posting'),
],
[
@@ -250,7 +256,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Content Expiration'),
t('Remove posts/comments and/or private messages at a future time'),
false,
- get_config('feature_lock','content_expire'),
+ Config::Get('feature_lock','content_expire'),
],
[
@@ -258,7 +264,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Suppress Duplicate Posts/Comments'),
t('Prevent posts with identical content to be published with less than two minutes in between submissions.'),
true,
- get_config('feature_lock','suppress_duplicates'),
+ Config::Get('feature_lock','suppress_duplicates'),
],
[
@@ -266,7 +272,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Auto-save drafts of posts and comments'),
t('Automatically saves post and comment drafts in local browser storage to help prevent accidental loss of compositions'),
true,
- get_config('feature_lock','auto_save_draft'),
+ Config::Get('feature_lock','auto_save_draft'),
]
],
@@ -280,7 +286,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Navigation Channel Select'),
t('Change channels directly from within the navigation dropdown menu'),
false,
- get_config('feature_lock','nav_channel_select'),
+ Config::Get('feature_lock','nav_channel_select'),
]
],
@@ -294,7 +300,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Events Filter'),
t('Ability to display only events'),
false,
- get_config('feature_lock','events_tab')
+ Config::Get('feature_lock','events_tab')
],
[
@@ -302,7 +308,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Polls Filter'),
t('Ability to display only polls'),
false,
- get_config('feature_lock','polls_tab')
+ Config::Get('feature_lock','polls_tab')
],
[
@@ -310,7 +316,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Saved Searches'),
t('Save search terms for re-use'),
false,
- get_config('feature_lock','savedsearch')
+ Config::Get('feature_lock','savedsearch')
],
[
@@ -318,7 +324,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Saved Folders'),
t('Ability to file posts under folders'),
false,
- get_config('feature_lock','filing'),
+ Config::Get('feature_lock','filing'),
],
[
@@ -326,7 +332,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Alternate Stream Order'),
t('Ability to order the stream by last post date, last comment date or unthreaded activities'),
false,
- get_config('feature_lock','order_tab')
+ Config::Get('feature_lock','order_tab')
],
[
@@ -334,7 +340,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Contact Filter'),
t('Ability to display only posts of a selected contact'),
false,
- get_config('feature_lock','name_tab')
+ Config::Get('feature_lock','name_tab')
],
[
@@ -342,7 +348,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Forum Filter'),
t('Ability to display only posts of a specific forum'),
false,
- get_config('feature_lock','forums_tab')
+ Config::Get('feature_lock','forums_tab')
],
[
@@ -350,7 +356,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Personal Posts Filter'),
t('Ability to display only posts that you\'ve interacted on'),
false,
- get_config('feature_lock','personal_tab')
+ Config::Get('feature_lock','personal_tab')
],
[
@@ -358,7 +364,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Use blog/list mode'),
t('Comments will be displayed separately'),
false,
- get_config('feature_lock','network_list_mode'),
+ Config::Get('feature_lock','network_list_mode'),
]
],
@@ -372,7 +378,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Photo Location'),
t('If location data is available on uploaded photos, link this to a map.'),
false,
- get_config('feature_lock','photo_location'),
+ Config::Get('feature_lock','photo_location'),
],
[
@@ -380,7 +386,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Flag Adult Photos'),
t('Provide photo edit option to hide inappropriate photos from default album view'),
false,
- get_config('feature_lock','adult_photo_flagging'),
+ Config::Get('feature_lock','adult_photo_flagging'),
]
],
@@ -394,7 +400,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Advanced Profiles'),
t('Additional profile sections and selections'),
false,
- get_config('feature_lock','advanced_profiles')
+ Config::Get('feature_lock','advanced_profiles')
],
[
@@ -402,7 +408,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Profile Import/Export'),
t('Save and load profile details across sites/channels'),
false,
- get_config('feature_lock','profile_export')
+ Config::Get('feature_lock','profile_export')
],
[
@@ -410,7 +416,7 @@ function get_features($filtered = true, $level = (-1)) {
t('Multiple Profiles'),
t('Ability to create multiple profiles'),
false,
- get_config('feature_lock','multi_profiles')
+ Config::Get('feature_lock','multi_profiles')
]
]
diff --git a/include/feedutils.php b/include/feedutils.php
index f05c15414..1487ea2d6 100644
--- a/include/feedutils.php
+++ b/include/feedutils.php
@@ -4,6 +4,8 @@
* @brief Some functions to work with XML feeds.
*/
+use Zotlabs\Lib\Config;
+
/**
* @brief Return an Atom feed for channel.
*
@@ -226,15 +228,24 @@ function construct_activity_target($item) {
if($item['target']) {
$o = '<as:target>' . "\r\n";
$r = json_decode($item['target'],false);
- if(! $r)
+
+ if (!$r) {
return '';
- if($r->type)
+ }
+
+ if (isset($r->type)) {
$o .= '<as:obj_type>' . xmlify($r->type) . '</as:obj_type>' . "\r\n";
- if($r->id)
+ }
+
+ if (isset($r->id)) {
$o .= '<id>' . xmlify($r->id) . '</id>' . "\r\n";
- if($r->title)
+ }
+
+ if (isset($r->title)) {
$o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n";
- if($r->links) {
+ }
+
+ if (isset($r->link)) {
/** @FIXME !!! */
if(substr($r->link,0,1) === '<') {
if(strstr($r->link,'&') && (! strstr($r->link,'&amp;')))
@@ -242,11 +253,14 @@ function construct_activity_target($item) {
$r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link);
$o .= $r->link;
}
- else
+ else {
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n";
+ }
}
- if($r->content)
+
+ if(isset($r->content)) {
$o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n";
+ }
$o .= '</as:target>' . "\r\n";
@@ -309,7 +323,7 @@ function get_atom_author($feed, $item) {
$base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
if($base && count($base)) {
foreach($base as $link) {
- if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
+ if($link['attribs']['']['rel'] === 'alternate' && (!$author['author_link']))
$author['author_link'] = unxmlify($link['attribs']['']['href']);
if(!x($author, 'author_photo') || ! $author['author_photo']) {
if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
@@ -355,7 +369,7 @@ function get_atom_author($feed, $item) {
if($base && count($base)) {
foreach($base as $link) {
- if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
+ if($link['attribs']['']['rel'] === 'alternate' && (!$author['author_link']))
$author['author_link'] = unxmlify($link['attribs']['']['href']);
if(! (x($author,'author_photo'))) {
if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
@@ -996,7 +1010,7 @@ function process_feed_tombstones($feed,$importer,$contact,$pass) {
if(! intval($item['item_deleted'])) {
logger('deleting item ' . $item['id'] . ' mid=' . $item['mid'], LOGGER_DEBUG);
- drop_item($item['id'],false);
+ drop_item($item['id']);
}
}
}
@@ -1037,7 +1051,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
- $sys_expire = intval(get_config('system', 'default_expire_days'));
+ $sys_expire = intval(Config::Get('system', 'default_expire_days'));
$chn_expire = intval($importer['channel_expire_days']);
$expire_days = $sys_expire;
@@ -1171,15 +1185,19 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
intval($importer['channel_id'])
);
-
// Update content if 'updated' changes
- if($r) {
- if(activity_match($datarray['verb'], ['Delete', ACTIVITY_DELETE])
- && $datarray['author_xchan'] === $r[0]['author_xchan']) {
+ if ($r) {
+ // Check ownership
+ if ($datarray['author_xchan'] !== $r[0]['author_xchan']) {
+ logger('stored item author is not imported item author', LOGGER_DEBUG);
+ continue;
+ }
+
+ if (activity_match($datarray['verb'], ['Delete', ACTIVITY_DELETE])) {
if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
- drop_item($r[0]['id'],false);
+ drop_item($r[0]['id']);
}
continue;
}
@@ -1325,7 +1343,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// but save the thread_parent in case we need to refer to it later.
if($importer['channel_system']) {
- if( ! \Zotlabs\Lib\MessageFilter::evaluate($datarray,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) {
+ if( ! \Zotlabs\Lib\MessageFilter::evaluate($datarray,Config::Get('system','pubstream_incl'),Config::Get('system','pubstream_excl'))) {
continue;
}
}
@@ -1442,12 +1460,17 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// Update content if 'updated' changes
- if($r) {
- if(isset($datarray['verb']) && activity_match($datarray['verb'], ['Delete', ACTIVITY_DELETE])
- && isset($datarray['author_xchan']) && $datarray['author_xchan'] === $r[0]['author_xchan']) {
+ if ($r) {
+ // Check ownership
+ if ($datarray['author_xchan'] !== $r[0]['author_xchan']) {
+ logger('stored item author is not imported item author', LOGGER_DEBUG);
+ continue;
+ }
+
+ if (isset($datarray['verb']) && activity_match($datarray['verb'], ['Delete', ACTIVITY_DELETE])) {
if(! intval($r[0]['item_deleted'])) {
logger('deleting item ' . $r[0]['id'] . ' mid=' . $datarray['mid'], LOGGER_DEBUG);
- drop_item($r[0]['id'],false);
+ drop_item($r[0]['id'], uid: $importer['channel_id']);
}
continue;
}
@@ -1481,7 +1504,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
}
if($importer['channel_system']) {
- if( ! \Zotlabs\Lib\MessageFilter::evaluate($datarray,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) {
+ if( ! \Zotlabs\Lib\MessageFilter::evaluate($datarray,Config::Get('system','pubstream_incl'),Config::Get('system','pubstream_excl'))) {
continue;
}
}
diff --git a/include/help.php b/include/help.php
index 9e4be57f9..2358f1289 100644
--- a/include/help.php
+++ b/include/help.php
@@ -1,207 +1,10 @@
<?php
-use \Michelf\MarkdownExtra;
+use Michelf\MarkdownExtra;
use CommerceGuys\Intl\Language\LanguageRepository;
require_once('include/items.php');
-/**
- * @brief
- *
- * @param string $path
- * @param string $suffix (optional) default null
- * @return string
- */
-function get_help_fullpath($path, $suffix = null) {
-
- $docroot = (\App::$override_helproot) ? \App::$override_helproot : 'doc/';
- $docroot = (substr($docroot,-1)!='/') ? $docroot .= '/' : $docroot;
-
- // Determine the language and modify the path accordingly
- $x = determine_help_language();
- $lang = $x['language'];
-
- // The English translation is at the root of /doc/. Other languages are in
- // subfolders named by the language code such as "de", "es", etc.
- if($lang !== 'en') {
- $langpath = $lang . '/' . $path;
- } else {
- $langpath = $path;
- }
-
- $newpath = (isset(\App::$override_helpfiles[$langpath])) ? \App::$override_helpfiles[$langpath] : $langpath;
- $newpath = ($newpath == $langpath) ? $docroot . $newpath : $newpath;
-
- if ($suffix) {
- if (file_exists($newpath . $suffix)) {
- return $newpath;
- }
- } elseif (file_exists($newpath . '.md') ||
- file_exists($newpath . '.bb') ||
- file_exists($newpath . '.html')) {
- return $newpath;
- }
-
- $newpath = (isset(\App::$override_helpfiles[$path])) ? \App::$override_helpfiles[$path] : null;
-
- $newpath = (!$newpath) ? $docroot.$path : $newpath;
- return $newpath;
-}
-
-
-/**
- * @brief
- *
- * @param string $tocpath (optional) default false
- * @return string
- */
-function get_help_content($tocpath = false) {
-
- $doctype = 'markdown';
-
- $text = '';
-
- $path = (($tocpath !== false) ? $tocpath : '');
- $docroot = (\App::$override_helproot) ? \App::$override_helproot : 'doc/';
- $docroot = (substr($docroot,-1)!='/') ? $docroot .= '/' : $docroot;
-
- if($tocpath === false && argc() > 1) {
- $path = '';
- for($x = 1; $x < argc(); $x ++) {
- if(strlen($path))
- $path .= '/';
- $path .= argv($x);
- }
- }
-
-
- if($path) {
- $fullpath = get_help_fullpath($path);
- $title = basename($path);
- if(! $tocpath)
- \App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title)));
-
- // Check that there is a "toc" or "sitetoc" located at the specified path.
- // If there is not, then there was not a translation of the table of contents
- // available and so default back to the English TOC at /doc/toc.{html,bb,md}
- // TODO: This is incompatible with the hierarchical TOC construction
- // defined in /Zotlabs/Widget/Helpindex.php.
- if($tocpath !== false &&
- load_doc_file($fullpath . '.md') === '' &&
- load_doc_file($fullpath . '.bb') === '' &&
- load_doc_file($fullpath . '.html') === ''
- ) {
- $path = $title;
- }
- $fullpath = get_help_fullpath($path);
- $text = load_doc_file($fullpath . '.md');
-
- if(! $text) {
- $text = load_doc_file($fullpath . '.bb');
- if($text)
- $doctype = 'bbcode';
- }
- if(! $text) {
- $text = load_doc_file($fullpath . '.html');
- if($text)
- $doctype = 'html';
- }
- }
-
- if(($tocpath) && (! $text))
- return '';
-
- if($tocpath === false) {
- if(! $text) {
- $path = 'Site';
- $fullpath = get_help_fullpath($path,'.md');
- $text = load_doc_file($fullpath . '.md');
- \App::$page['title'] = t('Help');
- }
- if(! $text) {
- $doctype = 'bbcode';
- $path = 'main';
- $fullpath = get_help_fullpath($path,'.md');
- $text = load_doc_file($fullpath . '.bb');
- goaway('/help/about/about');
- \App::$page['title'] = t('Help');
- }
-
- if(! $text) {
- header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found'));
- $tpl = get_markup_template("404.tpl");
- return replace_macros($tpl, array(
- '$message' => t('Page not found.')
- ));
- }
- }
-
- if($doctype === 'html')
- $content = parseIdentityAwareHTML($text);
- if($doctype === 'markdown') {
- # escape #include tags
- $text = preg_replace('/#include/ism', '%%include', $text);
- $content = MarkdownExtra::defaultTransform($text);
- $content = preg_replace('/%%include/ism', '#include', $content);
- }
- if($doctype === 'bbcode') {
- require_once('include/bbcode.php');
- $content = zidify_links(bbcode($text));
- // bbcode retargets external content to new windows. This content is internal.
- $content = str_replace(' target="_blank"', '', $content);
- }
-
- $content = preg_replace_callback("/#include (.*?)\;/ism", 'preg_callback_help_include', $content);
-
- return translate_projectname($content);
-}
-
-function preg_callback_help_include($matches) {
-
- if($matches[1]) {
- $include = str_replace($matches[0],load_doc_file($matches[1]),$matches[0]);
- if(preg_match('/\.bb$/', $matches[1]) || preg_match('/\.txt$/', $matches[1])) {
- require_once('include/bbcode.php');
- $include = zidify_links(bbcode($include));
- $include = str_replace(' target="_blank"','',$include);
- }
- elseif(preg_match('/\.md$/', $matches[1])) {
- $include = MarkdownExtra::defaultTransform($include);
- }
- return $include;
- }
-
-}
-
-/**
- * @brief Determines help language.
- *
- * If the language was specified in the URL, override the language preference
- * of the browser. Default to English if both of these are absent.
- *
- * @return array Associative array with:
- * * \e string \b language - 2-letter ISO 639-1 code ("en")
- * * \e boolean \b from_url - true if language from URL overrides browser default
- */
-function determine_help_language() {
-
- $language_repository = new LanguageRepository;
- $languages = $language_repository->getList();
-
- if(array_key_exists(argv(1), $languages)) {
- $lang = argv(1);
- $from_url = true;
- } else {
- $lang = \App::$language;
- if(! isset($lang))
- $lang = 'en';
-
- $from_url = false;
- }
-
- return array('language' => $lang, 'from_url' => $from_url);
-}
-
function load_doc_file($s) {
$c = find_doc_file($s);
@@ -353,12 +156,12 @@ function store_doc_file($s) {
if($r) {
$item['id'] = $r[0]['id'];
$item['mid'] = $item['parent_mid'] = $r[0]['mid'];
- $x = item_store_update($item);
+ $x = item_store_update($item, deliver: false, addAndSync: false);
}
else {
$item['uuid'] = item_message_id();
$item['mid'] = $item['parent_mid'] = z_root() . '/item/' . $item['uuid'];
- $x = item_store($item);
+ $x = item_store($item, deliver: false, addAndSync: false);
}
return $x;
diff --git a/include/html2bbcode.php b/include/html2bbcode.php
index 03e09cd62..b799a0c28 100644
--- a/include/html2bbcode.php
+++ b/include/html2bbcode.php
@@ -26,6 +26,7 @@ function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb)
$xpath = new DomXPath($doc);
$list = $xpath->query("//".$oldnode);
+
foreach ($list as $oldNode) {
$attr = array();
@@ -113,13 +114,6 @@ function html2bbcode($message)
$message = str_replace("\r", "", $message);
- $message = str_replace(array(
- "<li><p>",
- "</p></li>"),
- array(
- "<li>",
- "</li>"),
- $message);
// remove namespaces
$message = preg_replace('=<(\w+):(.+?)>=', '<removeme>', $message);
@@ -129,7 +123,16 @@ function html2bbcode($message)
//$message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8");
$message = mb_encode_numericentity($message, [0x80, 0x10FFFF, 0, ~0], 'UTF-8');
+ // TODO: It would be better to do the list parsing with node2bbcode() but it has serious issues when
+ // parsing nested lists. Especially if the li tag has no closing tag (which is valid).
+ $message = preg_replace('/\<ul(.*?)\>/', '[list]', $message);
+ $message = preg_replace('/\<ol(.*?)\>/', '[list=1]', $message);
+
+ $message = str_replace(['<li><p>', '</p></li>'], ['<li>', '</li>'], $message);
+ $message = preg_replace('/\<li(.*?)\>/', '[*]', $message);
+ $message = str_replace(['</ul>', '</ol>'], '[/list]', $message);
+ $message = str_replace('</li>', '', $message);
if(!$message)
return;
@@ -185,7 +188,11 @@ function html2bbcode($message)
node2bbcode($doc, 'b', array(), '[b]', '[/b]');
node2bbcode($doc, 'i', array(), '[i]', '[/i]');
node2bbcode($doc, 'u', array(), '[u]', '[/u]');
+ // The s tag is deprecated in HTML5
node2bbcode($doc, 's', array(), '[s]', '[/s]');
+ node2bbcode($doc, 'del', [], '[s]', '[/s]');
+
+
node2bbcode($doc, 'mark', array(), '[mark]', '[/mark]');
node2bbcode($doc, 'span', array(), "", "");
@@ -205,21 +212,13 @@ function html2bbcode($message)
node2bbcode($doc, 'audio', array('src'=>'/(.+)/'), '[audio]$1', '[/audio]');
// node2bbcode($doc, 'iframe', array('src'=>'/(.+)/'), '[iframe]$1', '[/iframe]');
-
- node2bbcode($doc, 'ul', array(), "[list]", "[/list]");
- node2bbcode($doc, 'ol', array(), "[list=1]", "[/list]");
- node2bbcode($doc, 'li', array(), "[*]", "");
-
node2bbcode($doc, 'hr', array(), "[hr]", "");
-// node2bbcode($doc, 'table', array(), "", "");
-// node2bbcode($doc, 'tr', array(), "\n", "");
-// node2bbcode($doc, 'td', array(), "\t", "");
-
- node2bbcode($doc, 'table', array(), "[table]", "[/table]");
node2bbcode($doc, 'th', array(), "[th]", "[/th]");
node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
node2bbcode($doc, 'td', array(), "[td]", "[/td]");
+ node2bbcode($doc, 'table', array(), "[table]", "[/table]");
+
node2bbcode($doc, 'h1', array(), "[h1]", "[/h1]");
node2bbcode($doc, 'h2', array(), "[h2]", "[/h2]");
diff --git a/include/html2plain.php b/include/html2plain.php
index 5cb7ee35d..69fb5193a 100644
--- a/include/html2plain.php
+++ b/include/html2plain.php
@@ -129,6 +129,8 @@ function html2plain($html, $wraplength = 75, $compact = false)
if(!$message)
return;
+ $message = preg_replace('/\<li(.*?)\>/', "\n*", $message);
+ $message = str_replace('</li>', '', $message);
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
@@ -178,7 +180,7 @@ function html2plain($html, $wraplength = 75, $compact = false)
//node2bbcode($doc, 'ul', array(), "\n[list]", "[/list]\n");
//node2bbcode($doc, 'ol', array(), "\n[list=1]", "[/list]\n");
- node2bbcode($doc, 'li', array(), "\n* ", "\n");
+ //node2bbcode($doc, 'li', array(), "\n* ", "\n");
node2bbcode($doc, 'hr', array(), "\n".str_repeat("-", 70)."\n", "");
@@ -194,7 +196,7 @@ function html2plain($html, $wraplength = 75, $compact = false)
// Problem: there is no reliable way to detect if it is a link to a tag or profile
//node2bbcode($doc, 'a', array('href'=>'/(.+)/'), ' $1 ', '', true);
- node2bbcode($doc, 'a', array('href'=>'/(.+)/', 'rel'=>'oembed'), ' $1 ', '', true);
+ node2bbcode($doc, 'a', array('href'=>'/(.+)/', 'rel'=>'oembed'), ' $1 ', '');
//node2bbcode($doc, 'img', array('alt'=>'/(.+)/'), '$1', '');
//node2bbcode($doc, 'img', array('title'=>'/(.+)/'), '$1', '');
//node2bbcode($doc, 'img', array(), '', '');
@@ -203,7 +205,7 @@ function html2plain($html, $wraplength = 75, $compact = false)
else
node2bbcode($doc, 'img', array('src'=>'/(.+)/'), '', '');
- node2bbcode($doc, 'iframe', array('src'=>'/(.+)/'), ' $1 ', '', true);
+ node2bbcode($doc, 'iframe', array('src'=>'/(.+)/'), ' $1 ', '');
$message = $doc->saveHTML();
diff --git a/include/hubloc.php b/include/hubloc.php
index 4d2980a6b..982455f9c 100644
--- a/include/hubloc.php
+++ b/include/hubloc.php
@@ -5,6 +5,7 @@
*/
use Zotlabs\Daemon\Master;
+use Zotlabs\Lib\Config;
/**
* @brief Create an array for hubloc table and insert record.
@@ -129,7 +130,7 @@ function remove_obsolete_hublocs() {
$r = q("select hubloc_id from hubloc where hubloc_url = '%s' and hubloc_sitekey = '%s'",
dbesc(z_root()),
- dbesc(get_config('system', 'pubkey'))
+ dbesc(Config::Get('system', 'pubkey'))
);
if((! $r) || (! count($r)))
return;
@@ -139,11 +140,11 @@ function remove_obsolete_hublocs() {
// Do we have any invalid ones?
$r = q("select hubloc_id, hubloc_hash from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s'",
- dbesc(get_config('system', 'pubkey')),
+ dbesc(Config::Get('system', 'pubkey')),
dbesc(z_root())
);
$p = q("select hubloc_id, hubloc_hash from hubloc where hubloc_sitekey != '%s' and hubloc_url = '%s'",
- dbesc(get_config('system', 'pubkey')),
+ dbesc(Config::Get('system', 'pubkey')),
dbesc(z_root())
);
if(is_array($r) && is_array($p))
@@ -156,7 +157,7 @@ function remove_obsolete_hublocs() {
logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.');
- $interval = get_config('queueworker', 'queue_interval', 500000);
+ $interval = Config::Get('queueworker', 'queue_interval', 500000);
foreach($r as $rr) {
q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d",
diff --git a/include/import.php b/include/import.php
index 7dac518f5..77d35a3e7 100644
--- a/include/import.php
+++ b/include/import.php
@@ -1,6 +1,7 @@
<?php
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\IConfig;
use Zotlabs\Lib\Libzot;
@@ -824,13 +825,13 @@ function import_items($channel, $items, $sync = false, $relocate = null) {
if($item['edited'] >= $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
- $item_result = item_store_update($item,$allow_code,$deliver);
+ $item_result = item_store_update($item, $allow_code, $deliver, addAndSync: false);
}
}
else {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
- $item_result = item_store($item,$allow_code,$deliver);
+ $item_result = item_store($item, $allow_code, $deliver, addAndSync: false);
}
// preserve conversations you've been involved in from being expired
@@ -1479,7 +1480,7 @@ function sync_files($channel, $files) {
fclose($fp);
// Override remote hub thumbnails storage settings
- if(! boolval(get_config('system','photo_storage_type', 1))) {
+ if(! boolval(Config::Get('system','photo_storage_type', 1))) {
$p['os_storage'] = 0;
$p['content'] = file_get_contents($stored_image);
@unlink($stored_image);
@@ -1885,7 +1886,7 @@ function import_webpage_element($element, $channel, $type) {
$arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original
if($arr['edited'] > $i[0]['edited'])
- $x = item_store_update($arr,$execflag);
+ $x = item_store_update($arr, $execflag, deliver: false, addAndSync: false);
}
else {
if(($i) && (intval($i[0]['item_deleted']))) {
@@ -1896,7 +1897,7 @@ function import_webpage_element($element, $channel, $type) {
);
}
else
- $x = item_store($arr,$execflag);
+ $x = item_store($arr, $execflag, deliver: false, addAndSync: false);
}
if($x && $x['success']) {
diff --git a/include/items.php b/include/items.php
index a5a23650e..1f3671c83 100644
--- a/include/items.php
+++ b/include/items.php
@@ -4,6 +4,7 @@
* @brief Items related functions.
*/
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Crypto;
use Zotlabs\Lib\Enotify;
use Zotlabs\Lib\MarkdownSoap;
@@ -35,10 +36,10 @@ require_once('include/permissions.php');
* @param boolean $include_groups
* @return array containing the recipients
*/
-function collect_recipients($item, &$private_envelope,$include_groups = true) {
+function collect_recipients($item, &$private_envelope, $include_groups = true) {
$private_envelope = ((intval($item['item_private'])) ? true : false);
- $recipients = array();
+ $recipients = [];
if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) {
@@ -53,8 +54,15 @@ function collect_recipients($item, &$private_envelope,$include_groups = true) {
$allow_groups = [];
}
- $raw_recipients = array_unique(array_merge($allow_people, $allow_groups));
- $recipients = deliverable_abook_xchans($item['uid'], $raw_recipients);
+ $recipients = array_unique(array_merge($allow_people, $allow_groups));
+
+ if ($recipients) {
+ // deliverable_abook_xchans() will return all deliverable xchans
+ // if passed an empty array as 2nd argument (no filtering).
+ // Hence only call it if we do actually have any recipients.
+ $recipients = deliverable_abook_xchans($item['uid'], $recipients);
+ }
+
// if you specifically deny somebody but haven't allowed anybody, we'll allow everybody in your
// address book minus the denied connections. The post is still private and can't be seen publicly
@@ -250,6 +258,25 @@ function item_normal() {
return $sql;
}
+function item_forwardable($item) {
+ if (intval($item['item_unpublished']) ||
+ intval($item['item_delayed']) ||
+ intval($item['item_blocked']) ||
+ intval($item['item_hidden']) ||
+ intval($item['item_restrict']) || // this might change in the future
+ // internal follow/unfollow thread
+ in_array($item['verb'], ['Follow', 'Ignore', ACTIVITY_FOLLOW, ACTIVITY_UNFOLLOW]) ||
+ str_contains($item['postopts'], 'nodeliver') ||
+ // actor not fetchable
+ (isset($item['author']['xchan_network']) && in_array($item['author']['xchan_network'], ['rss', 'anon', 'token']))
+
+ ) {
+ return false;
+ }
+
+ return true;
+}
+
function item_normal_search() {
return " and item.item_hidden = 0 and item.item_type in (0,3,6,7) and item.item_deleted = 0
and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
@@ -353,7 +380,7 @@ function can_comment_on_post($observer_xchan, $item) {
case 'specific':
case 'contacts':
case '':
- if(local_channel() && get_abconfig(local_channel(), (($item['verb'] === ACTIVITY_SHARE) ? $item['source_xchan'] : $item['owner_xchan']), 'their_perms', 'post_comments')) {
+ if(local_channel() && get_abconfig(local_channel(), $item['owner_xchan'], 'their_perms', 'post_comments')) {
return true;
}
if(intval($item['item_wall']) && perm_is_allowed($item['uid'],$observer_xchan,'post_comments')) {
@@ -423,8 +450,9 @@ function add_source_route($iid, $hash) {
* * \e boolean \b success true or false
* * \e array \b activity the resulting activity if successful
*/
-function post_activity_item($arr, $allow_code = false, $deliver = true) {
+
+function post_activity_item($arr, $allow_code = false, $deliver = true, $channel = null, $observer = null, $addAndSync = true) {
$ret = array('success' => false);
$is_comment = false;
@@ -438,8 +466,13 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
if(! array_key_exists('item_thread_top',$arr) && (! $is_comment))
$arr['item_thread_top'] = 1;
- $channel = App::get_channel();
- $observer = App::get_observer();
+ if (!$channel) {
+ $channel = App::get_channel();
+ }
+
+ if (!$observer) {
+ $observer = App::get_observer();
+ }
$arr['aid'] = ((x($arr,'aid')) ? $arr['aid'] : $channel['channel_account_id']);
$arr['uid'] = ((x($arr,'uid')) ? $arr['uid'] : $channel['channel_id']);
@@ -485,6 +518,14 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
$arr['plink'] = $arr['mid'];
}
+ if (!$arr['target']) {
+ $arr['target'] = [
+ 'id' => str_replace('/item/', '/conversation/', $arr['parent_mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => z_root() . '/channel/' . $channel['channel_address'],
+ ];
+ $arr['tgt_type'] = 'Collection';
+ }
// for the benefit of plugins, we will behave as if this is an API call rather than a normal online post
@@ -501,29 +542,30 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
return $ret;
}
- $post = item_store($arr,$allow_code,$deliver);
-
- if($post['success']) {
- $post_id = $post['item_id'];
- $ret['success'] = true;
- $ret['item_id'] = $post_id;
- $ret['activity'] = $post['item'];
+ $post = item_store($arr, $allow_code, $deliver, $addAndSync);
- /**
- * @hooks post_local_end
- * Called after a local post operation has completed.
- * * \e array - the item returned from item_store()
- */
- call_hooks('post_local_end', $ret['activity']);
- }
- else
+ if (!$post['success']) {
return $ret;
-
- if($post_id && $deliver) {
- Master::Summon(['Notifier','activity', $post_id]);
}
+ $post_id = $post['item_id'];
$ret['success'] = true;
+ $ret['item_id'] = $post_id;
+ $ret['activity'] = $post['item'];
+
+ /**
+ * @hooks post_local_end
+ * Called after a local post operation has completed.
+ * * \e array - the item returned from item_store()
+ */
+ call_hooks('post_local_end', $ret['activity']);
+
+ if($post_id && $deliver) {
+ Master::Summon(['Notifier', 'activity', $post_id]);
+ if (!empty($post['approval_id'])) {
+ Master::Summon(['Notifier', 'activity', $post['approval_id']]);
+ }
+ }
return $ret;
}
@@ -1078,7 +1120,7 @@ function encode_item($item,$mirror = false,$zap_compat = false) {
$x['type'] = 'activity';
$x['encoding'] = 'zot';
- $key = get_config('system','prvkey');
+ $key = Config::Get('system','prvkey');
// If we're trying to backup an item so that it's recoverable or for export/imprt,
// add all the attributes we need to recover it
@@ -1586,7 +1628,7 @@ function item_json_encapsulate($arr, $k) {
* * \e boolean \b success
* * \e int \b item_id
*/
-function item_store($arr, $allow_exec = false, $deliver = true) {
+function item_store($arr, $allow_exec = false, $deliver = true, $addAndSync = true) {
$d = [
'item' => $arr,
@@ -1768,16 +1810,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
if((! array_key_exists('item_nocomment',$arr)) && ($arr['comment_policy'] == 'none'))
$arr['item_nocomment'] = 1;
- // handle time travelers
- // Allow a bit of fudge in case somebody just has a slightly slow/fast clock
-
- $d1 = new DateTime('now +10 minutes', new DateTimeZone('UTC'));
- $d2 = new DateTime($arr['created'] . '+00:00');
-
- if($d2 > $d1) {
- $arr['item_delayed'] = 1;
- }
-
if(empty($arr['llink'])) {
$arr['llink'] = z_root() . '/display/' . $arr['uuid'];
}
@@ -1819,7 +1851,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
);
}
- if(comments_are_now_closed($r[0])) {
+ if(comments_are_now_closed($r[0]) && !in_array($arr['verb'], ['Add', 'Remove'])) {
logger('item_store: comments closed');
$ret['message'] = 'Comments closed.';
return $ret;
@@ -1874,7 +1906,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['item_private'] = 0;
if(in_array($arr['obj_type'], ['Note','Answer']) && $r[0]['obj_type'] === 'Question' && intval($r[0]['item_wall'])) {
- Activity::update_poll($r[0]['id'], $arr);
+ Activity::update_poll($r[0], $arr);
}
}
@@ -2044,6 +2076,13 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
Master::Summon([ 'Cache_embeds', $current_post ]);
}
+ $ret['success'] = true;
+ $ret['item_id'] = $current_post;
+
+ if ($addAndSync) {
+ $ret = addToCollectionAndSync($ret);
+ }
+
// If _creating_ a deleted item, don't propagate it further or send out notifications.
// We need to store the item details just in case the delete came in before the original post,
// so that we have an item in the DB that's marked deleted and won't store a fresh post
@@ -2054,9 +2093,6 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
tag_deliver($arr['uid'],$current_post);
}
- $ret['success'] = true;
- $ret['item_id'] = $current_post;
-
return $ret;
}
@@ -2069,7 +2105,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
* @param boolean $deliver (optional) default true
* @return array
*/
-function item_store_update($arr, $allow_exec = false, $deliver = true) {
+function item_store_update($arr, $allow_exec = false, $deliver = true, $addAndSync = true) {
$d = [
'item' => $arr,
@@ -2203,7 +2239,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
$arr['revision'] = ((x($arr,'revision') && $arr['revision'] > 0) ? intval($arr['revision']) : 0);
- if(array_key_exists('comments_closed',$arr) && $arr['comments_closed'] > NULL_DATE)
+ if(array_key_exists('comments_closed',$arr))
$arr['comments_closed'] = datetime_convert('UTC','UTC',$arr['comments_closed']);
else
$arr['comments_closed'] = $orig[0]['comments_closed'];
@@ -2382,17 +2418,19 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
Master::Summon([ 'Cache_embeds', $orig_post_id ]);
}
+ $ret['success'] = true;
+ $ret['item_id'] = $orig_post_id;
-
+ if ($addAndSync) {
+ $ret = addToCollectionAndSync($ret);
+ }
if($deliver) {
- send_status_notifications($orig_post_id,$arr);
+ // don't send notify_comment for edits
+ // send_status_notifications($orig_post_id,$arr);
tag_deliver($uid,$orig_post_id);
}
- $ret['success'] = true;
- $ret['item_id'] = $orig_post_id;
-
return $ret;
}
@@ -2696,7 +2734,7 @@ function tag_deliver($uid, $item_id) {
logger('Post mentions: ' . print_r($terms,true), LOGGER_DATA);
}
- $max_forums = get_config('system','max_tagged_forums',2);
+ $max_forums = Config::Get('system','max_tagged_forums',2);
$matched_forums = 0;
@@ -2943,35 +2981,32 @@ function tgroup_check($uid, $item) {
// post to group via DM
if ($is_group) {
- if (intval($item['item_private']) === 2 && $item['mid'] === $item['parent_mid']) {
+ if (intval($item['item_private']) === 2 && $item['mid'] === $item['parent_mid'] && perm_is_allowed($uid, $item['owner_xchan'], 'post_wall')) {
return true;
}
}
-
// see if we already have this item. Maybe it is being updated.
$r = q("select id from item where mid = '%s' and uid = %d limit 1",
dbesc($item['mid']),
intval($uid)
);
- if($r)
- return true;
- if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver'))
- return false;
+ if ($r) {
+ return true;
+ }
- $u = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
- intval($uid)
- );
+ $u = channelx_by_n($uid);
- if(! $u)
+ if (!$u) {
return false;
+ }
- $max_forums = get_config('system','max_tagged_forums',2);
+ $max_forums = Config::Get('system','max_tagged_forums',2);
$matched_forums = 0;
- $link = normalise_link($u[0]['xchan_url']);
+ $link = normalise_link($u['xchan_url']);
$terms = [];
@@ -2988,7 +3023,7 @@ function tgroup_check($uid, $item) {
}
$mention = true;
- logger('tgroup_check: mention found for ' . $u[0]['channel_name']);
+ logger('tgroup_check: mention found for ' . $u['channel_name']);
// At this point we've determined that the person receiving this post was mentioned in it.
// Now let's check if this mention was inside a reshare so we don't spam a forum
@@ -3073,7 +3108,7 @@ function i_am_mentioned($channel, $item, $check_groups = false) {
}
}
}
- $unless = intval(get_pconfig($channel['channel_id'], 'system', 'unless_mention_count', get_config('system', 'unless_mention_count', 20)));
+ $unless = intval(get_pconfig($channel['channel_id'], 'system', 'unless_mention_count', Config::Get('system', 'unless_mention_count', 20)));
if ($unless && $terms && count($terms) > $unless) {
$tagged = false;
}
@@ -3096,6 +3131,11 @@ function i_am_mentioned($channel, $item, $check_groups = false) {
*/
function start_delivery_chain($channel, $item, $item_id, $parent, $group = false, $edit = false) {
+ if ($item['author_xchan'] === $channel['channel_hash'] && in_array($item['verb'], ['Add', 'Remove'])) {
+ logger('delivery chain already started');
+ return;
+ }
+
$sourced = check_item_source($channel['channel_id'],$item);
if($sourced) {
@@ -3141,17 +3181,113 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$item['parent_mid'] = $item['mid'];
$item['thr_parent'] = $item['mid'];
$item['llink'] = z_root() . '/display/' . $item['uuid'];
+ $item['target'] = json_encode([
+ 'id' => str_replace('/item/', '/conversation/', $item['mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => z_root() . '/channel/' . $channel['channel_address']
+ ]);
+ $item['tgt_type'] = 'Collection';
}
+ }
- $r = q("UPDATE item SET author_xchan = '%s', mid = '%s', parent_mid = '%s', thr_parent = '%s', llink = '%s' WHERE id = %d",
- dbesc($item['author_xchan']),
- dbesc($item['mid']),
- dbesc($item['parent_mid']),
- dbesc($item['thr_parent']),
- dbesc($item['llink']),
+ $private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
+ || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
+
+ $new_public_policy = map_scope(PermissionLimits::Get($channel['channel_id'],'view_stream'),true);
+
+ if((! $private) && $new_public_policy)
+ $private = 1;
+
+ $item_wall = 1;
+ $item_origin = (($item['item_deleted']) ? 0 : 1); // item_origin for deleted items is set to 0 in delete_imported_item() to prevent looping. In this case we probably should not set it back to 1 here.
+ $item_uplink = 0;
+ $item_nocomment = 0;
+
+ $flag_bits = $item['item_flags'];
+
+ // maintain the original source, which will be the original item owner and was stored in source_xchan
+ // when we created the delivery fork
+
+ if($parent) {
+ $r = q("update item set source_xchan = '%s' where id = %d",
+ dbesc($parent['source_xchan']),
+ intval($item_id)
+ );
+ }
+ else {
+ $item_uplink = (($item['item_rss']) ? 0 : 1); // Do not set item_uplink for rss items - we can not send anything to them.
+
+ // if this is an edit, item_store_update() will have already updated the item
+ // with the correct value for source_xchan (by ignoring it). We cannot set to owner_xchan
+ // in this case because owner_xchan will point to the parent of this chain
+ // and not the original sender.
+
+ if(!$edit) {
+ $r = q("update item set source_xchan = owner_xchan where id = %d",
+ intval($item_id)
+ );
+ }
+ }
+
+ // this will not work with item_store_update()
+
+ $r = q("update item set item_uplink = %d, item_nocomment = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
+ deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s', item_wall = %d, item_origin = %d,
+ author_xchan = '%s', mid = '%s', parent_mid = '%s', thr_parent = '%s', llink = '%s', target = '%s', tgt_type = '%s' where id = %d",
+ intval($item_uplink),
+ intval($item_nocomment),
+ intval($flag_bits),
+ dbesc($channel['channel_hash']),
+ dbesc($channel['channel_allow_cid']),
+ dbesc($channel['channel_allow_gid']),
+ dbesc($channel['channel_deny_cid']),
+ dbesc($channel['channel_deny_gid']),
+ intval($private),
+ dbesc($new_public_policy),
+ dbesc(map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'))),
+ dbesc($item['title']),
+ dbesc($item['body']),
+ intval($item_wall),
+ intval($item_origin),
+ dbesc($item['author_xchan']),
+ dbesc($item['mid']),
+ dbesc($item['parent_mid']),
+ dbesc($item['thr_parent']),
+ dbesc($item['llink']),
+ dbesc($item['target']),
+ dbesc($item['tgt_type']),
+ intval($item_id)
+ );
+
+ if($r) {
+ $rr = q("select * from item where id = %d",
intval($item_id)
);
+
+ if ($rr) {
+
+ // this is hackish but since we can not use item_store_update() here,
+ // we will prepare a similar output to feed to addToCollectionAndSync()
+ $ret['success'] = 1;
+ $ret['item_id'] = $rr[0]['id'];
+ $ret['item'] = $rr[0];
+
+ $result = addToCollectionAndSync($ret);
+
+ Master::Summon(['Notifier', 'tgroup', $result['item_id']]);
+ if ($result['approval_id']) {
+ Master::Summon(['Notifier', 'tgroup', $result['approval_id']]);
+ }
+ }
}
+ else {
+ logger('start_delivery_chain: failed to update item');
+ // reset the source xchan to prevent loops
+ $r = q("update item set source_xchan = '' where id = %d",
+ intval($item_id)
+ );
+ }
+ return;
}
if ($group && (! $parent)) {
@@ -3173,8 +3309,8 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
if ($r) {
if (intval($item['item_deleted'])) {
- drop_item($r[0]['id'], false, DROPITEM_PHASE1);
- Master::Summon([ 'Notifier', 'drop', $r[0]['id'] ]);
+ drop_item($r[0]['id'], DROPITEM_PHASE1, uid: $r[0]['uid']);
+ Master::Summon(['Notifier', 'drop' ,$r[0]['id']]);
return;
}
$arr['id'] = intval($r[0]['id']);
@@ -3191,9 +3327,14 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
}
else {
- $arr['uuid'] = item_message_id();
+ // To prevent duplicates from possible clones of the forum/group,
+ // we will create a v5 UUID of the source item mid.
+ // Add some extra entropy to prevent duplicate UUIDs with items where we already
+ // created an UUID from the mid (activities which do not provide an UUID field).
+ $arr['uuid'] = uuid_from_url($item['mid'] . '#group_item');
$arr['mid'] = z_root() . '/item/' . $arr['uuid'];
$arr['parent_mid'] = $arr['mid'];
+ $arr['plink'] = $arr['mid'];
}
$arr['aid'] = $channel['channel_account_id'];
@@ -3254,8 +3395,15 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
}
$arr['title'] = $item['title'];
- $arr['tgt_type'] = $item['tgt_type'];
- $arr['target'] = $item['target'];
+// $arr['tgt_type'] = $item['tgt_type'];
+// $arr['target'] = $item['target'];
+
+ $arr['tgt_type'] = 'Collection';
+ $arr['target'] = [
+ 'id' => str_replace('/item/', '/conversation/', $arr['parent_mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => channel_url($channel['channel_address'])
+ ];
$arr['term'] = $item['term'];
@@ -3278,10 +3426,14 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$post = item_store($arr);
}
- $post_id = $post['item_id'];
+ $post_id = $post['item_id'] ?? 0;
+ $approval_id = $post['approval_id'] ?? 0;
if($post_id) {
Master::Summon([ 'Notifier','tgroup',$post_id ]);
+ if ($approval_id) {
+ Master::Summon(['Notifier', 'tgroup', $approval_id]);
+ }
}
return;
}
@@ -3306,14 +3458,14 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
if ($edit) {
if (intval($item['item_deleted'])) {
- drop_item($item['id'],false,DROPITEM_PHASE1);
- Master::Summon([ 'Notifier','drop',$item['id'] ]);
+ drop_item($item['id'], DROPITEM_PHASE1, uid: $item['uid']);
+ Master::Summon(['Notifier', 'drop', $item['id']]);
return;
}
return;
}
else {
- $arr['uuid'] = item_message_id();
+ $arr['uuid'] = uuid_from_url($item['mid']);
$arr['mid'] = z_root() . '/activity/' . $arr['uuid'];
$arr['parent_mid'] = $item['parent_mid'];
//IConfig::Set($arr,'activitypub','context', str_replace('/item/','/conversation/',$item['parent_mid']));
@@ -3357,12 +3509,12 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
$arr['deny_gid'] = $channel['channel_deny_gid'];
$arr['comment_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'));
- $post = item_store($arr);
- $post_id = $post['item_id'];
+ $post = item_store($arr, deliver: false, addAndSync: false);
+ $post_id = $post['item_id'] ?? 0;
- if ($post_id) {
- Master::Summon([ 'Notifier','tgroup',$post_id ]);
- }
+ if ($post_id) {
+ Master::Summon(['Notifier', 'tgroup', $post_id]);
+ }
q("update channel set channel_lastpost = '%s' where channel_id = %d",
dbesc(datetime_convert()),
@@ -3372,81 +3524,6 @@ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false
return;
}
-
- // Change this copy of the post to a forum head message and deliver to all the tgroup members
- // also reset all the privacy bits to the forum default permissions
-
- $private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
- || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
-
- $new_public_policy = map_scope(PermissionLimits::Get($channel['channel_id'],'view_stream'),true);
-
- if((! $private) && $new_public_policy)
- $private = 1;
-
- $item_wall = 1;
- $item_origin = (($item['item_deleted']) ? 0 : 1); // item_origin for deleted items is set to 0 in delete_imported_item() to prevent looping. In this case we probably should not set it back to 1 here.
- $item_uplink = 0;
- $item_nocomment = 0;
-
- $flag_bits = $item['item_flags'];
-
- // maintain the original source, which will be the original item owner and was stored in source_xchan
- // when we created the delivery fork
-
- if($parent) {
- $r = q("update item set source_xchan = '%s' where id = %d",
- dbesc($parent['source_xchan']),
- intval($item_id)
- );
- }
- else {
- $item_uplink = (($item['item_rss']) ? 0 : 1); // Do not set item_uplink for rss items - we can not send anything to them.
-
- // if this is an edit, item_store_update() will have already updated the item
- // with the correct value for source_xchan (by ignoring it). We cannot set to owner_xchan
- // in this case because owner_xchan will point to the parent of this chain
- // and not the original sender.
-
- if(! $edit) {
- $r = q("update item set source_xchan = owner_xchan where id = %d",
- intval($item_id)
- );
- }
- }
-
- $title = $item['title'];
- $body = $item['body'];
-
- $r = q("update item set item_uplink = %d, item_nocomment = %d, item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
- deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s', item_wall = %d, item_origin = %d where id = %d",
- intval($item_uplink),
- intval($item_nocomment),
- intval($flag_bits),
- dbesc($channel['channel_hash']),
- dbesc($channel['channel_allow_cid']),
- dbesc($channel['channel_allow_gid']),
- dbesc($channel['channel_deny_cid']),
- dbesc($channel['channel_deny_gid']),
- intval($private),
- dbesc($new_public_policy),
- dbesc(map_scope(PermissionLimits::Get($channel['channel_id'],'post_comments'))),
- dbesc($title),
- dbesc($body),
- intval($item_wall),
- intval($item_origin),
- intval($item_id)
- );
-
- if($r)
- Master::Summon([ 'Notifier','tgroup',$item_id ]);
- else {
- logger('start_delivery_chain: failed to update item');
- // reset the source xchan to prevent loops
- $r = q("update item set source_xchan = '' where id = %d",
- intval($item_id)
- );
- }
}
/**
@@ -3762,7 +3839,7 @@ function item_expire($uid,$days,$comment_days = 7) {
$sql_extra = ((intval($expire_network_only)) ? " AND item_wall = 0 " : "");
- $expire_limit = get_config('system','expire_limit', 1000);
+ $expire_limit = Config::Get('system','expire_limit', 1000);
$item_normal = item_normal();
@@ -3785,7 +3862,7 @@ function item_expire($uid,$days,$comment_days = 7) {
if ($r) {
foreach ($r as $item) {
- drop_item($item['id'], false);
+ drop_item($item['id'], uid: $uid);
}
}
@@ -3798,25 +3875,12 @@ function retain_item($id) {
);
}
-function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL) {
- $uid = 0;
-
- if(! local_channel() && ! remote_channel())
- return;
-
- if(count($items)) {
+function drop_items($items, $stage = DROPITEM_NORMAL, $force = false, $expire = false) {
+ if ($items) {
foreach($items as $item) {
- $owner = drop_item($item,$interactive,$stage);
- if($owner && ! $uid)
- $uid = $owner;
+ drop_item($item, $stage, $force, expire: $expire);
}
}
-
- // multiple threads may have been deleted, send an expire notification
-
- if($uid) {
- Master::Summon([ 'Notifier','expire',$uid ]);
- }
}
@@ -3829,7 +3893,7 @@ function drop_items($items,$interactive = false,$stage = DROPITEM_NORMAL) {
// $stage = 1 => set deleted flag on the item and perform intial notifications
// $stage = 2 => perform low level delete at a later stage
-function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
+function drop_item($id, $stage = DROPITEM_NORMAL, $force = false, $uid = 0, $observer_hash = '', $expire = false, $recurse = false) {
// locate item to be deleted
@@ -3837,33 +3901,48 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
intval($id)
);
- if((! $r) || (intval($r[0]['item_deleted']) && ($stage === DROPITEM_NORMAL))) {
- if(! $interactive)
- return 0;
- notice( t('Item not found.') . EOL);
- //goaway(z_root() . '/' . $_SESSION['return_url']);
+ if(!$r || (intval($r[0]['item_deleted']) && $stage === DROPITEM_NORMAL)) {
+ return false;
}
$item = $r[0];
- $ok_to_delete = false;
+ if(!$recurse) {
+ drop_related($item, $stage, $force, $uid, $observer_hash, $expire);
+ }
- // system deletion
- if(! $interactive)
- $ok_to_delete = true;
+ $ok_to_delete = false;
// admin deletion
- if(is_site_admin())
+ if(is_site_admin()) {
$ok_to_delete = true;
+ }
// owner deletion
- if(local_channel() && local_channel() == $item['uid'])
+ if(local_channel() && local_channel() == $item['uid']) {
+ $ok_to_delete = true;
+ }
+
+ // remote delete when nobody is authenticated (called from Libzot and Daemons)
+ if ($uid && intval($uid) === intval($item['uid'])) {
$ok_to_delete = true;
+ }
// author deletion
- $observer = App::get_observer();
- if($observer && $observer['xchan_hash'] && ($observer['xchan_hash'] === $item['author_xchan']))
+ if ($observer_hash) {
+ $observer = ['xchan_hash' => $observer_hash];
+ }
+ else {
+ $observer = App::get_observer();
+ }
+
+ if (isset($observer['xchan_hash']) && $observer['xchan_hash'] === $item['author_xchan']) {
+ $ok_to_delete = true;
+ }
+
+ if (isset($observer['xchan_hash']) && $observer['xchan_hash'] === $item['owner_xchan']) {
$ok_to_delete = true;
+ }
if($ok_to_delete) {
@@ -3876,9 +3955,9 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
$arr = [
'item' => $item,
- 'interactive' => $interactive,
'stage' => $stage
];
+
/**
* @hooks drop_item
* Called when an 'item' is removed.
@@ -3901,30 +3980,95 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL) {
delete_item_lowlevel($item, $stage);
}
- if(! $interactive)
- return 1;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- // send the notification upstream/downstream as the case may be
- // only send notifications to others if this is the owner's wall item.
- // This isn't optimal. We somehow need to pass to this function whether or not
- // to call the notifier, or we need to call the notifier from the calling function.
- // We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only
- // set if we know we're going to send delete notifications out to others.
+// If somebody deletes a 'Create' activity, find any associated 'Add/Collection'
+// activity and delete it. And vice versa.
- if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1)) {
- Master::Summon([ 'Notifier','drop',$notify_id ]);
+function drop_related($item, $stage = DROPITEM_NORMAL, $force = false, $uid = 0, $observer_hash = '', $expire = false, $recurse = false) {
+ $allRelated = q("select * from item where parent_mid = '%s' and uid = %d",
+ dbesc($item['parent_mid']),
+ intval($item['uid'])
+ );
+ if (! $allRelated) {
+ return;
+ }
+ if ($item['verb'] === 'Add' && $item['tgt_type'] === 'Collection') {
+ if (is_array($item['obj'])) {
+ $thisItem = $item['obj'];
+ }
+ else {
+ $thisItem = json_decode($item['obj'], true);
+ }
+ if (isset($thisItem['object']['id'])) {
+ $targetMid = $thisItem['object']['id'];
+ }
+ if (!$targetMid) {
+ return;
+ }
+ foreach ($allRelated as $related) {
+ if ($related['mid'] === $targetMid) {
+ drop_item($related['id'], $stage, $force, $uid, $observer_hash, $expire, recurse: true);
+ break;
+ }
}
- //goaway(z_root() . '/' . $_SESSION['return_url']);
}
else {
- if(! $interactive)
- return 0;
- notice( t('Permission denied.') . EOL);
- //goaway(z_root() . '/' . $_SESSION['return_url']);
+ foreach ($allRelated as $related) {
+ if ($related['verb'] === 'Add' && str_contains($related['tgt_type'], 'Collection')) {
+ $thisItem = json_decode($related['obj'], true);
+ if (isset($thisItem['id']) && $thisItem['id'] === str_replace('/item/', '/activity/', $item['mid'])) {
+ drop_item($related['id'], $stage, $force, $uid, $observer_hash, $expire, recurse: true);
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+function find_related($item) {
+ $allRelated = q("select * from item where parent_mid = '%s' and uid = %d",
+ dbesc($item['parent_mid']),
+ intval($item['uid'])
+ );
+ if (! $allRelated) {
+ return false;
+ }
+ if ($item['verb'] === 'Add' && $item['tgt_type'] === 'Collection') {
+ $thisItem = json_decode($item['obj'],true);
+ if (is_array($thisItem)) {
+ $targetMid = $thisItem['object']['id'];
+ }
+ if (!$targetMid) {
+ return false;
+ }
+ foreach ($allRelated as $related) {
+ if ($related['mid'] === $targetMid) {
+ return $related;
+ }
+ }
}
+ else {
+ foreach ($allRelated as $related) {
+ if ($related['verb'] === 'Add' && str_contains($related['tgt_type'], 'Collection')) {
+ $thisItem = json_decode($related['obj'], true);
+ if (isset($thisItem['object']['id']) && $thisItem['object']['id'] === $item['mid']) {
+ return $related;
+ }
+ }
+ }
+ }
+ return false;
}
+
/**
* @warning This function does not check for permission and does not send
* notifications and does not check recursion.
@@ -5000,7 +5144,7 @@ function fix_attached_permissions($uid, $body, $str_contact_allow, $str_group_al
$attach = array_shift($attach_q);
- $new_public = !(($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny));
+ //$new_public = !(($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny));
$existing_public = !(($attach['allow_cid'] || $attach['allow_gid'] || $attach['deny_cid'] || $attach['deny_gid']));
if ($existing_public) {
@@ -5015,10 +5159,11 @@ function fix_attached_permissions($uid, $body, $str_contact_allow, $str_group_al
continue;
}
- $item_private = 0;
-
- if ($new_public === false) {
- $item_private = (($str_group_allow || ($str_contact_allow && substr_count($str_contact_allow,'<') > 2)) ? 1 : 2);
+ if ($token) {
+ $str_contact_allow = $attach['allow_cid'];
+ $str_group_allow = $attach['allow_gid'];
+ $str_contact_deny = $attach['deny_cid'];
+ $str_group_deny = $attach['deny_gid'];
// preserve any existing tokens that may have been set for this file
$token_matches = null;
@@ -5046,7 +5191,7 @@ function fix_attached_permissions($uid, $body, $str_contact_allow, $str_group_al
);
if ($attach['is_photo']) {
- $r = q("UPDATE photo SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s'
+ q("UPDATE photo SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s'
WHERE resource_id = '%s' AND uid = %d ",
dbesc($str_contact_allow),
dbesc($str_group_allow),
@@ -5056,7 +5201,16 @@ function fix_attached_permissions($uid, $body, $str_contact_allow, $str_group_al
intval($uid)
);
- $r = q("UPDATE item SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d
+ $item_private = 0;
+
+ if ($str_group_allow || $str_contact_deny || $str_group_deny) {
+ $item_private = 1;
+ }
+ elseif ($str_contact_allow) {
+ $item_private = 2;
+ }
+
+ q("UPDATE item SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d
WHERE resource_id = '%s' AND 'resource_type' = 'photo' AND uid = %d",
dbesc($str_contact_allow),
dbesc($str_group_allow),
@@ -5077,7 +5231,7 @@ function fix_attached_permissions($uid, $body, $str_contact_allow, $str_group_al
* which will allow you to interact with it.
*/
-function copy_of_pubitem($channel,$mid) {
+function copy_of_pubitem($channel, $mid) {
$result = null;
$syschan = get_sys_channel();
@@ -5095,36 +5249,104 @@ function copy_of_pubitem($channel,$mid) {
return $item[0];
}
-
- $r = q("select * from item where parent_mid = (select parent_mid from item where mid = '%s' and uid = %d ) order by id ",
+ $r = q("select * from item where parent_mid = (select parent_mid from item where mid = '%s' and uid = %d) and uid = %d order by id ",
dbesc($mid),
+ intval($syschan['channel_id']),
intval($syschan['channel_id'])
);
if($r) {
$items = fetch_post_tags($r,true);
foreach($items as $rv) {
- $d = q("select id from item where mid = '%s' and uid = %d limit 1",
- dbesc($rv['mid']),
- intval($channel['channel_id'])
- );
- if($d) {
- continue;
- }
unset($rv['id']);
unset($rv['parent']);
+
$rv['aid'] = $channel['channel_account_id'];
$rv['uid'] = $channel['channel_id'];
$rv['item_wall'] = 0;
$rv['item_origin'] = 0;
- $x = item_store($rv);
+ $x = item_store($rv, deliver: false, addAndSync: false);
if($x['item_id'] && $x['item']['mid'] === $mid) {
$result = $x['item'];
+ sync_an_item($channel['channel_id'], $x['item_id']);
}
}
}
+
return $result;
}
+
+function addToCollectionAndSync($ret) {
+ if (!$ret['success']) {
+ return $ret;
+ }
+
+ $channel = channelx_by_n($ret['item']['uid']);
+ if ($channel && $channel['channel_hash'] === $ret['item']['owner_xchan']) {
+ $items = [$ret['item']];
+
+ if ((int)$items[0]['item_blocked'] === ITEM_MODERATED
+ || (int)$items[0]['item_unpublished'] || (int)$items[0]['item_delayed']) {
+ return $ret;
+ }
+
+ xchan_query($items);
+ // TODO: fetch_post_tags() will add term and iconfig twice if called twice and it looks like they are already added here
+ // $items = fetch_post_tags($items);
+ $sync_items = [];
+ $sync_items[] = encode_item($items[0], true);
+
+ if (!in_array($ret['item']['verb'], ['Add', 'Remove'])) {
+ $activity = Activity::encode_activity($items[0]);
+
+ if (!$activity) {
+ return $ret;
+ }
+
+ $new_obj = Activity::build_packet($activity, $channel, false);
+ $approval = Activity::addToCollection($channel, $new_obj, $ret['item']['parent_mid'], $ret['item'], deliver: false);
+
+ if ($approval['success']) {
+ $ret['approval_id'] = $approval['item_id'];
+ $ret['approval'] = $approval['activity'];
+ $add_items = [$approval['activity']];
+ xchan_query($add_items);
+ $add_items = fetch_post_tags($add_items);
+ $sync_items[] = encode_item($add_items[0], true);
+ }
+ }
+
+ $resource_type = $ret['item']['resource_type'];
+
+ if ($resource_type === 'event') {
+ $z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
+ dbesc($ret['item']['resource_id']),
+ intval($channel['channel_id'])
+ );
+
+ if ($z) {
+ Libsync::build_sync_packet($channel['channel_id'], ['event_item' => $sync_items, 'event' => $z]);
+ }
+ }
+ elseif ($resource_type === 'photo') {
+ // reserved for future use, currently handled in the photo upload workflow
+ }
+ else {
+ Libsync::build_sync_packet($ret['item']['uid'], ['item' => $sync_items]);
+ }
+ }
+
+ return $ret;
+}
+
+function reverse_activity_mid($string) {
+ return str_replace(z_root() . '/activity/', z_root() . '/item/', $string);
+}
+
+function set_activity_mid($string) {
+ return str_replace(z_root() . '/item/', z_root() . '/activity/', $string);
+}
+
diff --git a/include/js_strings.php b/include/js_strings.php
index 090d28ce3..b41c34508 100644
--- a/include/js_strings.php
+++ b/include/js_strings.php
@@ -5,10 +5,10 @@ function js_strings() {
'$delitem' => t('Delete this item?'),
'$itemdel' => t('Item deleted'),
'$comment' => t('Comment'),
- '$showmore' => sprintf( t('%s show all'), '<i class=\'fa fa-chevron-down\'></i>'),
- '$showfewer' => sprintf( t('%s show less'), '<i class=\'fa fa-chevron-up\'></i>'),
- '$divgrowmore' => sprintf( t('%s expand'), '<i class=\'fa fa-chevron-down\'></i>'),
- '$divgrowless' => sprintf( t('%s collapse'),'<i class=\'fa fa-chevron-up\'></i>'),
+ '$showmore' => t('show all'),
+ '$showfewer' => t('show less'),
+ '$divgrowmore' => t('expand'),
+ '$divgrowless' => t('collapse'),
'$pwshort' => t("Password too short"),
'$pwnomatch' => t("Passwords do not match"),
'$everybody' => t('everybody'),
@@ -49,29 +49,6 @@ function js_strings() {
'months' => tt('%d months', '%d months', '%d'),
'years' => tt('%d years', '%d years', '%d'),
- // get plural function code
- 'plural_func' => tf(),
-
- '$t01' => ((t('timeago.prefixAgo') == 'timeago.prefixAgo') ? '' : ((t('timeago.prefixAgo') == 'NONE') ? '' : t('timeago.prefixAgo'))),
- '$t02' => ((t('timeago.prefixFromNow') == 'timeago.prefixFromNow') ? '' : ((t('timeago.prefixFromNow') == 'NONE') ? '' : t('timeago.prefixFromNow'))),
- '$t03' => ((t('timeago.suffixAgo') == 'timeago.suffixAgo') ? 'ago' : ((t('timeago.suffixAgo') == 'NONE') ? '' : t('timeago.suffixAgo'))),
- '$t04' => ((t('timeago.suffixFromNow') == 'timeago.suffixFromNow') ? 'from now' : ((t('timeago.suffixFromNow') == 'NONE') ? '' : t('timeago.suffixFromNow'))),
-
- // translatable main strings for jquery.timeago
- '$t05' => t('less than a minute'),
- '$t06' => t('about a minute'),
- '$t07' => ta('%d minutes'),
- '$t08' => t('about an hour'),
- '$t09' => ta('about %d hours'),
- '$t10' => t('a day'),
- '$t11' => ta('%d days'),
- '$t12' => t('about a month'),
- '$t13' => ta('%d months'),
- '$t14' => t('about a year'),
- '$t15' => ta('%d years'),
- '$t16' => t(' '), // wordSeparator
- '$t17' => ((t('timeago.numbers') != 'timeago.numbers') ? t('timeago.numbers') : '[]'),
-
'$January' => t('January'),
'$February' => t('February'),
'$March' => t('March'),
diff --git a/include/language.php b/include/language.php
index 1b2e7332e..538f67d90 100644
--- a/include/language.php
+++ b/include/language.php
@@ -10,6 +10,7 @@
use CommerceGuys\Intl\Language\LanguageRepository;
use LanguageDetection\Language;
+use Zotlabs\Lib\Config;
/**
* @brief Get the browser's submitted preferred languages.
@@ -17,7 +18,7 @@ use LanguageDetection\Language;
* This functions parses the HTTP_ACCEPT_LANGUAGE header sent by the browser and
* extracts the preferred languages and their priority.
*
- * Get the language setting directly from system variables, bypassing get_config()
+ * Get the language setting directly from system variables, bypassing Config::Get()
* as database may not yet be configured.
*
* If possible, we use the value from the browser.
@@ -197,10 +198,10 @@ function load_translation_table($lang, $install = false) {
*
* @param string $s string that should get translated
* @param string $ctx (optional) context to appear in po file
- * @return translated string if exists, otherwise return $s
+ * @return string translated string if exists, otherwise return $s
*
*/
-function t($s, $ctx = '') {
+function t($s, $ctx = ''): string {
$cs = $ctx ? '__ctx:' . $ctx . '__ ' . $s : $s;
if (x(App::$strings, $cs)) {
@@ -313,8 +314,8 @@ function detect_language($s) {
return EMPTY_STR;
}
- $min_length = get_config('system', 'language_detect_min_length', LANGUAGE_DETECT_MIN_LENGTH);
- $min_confidence = get_config('system', 'language_detect_min_confidence', LANGUAGE_DETECT_MIN_CONFIDENCE);
+ $min_length = Config::Get('system', 'language_detect_min_length', LANGUAGE_DETECT_MIN_LENGTH);
+ $min_confidence = Config::Get('system', 'language_detect_min_confidence', LANGUAGE_DETECT_MIN_CONFIDENCE);
// embedded apps have long base64 strings which will trip up the detector.
$naked_body = preg_replace('/\[app\](.*?)\[\/app\]/', '', $s);
diff --git a/include/markdown.php b/include/markdown.php
index b2adcd0d5..90d671fe4 100644
--- a/include/markdown.php
+++ b/include/markdown.php
@@ -80,22 +80,6 @@ function markdown_to_bb($s, $use_zrl = false, $options = []) {
$s = html2bbcode($s);
- // $s = bb_code_protect($s);
-
- // Convert everything that looks like a link to a link
- if($use_zrl) {
- if (strpos($s,'[/img]') !== false) {
- $s = preg_replace_callback("/\[img\](.*?)\[\/img\]/ism", 'use_zrl_cb_img', $s);
- $s = preg_replace_callback("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", 'use_zrl_cb_img_x', $s);
- }
- $s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)([\,\.\:\;]\s|$)/ismu", 'use_zrl_cb_link',$s);
- }
- else {
- $s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)([\,\.\:\;]\s|$)/ismu", '$1[url=$2$3]$2$3[/url]$4',$s);
- }
-
- // $s = bb_code_unprotect($s);
-
// remove duplicate adjacent code tags
$s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s);
diff --git a/include/menu.php b/include/menu.php
index 1f65f987d..2fcf88bca 100644
--- a/include/menu.php
+++ b/include/menu.php
@@ -166,7 +166,8 @@ function menu_create($arr) {
if($r)
return false;
- $t = datetime_convert();
+ $time_created = datetime_convert('UTC', 'UTC', empty($arr['menu_created']) ? 'now' : $arr['menu_created']);
+ $time_edited = empty($arr['menu_edited']) ? $time_created : datetime_convert('UTC', 'UTC', $arr['menu_edited']);
$r = q("insert into menu ( menu_name, menu_desc, menu_flags, menu_channel_id, menu_created, menu_edited )
values( '%s', '%s', %d, %d, '%s', '%s' )",
@@ -174,8 +175,8 @@ function menu_create($arr) {
dbesc($menu_desc),
intval($menu_flags),
intval($menu_channel_id),
- dbesc(datetime_convert('UTC','UTC',(($arr['menu_created']) ? $arr['menu_created'] : $t))),
- dbesc(datetime_convert('UTC','UTC',(($arr['menu_edited']) ? $arr['menu_edited'] : $t)))
+ dbesc($time_created),
+ dbesc($time_edited)
);
if(! $r)
return false;
diff --git a/include/nav.php b/include/nav.php
index e4df7e4e5..1bee5a2db 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -1,7 +1,8 @@
<?php /** @file */
-use \Zotlabs\Lib\Apps;
-use \Zotlabs\Lib\Chatroom;
+use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Chatroom;
+use Zotlabs\Lib\Config;
require_once('include/security.php');
require_once('include/menu.php');
@@ -57,10 +58,10 @@ function nav($template = 'default') {
*
*/
- $banner = get_config('system', 'banner');
+ $banner = Config::Get('system', 'banner');
if ($banner === false)
- $banner = get_config('system', 'sitename');
+ $banner = Config::Get('system', 'sitename');
call_hooks('get_banner', $banner);
@@ -175,15 +176,15 @@ function nav($template = 'default') {
];
}
- if ((get_config('system', 'register_policy') == REGISTER_OPEN || get_config('system', 'register_policy') == REGISTER_APPROVE) && empty($_SESSION['authenticated'])) {
+ if ((Config::Get('system', 'register_policy') == REGISTER_OPEN || Config::Get('system', 'register_policy') == REGISTER_APPROVE) && empty($_SESSION['authenticated'])) {
$nav['register'] = ['register', t('Register'), "", t('Create an account'), 'register_nav_btn'];
}
// TODO: update help content for various modules
- if (false /* !get_config('system', 'hide_help') */) {
+ if (false /* !Config::Get('system', 'hide_help') */) {
$help_url = z_root() . '/help?f=&cmd=' . App::$cmd;
$context_help = '';
- $enable_context_help = ((intval(get_config('system', 'enable_context_help')) === 1 || get_config('system', 'enable_context_help') === false) ? true : false);
+ $enable_context_help = ((intval(Config::Get('system', 'enable_context_help')) === 1 || Config::Get('system', 'enable_context_help') === false) ? true : false);
if ($enable_context_help === true) {
require_once('include/help.php');
$context_help = load_context_help();
@@ -350,7 +351,7 @@ function nav($template = 'default') {
'$pleasewait' => t('Please wait...'),
'$nav_apps' => $nav_apps,
'$navbar_apps' => $navbar_apps,
- '$channel_menu' => get_pconfig(App::$profile_uid, 'system', 'channel_menu', get_config('system', 'channel_menu')),
+ '$channel_menu' => get_pconfig(App::$profile_uid, 'system', 'channel_menu', Config::Get('system', 'channel_menu')),
'$channel_thumb' => ((App::$profile) ? App::$profile['thumb'] : ''),
'$channel_apps' => $channel_apps,
'$addapps' => t('Apps'),
@@ -448,7 +449,7 @@ function channel_apps($is_owner = false, $nickname = null) {
'sel' => ((argv(0) == 'channel') ? 'active' : ''),
'title' => t('Status Messages and Posts'),
'id' => 'status-tab',
- 'icon' => 'home'
+ 'icon' => 'house'
],
];
@@ -461,7 +462,7 @@ function channel_apps($is_owner = false, $nickname = null) {
'sel' => ((argv(0) == 'profile') ? 'active' : ''),
'title' => t('Profile Details'),
'id' => 'profile-tab',
- 'icon' => 'user'
+ 'icon' => 'person'
];
}
if ($p['view_storage']) {
@@ -471,7 +472,7 @@ function channel_apps($is_owner = false, $nickname = null) {
'sel' => ((argv(0) == 'photos') ? 'active' : ''),
'title' => t('Photo Albums'),
'id' => 'photo-tab',
- 'icon' => 'photo'
+ 'icon' => 'image'
];
$tabs[] = [
'label' => t('Files'),
@@ -479,7 +480,7 @@ function channel_apps($is_owner = false, $nickname = null) {
'sel' => ((argv(0) == 'cloud' || argv(0) == 'sharedwithme') ? 'active' : ''),
'title' => t('Files and Storage'),
'id' => 'files-tab',
- 'icon' => 'folder-open'
+ 'icon' => 'folder'
];
}
@@ -490,7 +491,7 @@ function channel_apps($is_owner = false, $nickname = null) {
'sel' => ((argv(0) == 'cal') ? 'active' : ''),
'title' => t('Calendar'),
'id' => 'event-tab',
- 'icon' => 'calendar'
+ 'icon' => 'calendar-date'
];
}
@@ -504,7 +505,7 @@ function channel_apps($is_owner = false, $nickname = null) {
'sel' => ((argv(0) == 'chat') ? 'active' : ''),
'title' => t('Chatrooms'),
'id' => 'chat-tab',
- 'icon' => 'comments-o'
+ 'icon' => 'chat'
];
}
}
@@ -528,18 +529,7 @@ function channel_apps($is_owner = false, $nickname = null) {
'sel' => ((argv(0) == 'webpages') ? 'active' : ''),
'title' => t('View Webpages'),
'id' => 'webpages-tab',
- 'icon' => 'newspaper-o'
- ];
- }
-
- if ($p['view_wiki'] && Apps::system_app_installed($uid, 'Wiki')) {
- $tabs[] = [
- 'label' => t('Wikis'),
- 'url' => z_root() . '/wiki/' . $nickname,
- 'sel' => ((argv(0) == 'wiki') ? 'active' : ''),
- 'title' => t('Wiki'),
- 'id' => 'wiki-tab',
- 'icon' => 'pencil-square-o'
+ 'icon' => 'layout-text-sidebar'
];
}
diff --git a/include/network.php b/include/network.php
index a5c14f9d1..55eecac84 100644
--- a/include/network.php
+++ b/include/network.php
@@ -1,6 +1,8 @@
<?php
use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Config;
+use Zotlabs\Lib\Mailer;
use Zotlabs\Lib\Zotfinger;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Queue;
@@ -67,7 +69,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; zot)');
@curl_setopt($ch, CURLOPT_ENCODING, '');
- $ciphers = @get_config('system','curl_ssl_ciphers');
+ $ciphers = @Config::Get('system','curl_ssl_ciphers');
if($ciphers)
@curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
@@ -114,16 +116,16 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_TIMEOUT, intval($opts['timeout']));
}
else {
- $curl_time = intval(@get_config('system','curl_timeout'));
- @curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
+ $curl_time = intval(@Config::Get('system','curl_timeout'));
+ @curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== 0) ? $curl_time : 60));
}
if(x($opts,'connecttimeout') && intval($opts['connecttimeout'])) {
@curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, intval($opts['connecttimeout']));
}
else {
- $curl_contime = intval(@get_config('system','curl_connecttimeout'));
- @curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (($curl_contime !== false) ? $curl_contime : 30));
+ $curl_contime = intval(@Config::Get('system','curl_connecttimeout'));
+ @curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (($curl_contime !== 0) ? $curl_contime : 30));
}
if(x($opts,'http_auth')) {
@@ -145,11 +147,11 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,
((x($opts,'novalidate') && intval($opts['novalidate'])) ? false : true));
- $prx = @get_config('system','proxy');
+ $prx = @Config::Get('system','proxy');
if(strlen($prx)) {
@curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
@curl_setopt($ch, CURLOPT_PROXY, $prx);
- $prxusr = @get_config('system','proxyuser');
+ $prxusr = @Config::Get('system','proxyuser');
if(strlen($prxusr))
@curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
}
@@ -263,7 +265,7 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; zot)");
@curl_setopt($ch, CURLOPT_ENCODING, '');
- $ciphers = @get_config('system','curl_ssl_ciphers');
+ $ciphers = @Config::Get('system','curl_ssl_ciphers');
if($ciphers)
@curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
@@ -296,8 +298,8 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_TIMEOUT, $opts['timeout']);
}
else {
- $curl_time = intval(@get_config('system','curl_timeout'));
- @curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
+ $curl_time = intval(@Config::Get('system','curl_timeout'));
+ @curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== 0) ? $curl_time : 60));
}
if(x($opts,'http_auth')) {
@@ -318,11 +320,11 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,
((x($opts,'novalidate') && intval($opts['novalidate'])) ? false : true));
- $prx = get_config('system','proxy');
+ $prx = Config::Get('system','proxy');
if(strlen($prx)) {
@curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
@curl_setopt($ch, CURLOPT_PROXY, $prx);
- $prxusr = get_config('system','proxyuser');
+ $prxusr = Config::Get('system','proxyuser');
if(strlen($prxusr))
@curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
}
@@ -555,12 +557,15 @@ function z_dns_check($h,$check_mx = 0) {
return((@dns_get_record($h,$opts) || filter_var($h, FILTER_VALIDATE_IP)) ? true : false);
}
-function is_local_url($url) {
- if (str_starts_with($url, z_root()) || str_starts_with($url, '/')) {
- return true;
- }
-
- return false;
+/**
+ * Returns whether an URL is local to the site, or not.
+ *
+ * @param string $url The URL to check
+ *
+ * @return bool True if the URL is local, false otherwise.
+ */
+function is_local_url(string $url): bool {
+ return str_starts_with($url, z_root()) || str_starts_with($url, '/');
}
/**
@@ -603,12 +608,12 @@ function validate_url(&$url) {
*/
function validate_email(string $addr): bool {
- if(get_config('system', 'disable_email_validation'))
+ if(Config::Get('system', 'disable_email_validation'))
return true;
$matches = array();
$result = preg_match(
- '/^[A-Z0-9._%-]+@([A-Z0-9.-]+\.[A-Z0-9-]{2,})$/i',
+ '/^[A-Z0-9._%+-]+@([A-Z0-9.-]+\.[A-Z0-9-]{2,})$/i',
punify($addr),
$matches);
@@ -638,7 +643,7 @@ function allowed_url($url) {
return false;
}
- $str_allowed = get_config('system', 'allowed_sites');
+ $str_allowed = Config::Get('system', 'allowed_sites');
if(! $str_allowed)
return true;
@@ -682,8 +687,8 @@ function allowed_email($email) {
if(! $domain)
return false;
- $str_allowed = get_config('system', 'allowed_email');
- $str_not_allowed = get_config('system', 'not_allowed_email');
+ $str_allowed = Config::Get('system', 'allowed_email');
+ $str_not_allowed = Config::Get('system', 'not_allowed_email');
if(! $str_allowed && ! $str_not_allowed)
return true;
@@ -1472,7 +1477,7 @@ function do_delivery($deliveries, $force = false) {
/*
$x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
- if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',3000)) && (! $force)) {
+ if(intval($x[0]['total']) > intval(Config::Get('system','force_queue_threshold',3000)) && (! $force)) {
logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
foreach($deliveries as $d) {
Queue::update($d);
@@ -1482,13 +1487,13 @@ function do_delivery($deliveries, $force = false) {
*/
- $interval = get_config('queueworker', 'queue_interval', 500000);
+ $interval = Config::Get('queueworker', 'queue_interval', 500000);
- $deliveries_per_process = intval(get_config('system','delivery_batch_count'));
+ $deliveries_per_process = intval(Config::Get('system', 'delivery_batch_count'));
- if($deliveries_per_process <= 0)
+ if($deliveries_per_process <= 0) {
$deliveries_per_process = 1;
-
+ }
$deliver = [];
foreach($deliveries as $d) {
@@ -1542,9 +1547,9 @@ function get_site_info() {
$admin = false;
}
- $def_service_class = get_config('system','default_service_class');
+ $def_service_class = Config::Get('system','default_service_class');
if($def_service_class)
- $service_class = get_config('service_class',$def_service_class);
+ $service_class = Config::Get('service_class',$def_service_class);
else
$service_class = false;
@@ -1555,9 +1560,9 @@ function get_site_info() {
if(! isset($commit) || strlen($commit) > 16)
$commit = '';
- $site_info = get_config('system','info');
- $site_name = get_config('system','sitename');
- if(! get_config('system','hidden_version_siteinfo')) {
+ $site_info = Config::Get('system','info');
+ $site_name = Config::Get('system','sitename');
+ if(! Config::Get('system','hidden_version_siteinfo')) {
$version = Zotlabs\Lib\System::get_project_version();
$tag = Zotlabs\Lib\System::get_std_version();
@@ -1573,15 +1578,15 @@ function get_site_info() {
}
//Statistics
- $channels_total_stat = intval(get_config('system','channels_total_stat'));
- $channels_active_halfyear_stat = intval(get_config('system','channels_active_halfyear_stat'));
- $channels_active_monthly_stat = intval(get_config('system','channels_active_monthly_stat'));
- $local_posts_stat = intval(get_config('system','local_posts_stat'));
- $local_comments_stat = intval(get_config('system','local_comments_stat'));
- $hide_in_statistics = intval(get_config('system','hide_in_statistics'));
- $site_expire = intval(get_config('system', 'default_expire_days'));
-
- load_config('feature_lock');
+ $channels_total_stat = intval(Config::Get('system','channels_total_stat'));
+ $channels_active_halfyear_stat = intval(Config::Get('system','channels_active_halfyear_stat'));
+ $channels_active_monthly_stat = intval(Config::Get('system','channels_active_monthly_stat'));
+ $local_posts_stat = intval(Config::Get('system','local_posts_stat'));
+ $local_comments_stat = intval(Config::Get('system','local_comments_stat'));
+ $hide_in_statistics = intval(Config::Get('system','hide_in_statistics'));
+ $site_expire = intval(Config::Get('system', 'default_expire_days'));
+
+ Config::Load('feature_lock');
$locked_features = array();
if(is_array(App::$config['feature_lock']) && count(App::$config['feature_lock'])) {
foreach(App::$config['feature_lock'] as $k => $v) {
@@ -1602,18 +1607,18 @@ function get_site_info() {
'server_role' => Zotlabs\Lib\System::get_server_role(),
'commit' => $commit,
'plugins' => $visible_plugins,
- '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')),
+ 'register_policy' => $register_policy[Config::Get('system','register_policy')],
+ 'invitation_only' => (bool) intval(Config::Get('system','invitation_only')),
+ 'directory_mode' => $directory_mode[Config::Get('system','directory_mode')],
+ 'directory_server' => Config::Get('system','directory_server'),
+ 'language' => Config::Get('system','language'),
+ 'rss_connections' => (bool) intval(Config::Get('system','feed_contacts')),
'expiration' => $site_expire,
'default_service_restrictions' => $service_class,
'locked_features' => $locked_features,
'admin' => $admin,
'dbdriver' => DBA::$dba->getdriver() . ' ' . ((ACTIVE_DBTYPE == DBTYPE_POSTGRES) ? 'postgres' : 'mysql'),
- 'lastpoll' => get_config('system','lastpoll'),
+ 'lastpoll' => Config::Get('system','lastpoll'),
'info' => (($site_info) ? $site_info : ''),
'channels_total' => $channels_total_stat,
'hide_in_statistics' => $hide_in_statistics
@@ -1651,7 +1656,7 @@ function check_siteallowed($url) {
if(array_key_exists('allowed',$arr))
return $arr['allowed'];
- $bl1 = get_config('system','whitelisted_sites');
+ $bl1 = Config::Get('system','whitelisted_sites');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl1 === '*')
@@ -1660,7 +1665,7 @@ function check_siteallowed($url) {
return true;
}
}
- $bl1 = get_config('system','blacklisted_sites');
+ $bl1 = Config::Get('system','blacklisted_sites');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl1 === '*')
@@ -1696,7 +1701,7 @@ function check_channelallowed($hash) {
if(array_key_exists('allowed',$arr))
return $arr['allowed'];
- $bl1 = get_config('system','whitelisted_channels');
+ $bl1 = Config::Get('system','whitelisted_channels');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl1 === '*')
@@ -1705,7 +1710,7 @@ function check_channelallowed($hash) {
return true;
}
}
- $bl1 = get_config('system','blacklisted_channels');
+ $bl1 = Config::Get('system','blacklisted_channels');
if(is_array($bl1) && $bl1) {
foreach($bl1 as $bl) {
if($bl1 === '*')
@@ -1809,54 +1814,9 @@ function network_to_name($s) {
*/
function z_mail($params) {
- if(! $params['fromEmail']) {
- $params['fromEmail'] = get_config('system','from_email');
- if(! $params['fromEmail'])
- $params['fromEmail'] = 'Administrator' . '@' . App::get_hostname();
- }
- if(! $params['fromName']) {
- $params['fromName'] = get_config('system','from_email_name');
- if(! $params['fromName'])
- $params['fromName'] = Zotlabs\Lib\System::get_site_name();
- }
- if(! $params['replyTo']) {
- $params['replyTo'] = get_config('system','reply_address');
- if(! $params['replyTo'])
- $params['replyTo'] = 'noreply' . '@' . App::get_hostname();
- }
-
- $params['sent'] = false;
- $params['result'] = false;
-
- /**
- * @hooks email_send
- * * \e params @see z_mail()
- */
- call_hooks('email_send', $params);
-
- if($params['sent']) {
- logger('notification: z_mail returns ' . (($params['result']) ? 'success' : 'failure'), LOGGER_DEBUG);
- return $params['result'];
- }
-
- $fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
- $messageSubject = email_header_encode(html_entity_decode($params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
-
- $messageHeader =
- $params['additionalMailHeader'] .
- "From: $fromName <{$params['fromEmail']}>" . PHP_EOL .
- "Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL .
- "Content-Type: text/plain; charset=UTF-8";
-
- // send the message
- $res = mail(
- $params['toEmail'], // send to address
- $messageSubject, // subject
- $params['textVersion'],
- $messageHeader // message headers
- );
- logger('notification: z_mail returns ' . (($res) ? 'success' : 'failure'), LOGGER_DEBUG);
- return $res;
+ // Delegate the call to the Mailer class.
+ $mailer = new Mailer($params);
+ return $mailer->deliver();
}
@@ -2141,21 +2101,59 @@ function get_request_string($url) {
/**
- * Builds a url from the result of `parse_url`.
+ * Reconstructs a URL from its parsed components.
+ *
+ * This function takes a parsed URL as an associative array and reconstructs
+ * the URL based on the specified components (scheme, host, port, user, pass, path, query, fragment).
+ * You can specify which components should be included in the final URL by passing the optional
+ * `$parts` array. The function will return the complete URL string formed by combining
+ * only the parts that exist in both the parsed URL and the `$parts` array.
+ *
+ * @param array $parsed_url The parsed URL components as an associative array.
+ * The array can include keys like 'scheme', 'host', 'port', 'user', 'pass',
+ * 'path', 'query', 'fragment'.
*
- * @param array $parsed_url An associative array as produced by `parse_url`.
+ * @param array $parts An optional array that specifies which components of the URL
+ * should be included in the final string. Defaults to:
+ * ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'].
+ * If any of the components are not required, they can be omitted from the array.
*
- * @return The reassembled URL as a string.
+ * @return string The reconstructed URL as a string.
*/
-function unparse_url($parsed_url) {
- $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
- $host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
- $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
- $user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
- $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
- $pass = ($user || $pass) ? "$pass@" : '';
- $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
- $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
- $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
- return "$scheme$user$pass$host$port$path$query$fragment";
+function unparse_url(array $parsed_url, array $parts = ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment']): string {
+ $url_parts = [];
+
+ if (in_array('scheme', $parts) && array_key_exists('scheme', $parsed_url)) {
+ $url_parts[] = $parsed_url['scheme'] . '://';
+ }
+
+ if (in_array('user', $parts) && array_key_exists('user', $parsed_url)) {
+ $url_parts[] = $parsed_url['user'];
+ if (in_array('pass', $parts) && array_key_exists('pass', $parsed_url)) {
+ $url_parts[] = ':' . $parsed_url['pass'];
+ }
+ $url_parts[] = '@';
+ }
+
+ if (in_array('host', $parts) && array_key_exists('host', $parsed_url)) {
+ $url_parts[] = $parsed_url['host'];
+ }
+
+ if (in_array('port', $parts) && array_key_exists('port', $parsed_url)) {
+ $url_parts[] = ':' . $parsed_url['port'];
+ }
+
+ if (in_array('path', $parts) && array_key_exists('path', $parsed_url)) {
+ $url_parts[] = $parsed_url['path'];
+ }
+
+ if (in_array('query', $parts) && array_key_exists('query', $parsed_url)) {
+ $url_parts[] = '?' . $parsed_url['query'];
+ }
+
+ if (in_array('fragment', $parts) && array_key_exists('fragment', $parsed_url)) {
+ $url_parts[] = '#' . $parsed_url['fragment'];
+ }
+
+ return implode('', $url_parts);
}
diff --git a/include/oauth.php b/include/oauth.php
index 845ec4558..3426f9ca5 100644
--- a/include/oauth.php
+++ b/include/oauth.php
@@ -1,11 +1,13 @@
<?php /** @file */
-/**
+/**
* OAuth server
* Based on oauth2-php <http://code.google.com/p/oauth2-php/>
- *
+ *
*/
+use Zotlabs\Lib\Config;
+
define('REQUEST_TOKEN_DURATION', 300);
define('ACCESS_TOKEN_DURATION', 31536000);
@@ -18,7 +20,7 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
function gen_token(){
return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
}
-
+
function lookup_consumer($consumer_key) {
logger('consumer_key: ' . $consumer_key, LOGGER_DEBUG);
@@ -72,7 +74,7 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
$key = $this->gen_token();
$sec = $this->gen_token();
-
+
if ($consumer->key){
$k = $consumer->key;
} else {
@@ -94,19 +96,19 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
function new_access_token($token, $consumer, $verifier = null) {
logger(__function__.":".$token.", ". $consumer.", ". $verifier, LOGGER_DEBUG);
-
+
// return a new access token attached to this consumer
// for the user associated with this token if the request token
// is authorized
// should also invalidate the request token
-
+
$ret=Null;
-
+
// get user for this verifier
- $uverifier = get_config("oauth", $verifier);
+ $uverifier = Config::Get("oauth", $verifier);
logger(__function__.":".$verifier.",".$uverifier, LOGGER_DEBUG);
if (is_null($verifier) || ($uverifier!==false)) {
-
+
$key = $this->gen_token();
$sec = $this->gen_token();
@@ -119,16 +121,16 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
intval($uverifier));
if ($r)
- $ret = new OAuth1Token($key,$sec);
+ $ret = new OAuth1Token($key,$sec);
}
-
-
+
+
q("DELETE FROM tokens WHERE id='%s'", $token->key);
-
-
+
+
if (!is_null($ret) && $uverifier!==false) {
- del_config("oauth", $verifier);
-
+ Config::Delete("oauth", $verifier);
+
// $apps = get_pconfig($uverifier, "oauth", "apps");
// if ($apps===false) $apps=array();
// $apps[] = $consumer->key;
@@ -145,7 +147,7 @@ class ZotOAuth1 extends OAuth1Server {
$this->add_signature_method(new OAuth1SignatureMethod_PLAINTEXT());
$this->add_signature_method(new OAuth1SignatureMethod_HMAC_SHA1());
}
-
+
function loginUser($uid){
logger("ZotOAuth1::loginUser $uid");
@@ -174,7 +176,7 @@ class ZotOAuth1 extends OAuth1Server {
$_SESSION['allow_api'] = true;
}
}
-
+
}
/*
@@ -195,13 +197,13 @@ class FKOAuth2 extends OAuth2 {
dbesc($client_secret),
dbesc($redirect_uri)
);
-
+
return $r;
}
protected function checkClientCredentials($client_id, $client_secret = NULL) {
$client_secret = $this->db_secret($client_secret);
-
+
$r = q("SELECT pw FROM clients WHERE client_id = '%s'",
dbesc($client_id));
@@ -223,21 +225,21 @@ class FKOAuth2 extends OAuth2 {
protected function getAccessToken($oauth_token) {
$r = q("SELECT client_id, expires, scope FROM tokens WHERE id = '%s'",
dbesc($oauth_token));
-
+
if (count($r))
return $r[0];
return null;
}
-
+
protected function setAccessToken($oauth_token, $client_id, $expires, $scope = NULL) {
$r = q("INSERT INTO tokens (id, client_id, expires, scope) VALUES ('%s', '%s', %d, '%s')",
dbesc($oauth_token),
dbesc($client_id),
intval($expires),
dbesc($scope));
-
+
return $r;
}
@@ -251,23 +253,23 @@ class FKOAuth2 extends OAuth2 {
protected function getAuthCode($code) {
$r = q("SELECT id, client_id, redirect_uri, expires, auth_scope FROM auth_codes WHERE id = '%s'",
dbesc($code));
-
+
if (count($r))
return $r[0];
return null;
}
protected function setAuthCode($code, $client_id, $redirect_uri, $expires, $scope = NULL) {
- $r = q("INSERT INTO auth_codes
- (id, client_id, redirect_uri, expires, auth_scope) VALUES
+ $r = q("INSERT INTO auth_codes
+ (id, client_id, redirect_uri, expires, auth_scope) VALUES
('%s', '%s', '%s', %d, '%s')",
dbesc($code),
dbesc($client_id),
dbesc($redirect_uri),
intval($expires),
dbesc($scope));
- return $r;
- }
-
+ return $r;
+ }
+
}
*/
diff --git a/include/oauth2.php b/include/oauth2.php
index 3a71a651d..f7a279892 100644
--- a/include/oauth2.php
+++ b/include/oauth2.php
@@ -12,12 +12,12 @@
$oauth2_server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));
$oauth2_server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));
- $keyStorage = new OAuth2\Storage\Memory( [
- 'keys' => [
- 'public_key' => get_config('system','pubkey'),
- 'private_key' => get_config('system','prvkey')
+ $keyStorage = new OAuth2\Storage\Memory( [
+ 'keys' => [
+ 'public_key' => Config::Get('system','pubkey'),
+ 'private_key' => Config::Get('system','prvkey')
]
]);
$oauth2_server->addStorage($keyStorage,'public_key');
-*/ \ No newline at end of file
+*/
diff --git a/include/oembed.php b/include/oembed.php
index a90c91641..840164663 100644
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -1,7 +1,7 @@
<?php /** @file */
use Zotlabs\Lib\Cache;
-
+use Zotlabs\Lib\Config;
function oembed_replacecb($matches){
@@ -28,7 +28,7 @@ function oembed_action($embedurl) {
logger('oembed_action: ' . $embedurl, LOGGER_DEBUG, LOG_INFO);
if(strpos($embedurl,'http://') === 0) {
- if(intval(get_config('system','embed_sslonly'))) {
+ if(intval(Config::Get('system','embed_sslonly'))) {
$action = 'block';
}
}
@@ -39,7 +39,7 @@ function oembed_action($embedurl) {
// site white/black list
- if(($x = get_config('system','embed_deny'))) {
+ if(($x = Config::Get('system','embed_deny'))) {
if(($x) && (! is_array($x)))
$x = explode("\n",$x);
if($x) {
@@ -55,7 +55,7 @@ function oembed_action($embedurl) {
$found = false;
- if(($x = get_config('system','embed_allow'))) {
+ if(($x = Config::Get('system','embed_allow'))) {
if(($x) && (! is_array($x)))
$x = explode("\n",$x);
if($x) {
@@ -139,16 +139,20 @@ function oembed_fetch_url($embedurl){
// we should try to cache this and avoid a lookup on each render
$is_matrix = is_matrix_url($embedurl);
- $zrl = ((get_config('system','oembed_zrl')) ? $is_matrix : false);
+ $zrl = ((Config::Get('system','oembed_zrl')) ? $is_matrix : false);
$furl = ((local_channel() && $zrl) ? zid($embedurl) : $embedurl);
- if($action !== 'block' && (! get_config('system','oembed_cache_disable'))) {
+ if (empty($furl)) {
+ return;
+ }
+
+ if($action !== 'block' && (! Config::Get('system','oembed_cache_disable'))) {
$txt = Cache::get('[' . App::$videowidth . '] ' . $furl);
}
- if(strpos(strtolower($embedurl),'.pdf') !== false && get_config('system','inline_pdf')) {
+ if(strpos(strtolower($embedurl),'.pdf') !== false && Config::Get('system','inline_pdf')) {
$action = 'allow';
$j = [
'html' => '<object data="' . $embedurl . '" type="application/pdf" style="width: 100%; height: 300px;"></object>',
@@ -164,7 +168,7 @@ function oembed_fetch_url($embedurl){
$txt = EMPTY_STR;
if ($action !== 'block') {
- $max_oembed_size = get_config('system', 'oembed_max_size', 1 * 1024 * 1024 /* 1MB */);
+ $max_oembed_size = Config::Get('system', 'oembed_max_size', 1 * 1024 * 1024 /* 1MB */);
stream_context_set_default(
[
@@ -259,7 +263,7 @@ function oembed_fetch_url($embedurl){
// save in cache
- if(! get_config('system','oembed_cache_disable'))
+ if(! Config::Get('system','oembed_cache_disable'))
Cache::set('[' . App::$videowidth . '] ' . $furl, $txt);
}
@@ -328,7 +332,7 @@ function oembed_format_object($j){
$jhtml = oembed_iframe($j['embedurl'],(isset($j['width']) ? $j['width'] : null), (isset($j['height']) ? $j['height'] : null));
- $ret="<span class='oembed " . $j['type'] . "'>";
+ $ret="<span class='clearfix d-block oembed " . $j['type'] . "'>";
switch ($j['type']) {
case "video": {
if (isset($j['thumbnail_url'])) {
@@ -351,7 +355,6 @@ function oembed_format_object($j){
} else {
$ret=$jhtml;
}
- $ret.="<br>";
}; break;
case "photo": {
$ret.= "<img width='".$j['width']."' src='".$j['url']."'>";
@@ -386,15 +389,15 @@ function oembed_format_object($j){
// add link to source if not present in "rich" type
if ( $j['type'] != 'rich' || !strpos($j['html'],$embedurl) ){
$embedlink = (isset($j['title']))?$j['title'] : $embedurl;
- $ret .= '<br />' . "<a href='$embedurl' rel='oembed'>$embedlink</a>";
+ $ret .= "<a href='$embedurl' rel='oembed'>$embedlink</a>";
$ret .= "<br />";
if (isset($j['author_name'])) $ret .= t(' by ') . $j['author_name'];
if (isset($j['provider_name'])) $ret .= t(' on ') . $j['provider_name'];
} else {
// add <a> for html2bbcode conversion
- $ret .= "<br /><a href='$embedurl' rel='oembed'>$embedurl</a>";
+ $ret .= "<a href='$embedurl' rel='oembed'>$embedurl</a>";
}
- $ret.="<br style='clear:left'></span>";
+ $ret.="</span>";
// mb_convert_encoding() is deprecated
// return mb_convert_encoding($ret, 'HTML-ENTITIES', mb_detect_encoding($ret));
@@ -414,8 +417,8 @@ function oembed_iframe($src,$width,$height) {
}
// try and leave some room for the description line.
- $height = intval($height) + 80;
- $width = intval($width) + 40;
+ $height = intval($height);
+ $width = intval($width);
$s = z_root() . '/oembed/' . base64url_encode($src);
@@ -429,7 +432,7 @@ function oembed_iframe($src,$width,$height) {
function oembed_bbcode2html($text){
- $stopoembed = get_config("system","no_oembed");
+ $stopoembed = Config::Get("system","no_oembed");
if ($stopoembed == true){
return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "<!-- oembed $1 --><i>". t('Embedding disabled') ." : $1</i><!-- /oembed $1 -->" ,$text);
}
diff --git a/include/permissions.php b/include/permissions.php
index 28f242712..29d242537 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -1,5 +1,7 @@
<?php
+use Zotlabs\Lib\Config;
+
require_once('include/security.php');
/**
@@ -105,7 +107,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_
// system is blocked to anybody who is not authenticated
- if(($check_siteblock) && (! $observer_xchan) && intval(get_config('system', 'block_public'))) {
+ if(($check_siteblock) && (! $observer_xchan) && intval(Config::Get('system', 'block_public'))) {
$ret[$perm_name] = 0;
continue;
}
@@ -291,7 +293,7 @@ function perm_is_allowed($uid, $observer_xchan, $permission, $check_siteblock =
// system is blocked to anybody who is not authenticated
- if(($check_siteblock) && (! $observer_xchan) && intval(get_config('system', 'block_public')))
+ if(($check_siteblock) && (! $observer_xchan) && intval(Config::Get('system', 'block_public')))
return false;
// Check if this $uid is actually the $observer_xchan
@@ -406,7 +408,7 @@ function get_all_api_perms($uid,$api) {
$arr = array(
'channel_id' => $uid,
- 'observer_hash' => $observer_xchan,
+ 'observer_hash' => null, //$observer_xchan,
'permissions' => $ret);
call_hooks('get_all_api_perms',$arr);
@@ -420,7 +422,7 @@ function api_perm_is_allowed($uid,$api,$permission) {
$arr = array(
'channel_id' => $uid,
- 'observer_hash' => $observer_xchan,
+ 'observer_hash' => null, //$observer_xchan,
'permission' => $permission,
'result' => false
);
@@ -496,7 +498,7 @@ function site_default_perms() {
$global_perms = \Zotlabs\Access\Permissions::Perms();
foreach($global_perms as $perm => $v) {
- $x = get_config('default_perms', $perm, $typical[$perm]);
+ $x = Config::Get('default_perms', $perm, $typical[$perm]);
$ret[$perm] = $x;
}
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index 4394d3238..66a5d19f9 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -1,5 +1,6 @@
<?php
+use Zotlabs\Lib\Config;
use Zotlabs\Photo\PhotoDriver;
use Zotlabs\Photo\PhotoGd;
use Zotlabs\Photo\PhotoImagick;
@@ -32,13 +33,13 @@ function photo_factory($data, $type = null) {
return null;
}
- $ignore_imagick = get_config('system', 'ignore_imagick');
+ $ignore_imagick = Config::Get('system', 'ignore_imagick');
if(class_exists('Imagick') && !$ignore_imagick) {
$v = Imagick::getVersion();
preg_match('/ImageMagick ([0-9]+\.[0-9]+\.[0-9]+)/', $v['versionString'], $m);
if(version_compare($m[1], '6.6.7') >= 0) {
- $limits = get_config('system', 'imagick_limits', false);
+ $limits = Config::Get('system', 'imagick_limits', false);
if ($limits)
foreach ($limits as $k => $v)
IMagick::setResourceLimit($k, $v);
@@ -99,7 +100,7 @@ function guess_image_type($filename, $data = '') {
}
if(is_null($type)){
- $ignore_imagick = get_config('system', 'ignore_imagick');
+ $ignore_imagick = Config::Get('system', 'ignore_imagick');
// Guessing from extension? Isn't that... dangerous?
if(class_exists('Imagick') && ! $ignore_imagick) {
$v = Imagick::getVersion();
diff --git a/include/photos.php b/include/photos.php
index 5e993e15f..a9f92e103 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -6,6 +6,8 @@
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Lib\Activity;
+use Zotlabs\Lib\Config;
+use Zotlabs\Daemon\Master;
require_once('include/permissions.php');
require_once('include/items.php');
@@ -74,11 +76,11 @@ function photo_upload($channel, $observer, $args) {
$os_storage = 0;
- $max_thumb = get_config('system', 'max_thumbnail', 1600);
+ $max_thumb = Config::Get('system', 'max_thumbnail', 1600);
if ($args['os_syspath'] && $args['getimagesize']) {
if ($args['getimagesize'][0] > $max_thumb || $args['getimagesize'][1] > $max_thumb) {
- $imagick_path = get_config('system', 'imagick_convert_path');
+ $imagick_path = Config::Get('system', 'imagick_convert_path');
if ($imagick_path && @file_exists($imagick_path)) {
$tmp_name = $args['os_syspath'] . '-001';
$newsize = photo_calculate_scale(array_merge($args['getimagesize'], ['max' => $max_thumb]));
@@ -146,7 +148,7 @@ function photo_upload($channel, $observer, $args) {
logger('Received file: ' . $filename . ' as ' . $src . ' (' . $type . ') ' . $filesize . ' bytes', LOGGER_DEBUG);
- $maximagesize = get_config('system', 'maximagesize');
+ $maximagesize = Config::Get('system', 'maximagesize');
if (($maximagesize) && ($filesize > $maximagesize)) {
$ret['message'] = sprintf(t('Image exceeds website size limit of %lu bytes'), $maximagesize);
@@ -219,7 +221,7 @@ function photo_upload($channel, $observer, $args) {
@unlink($src);
- $max_length = get_config('system', 'max_image_length');
+ $max_length = Config::Get('system', 'max_image_length');
if (!$max_length)
$max_length = MAX_IMAGE_LENGTH;
if ($max_length > 0)
@@ -404,7 +406,7 @@ function photo_upload($channel, $observer, $args) {
}
}
- $attribution = (($visitor) ? $visitor : $channel['xchan_url']);
+ $attribution = (($visitor) ? $visitor : channel_url($channel));
//// Create item object
$object = [
@@ -437,13 +439,13 @@ function photo_upload($channel, $observer, $args) {
else {
$object['to'] = Activity::map_acl(array_merge($ac, ['item_private' => 1 - intval($public)]));
}
-
+/*
$target = [
'type' => 'orderedCollection',
'name' => ((strlen($album)) ? $album : '/'),
'id' => z_root() . '/album/' . $channel['channel_address'] . ((isset($args['directory']['hash'])) ? '/' . $args['directory']['hash'] : EMPTY_STR)
];
-
+*/
// Create item container
if (isset($args['item'])) {
foreach ($args['item'] as $i) {
@@ -452,6 +454,11 @@ function photo_upload($channel, $observer, $args) {
$force = false;
if ($item['mid'] === $item['parent_mid']) {
+ $target = [
+ 'id' => str_replace('/item/', '/conversation/', $item['mid']),
+ 'type' => 'Collection',
+ 'attributedTo' => $attribution,
+ ];
$item['body'] = $summary;
$item['mimetype'] = 'text/bbcode';
@@ -459,10 +466,10 @@ function photo_upload($channel, $observer, $args) {
$object['id'] = $item['mid'];
$object['diaspora:guid'] = $item['uuid'];
- $item['obj'] = json_encode($object);
+ $item['obj'] = $object;
- $item['tgt_type'] = 'orderedCollection';
- $item['target'] = json_encode($target);
+ $item['tgt_type'] = 'Collection';
+ $item['target'] = $target;
if ($post_tags) {
$arr['term'] = $post_tags;
}
@@ -476,15 +483,23 @@ function photo_upload($channel, $observer, $args) {
if (($item['edited'] > $r[0]['edited']) || $force) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
- item_store_update($item, false, $deliver);
+ $result = item_store_update($item, deliver: $deliver);
continue;
}
}
else {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
- item_store($item, false, $deliver);
+ $result = item_store($item, deliver: $deliver);
}
+
+ if ($result['success'] && $visible && $deliver) {
+ Master::Summon(['Notifier', 'wall-new', $result['item_id']]);
+ if (!empty($result['approval_id'])) {
+ Master::Summon(['Notifier', 'wall-new', $result['approval_id']]);
+ }
+ }
+
}
}
else {
@@ -495,6 +510,12 @@ function photo_upload($channel, $observer, $args) {
$object['id'] = $mid;
$object['diaspora:guid'] = $uuid;
+ $target = [
+ 'id' => z_root() . '/conversation/' . $uuid,
+ 'type' => 'Collection',
+ 'attributedTo' => $attribution,
+ ];
+
$arr = [
'aid' => $account_id,
'uid' => $channel_id,
@@ -513,9 +534,9 @@ function photo_upload($channel, $observer, $args) {
'deny_gid' => $ac['deny_gid'],
'verb' => 'Create',
'obj_type' => 'Image',
- 'obj' => json_encode($object),
- 'tgt_type' => 'orderedCollection',
- 'target' => json_encode($target),
+ 'obj' => $object,
+ 'tgt_type' => 'Collection',
+ 'target' => $target,
'item_wall' => $visible,
'item_origin' => 1,
'item_thread_top' => 1,
@@ -540,21 +561,26 @@ function photo_upload($channel, $observer, $args) {
// linked item from leaking into the feed when somebody has a channel with read_stream restrictions.
$arr['public_policy'] = map_scope(PermissionLimits::Get($channel['channel_id'], 'view_stream'), true);
- if ($arr['public_policy'])
+
+ if ($arr['public_policy']) {
$arr['item_private'] = 1;
+ }
- $result = item_store($arr, false, $deliver);
- $item_id = $result['item_id'];
+ $result = item_store($arr, deliver: $deliver);
- if ($visible && $deliver)
- Zotlabs\Daemon\Master::Summon(['Notifier', 'wall-new', $item_id]);
+ if ($result['success'] && $visible && $deliver) {
+ Master::Summon(['Notifier', 'wall-new', $result['item_id']]);
+ if (!empty($result['approval_id'])) {
+ Master::Summon(['Notifier', 'wall-new', $result['approval_id']]);
+ }
+ }
}
$ret['success'] = true;
$ret['item'] = $arr;
$ret['body'] = $obj_body;
$ret['resource_id'] = $photo_hash;
- $ret['photoitem_id'] = $item_id;
+ $ret['photoitem_id'] = $result['item_id'];
/**
* @hooks photo_upload_end
@@ -910,7 +936,7 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
. '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['imgscale'] . '[/zmg]'
. '[/zrl]';
- $result = item_store($arr);
+ $result = item_store($arr, deliver: false, addAndSync: true);
$item_id = $result['item_id'];
return $item_id;
diff --git a/include/plugin.php b/include/plugin.php
index bbfeab988..b5f9959b9 100644
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -5,6 +5,7 @@
* @brief Some functions to handle addons and themes.
*/
+use Zotlabs\Lib\Config;
/**
* @brief Handle errors in plugin calls.
@@ -25,7 +26,7 @@ function handleerrors_plugin($plugin, $notice, $log, $uninstall = false){
$idx = array_search($plugin, \App::$plugins);
unset(\App::$plugins[$idx]);
uninstall_plugin($plugin);
- set_config("system", "addon", implode(", ", \App::$plugins));
+ Config::Set("system", "addon", implode(", ", \App::$plugins));
}
}
@@ -187,7 +188,7 @@ function plugin_is_installed($name) {
* @brief Reload all updated plugins.
*/
function reload_plugins() {
- $plugins = get_config('system', 'addon');
+ $plugins = Config::Get('system', 'addon');
if(strlen($plugins)) {
$r = dbq("SELECT * FROM addon WHERE installed = 1");
if($r)
@@ -266,7 +267,7 @@ function plugins_sync() {
$installed = plugins_installed_list();
- $plugins = get_config('system', 'addon', '');
+ $plugins = Config::Get('system', 'addon', '');
$plugins_arr = explode(',', $plugins);
@@ -487,18 +488,19 @@ function call_hooks($name, &$data = null) {
@include_once($hook[0]);
}
- if(preg_match('|^a:[0-9]+:{.*}$|s', $hook[1])) {
- $hook[1] = unserialize($hook[1]);
- }
- elseif(strpos($hook[1],'::')) {
- // We shouldn't need to do this, but it appears that PHP
- // isn't able to directly execute a string variable with a class
- // method in the manner we are attempting it, so we'll
- // turn it into an array.
- $hook[1] = explode('::',$hook[1]);
+ if(is_string($hook[1])) {
+ if (preg_match('|^a:[0-9]+:{.*}$|s', $hook[1])) {
+ $hook[1] = unserialize($hook[1]);
+ }
+ elseif(strpos($hook[1],'::')) {
+ // We shouldn't need to do this, but it appears that PHP
+ // isn't able to directly execute a string variable with a class
+ // method in the manner we are attempting it, so we'll
+ // turn it into an array.
+ $hook[1] = explode('::',$hook[1]);
+ }
}
-
if(is_callable($hook[1])) {
$func = $hook[1];
$func($data);
@@ -719,7 +721,7 @@ function check_plugin_versions($info) {
continue;
if(strpos($test,'.')) {
$conf = explode('.',$test);
- if(get_config(trim($conf[0]),trim($conf[1])))
+ if(Config::Get(trim($conf[0]),trim($conf[1])))
return true;
else
return false;
@@ -985,12 +987,13 @@ function format_css_if_exists($source) {
}
} else {
// It's a file from the theme
- $path = theme_include($script);
+ $theme_include = theme_include($script);
+ $path = (($theme_include) ? '/' . $theme_include : '');
}
if($path) {
$qstring = ((parse_url($path, PHP_URL_QUERY)) ? '&' : '?') . 'v=' . STD_VERSION;
- return '<link rel="stylesheet" href="' . $path_prefix . '/' . $path . $qstring . '" type="text/css" media="' . $source[1] . '">' . "\r\n";
+ return '<link rel="stylesheet" href="' . $path_prefix . $path . $qstring . '" type="text/css" media="' . $source[1] . '">' . "\r\n";
}
}
@@ -1057,11 +1060,12 @@ function format_js_if_exists($source) {
}
else {
// It's a file from the theme
- $path = theme_include($source);
+ $theme_include = theme_include($source);
+ $path = (($theme_include) ? '/' . $theme_include : '');
}
if($path) {
$qstring = ((parse_url($path, PHP_URL_QUERY)) ? '&' : '?') . 'v=' . STD_VERSION;
- return '<script src="' . $path_prefix . '/' . $path . $qstring . '" ></script>' . "\r\n" ;
+ return '<script src="' . $path_prefix . $path . $qstring . '"></script>' . "\r\n" ;
}
}
diff --git a/include/security.php b/include/security.php
index b3e45742e..4b072cf92 100644
--- a/include/security.php
+++ b/include/security.php
@@ -5,8 +5,10 @@
* @brief Some security related functions.
*/
+use Zotlabs\Lib\Config;
+
/**
- * @param int $user_record The account_id
+ * @param array $user_record The account record
* @param array $channel
* @param bool $login_initial default false
* @param bool $interactive default false
@@ -319,6 +321,7 @@ function change_channel($change_channel) {
function permissions_sql($owner_id, $remote_observer = null, $table = '', $token = EMPTY_STR) {
$local_channel = local_channel();
+ $observer = $remote_observer ?? get_observer_hash();
/**
* Construct permissions
@@ -342,15 +345,22 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '', $token
if (($local_channel) && ($local_channel == $owner_id)) {
return EMPTY_STR;
}
- /**
- * Authenticated visitor.
- */
-
else {
- $observer = ((!is_null($remote_observer)) ? $remote_observer : get_observer_hash());
+ /*
+ * OCAP token access
+ */
- if ($observer) {
+ if ($token) {
+ $sql = " AND ( {$table}allow_cid like '" . protect_sprintf('%<token:' . $token . '>%') .
+ "' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '' AND {$table}deny_cid = '' AND {$table}deny_gid = '' ) )";
+ }
+
+ /**
+ * Authenticated visitor.
+ */
+
+ elseif ($observer) {
$sec = get_security_ids($owner_id, $observer);
@@ -398,16 +408,6 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '', $token
dbesc($gs)
);
}
-
- /*
- * OCAP token access
- */
-
- elseif ($token) {
- $sql = " AND ( {$table}allow_cid like '" . protect_sprintf('%<token:' . $token . '>%') .
- "' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '' AND {$table}deny_cid = '' AND {$table}deny_gid = '' ) )";
- }
-
}
return $sql;
@@ -495,7 +495,7 @@ function item_permissions_sql($owner_id, $remote_observer = null) {
" AND ( author_xchan = '%s' OR owner_xchan = '%s' OR
(( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s')
AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ))
- )))
+ )) OR ( item_private = 1 $scope ))
",
dbesc($observer),
dbesc($observer),
@@ -706,56 +706,61 @@ function get_security_ids($channel_id, $ob_hash) {
'allow_gid' => []
];
- if ($channel_id) {
- $ch = q("select channel_hash from channel where channel_id = %d",
- intval($channel_id)
- );
- if ($ch) {
- $ret['channel_id'][] = $ch[0]['channel_hash'];
- }
- }
-
- $groups = [];
-
- $x = q("select * from xchan where xchan_hash = '%s'",
+ $x = q("select xchan_hash from xchan where xchan_hash = '%s'",
dbesc($ob_hash)
);
- if ($x) {
+ if (!$x) {
+ return $ret;
+ }
- // include xchans for all zot-like networks
+ $ret['allow_cid'][] = $x[0]['xchan_hash'];
- $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
- dbesc($ob_hash),
- dbesc($x[0]['xchan_guid']),
- dbesc($x[0]['xchan_pubkey'])
- );
+ if (!$channel_id) {
+ return $ret;
+ }
- if ($xchans) {
- $ret['allow_cid'] = ids_to_array($xchans, 'xchan_hash');
- $hashes = ids_to_querystr($xchans, 'xchan_hash', true);
+ $ch = q("select channel_hash from channel where channel_id = %d",
+ intval($channel_id)
+ );
+ if ($ch) {
+ $ret['channel_id'][] = $ch[0]['channel_hash'];
+ }
- // private profiles are treated as a virtual group
+ $groups = [];
- $r = q("SELECT abook_profile from abook where abook_xchan in ( " . protect_sprintf($hashes) . " ) and abook_profile != '' ");
- if ($r) {
- foreach ($r as $rv) {
- $groups[] = 'vp.' . $rv['abook_profile'];
- }
+ // private profiles are treated as a virtual group
+
+ $r = q("SELECT abook_profile from abook where abook_channel = %d and abook_xchan = '%s' and abook_profile != ''",
+ intval($channel_id),
+ dbesc(protect_sprintf($x[0]['xchan_hash']))
+ );
+
+ if ($r) {
+ foreach ($r as $rv) {
+ if (!in_array('vp.' . $rv['abook_profile'], $groups)) {
+ $groups[] = 'vp.' . $rv['abook_profile'];
}
+ }
+ }
- // physical groups this identity is a member of
+ // physical groups this identity is a member of
- $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan in ( " . protect_sprintf($hashes) . " ) ");
- if ($r) {
- foreach ($r as $rv) {
- $groups[] = $rv['hash'];
- }
+ $r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE pgrp.uid = %d and pgrp_member.xchan = '%s'",
+ intval($channel_id),
+ dbesc(protect_sprintf($x[0]['xchan_hash']))
+ );
+
+ if ($r) {
+ foreach ($r as $rv) {
+ if (!in_array($rv['hash'], $groups)) {
+ $groups[] = $rv['hash'];
}
- $ret['allow_gid'] = $groups;
}
}
+ $ret['allow_gid'] = $groups;
+
return $ret;
}
@@ -872,7 +877,7 @@ function stream_perms_xchans($perms = NULL) {
*/
function zarIsDuty($wd=NULL, $hhmm=NULL, $op='isOpen') {
- $isduty = get_config('system', 'register_duty_jso');
+ $isduty = Config::Get('system', 'register_duty_jso');
if (!$isduty)
return (bool)false;
@@ -906,7 +911,6 @@ function zarIsDuty($wd=NULL, $hhmm=NULL, $op='isOpen') {
}
}
return $dutyis;
- break;
case 'nextOpen':
/**
@@ -951,7 +955,6 @@ function zarIsDuty($wd=NULL, $hhmm=NULL, $op='isOpen') {
}
}
return $is1; // false or array
- break;
default:
//
diff --git a/include/socgraph.php b/include/socgraph.php
index e5e8ddf74..336c1c0c3 100644
--- a/include/socgraph.php
+++ b/include/socgraph.php
@@ -1,6 +1,7 @@
<?php /** @file */
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Libzotdir;
use Zotlabs\Lib\Zotfinger;
@@ -288,7 +289,7 @@ function suggestion_query($uid, $myxchan, $start = 0, $limit = 80) {
function update_suggestions() {
- $dirmode = get_config('system', 'directory_mode', DIRECTORY_MODE_NORMAL);
+ $dirmode = Config::Get('system', 'directory_mode', DIRECTORY_MODE_NORMAL);
if($dirmode == DIRECTORY_MODE_STANDALONE) {
poco_load('', z_root() . '/poco');
diff --git a/include/statistics_fns.php b/include/statistics_fns.php
index 98b0efd41..5915c82a2 100644
--- a/include/statistics_fns.php
+++ b/include/statistics_fns.php
@@ -1,13 +1,15 @@
<?php /** @file */
+use Zotlabs\Lib\Config;
+
function update_channels_total_stat() {
$r = q("select count(channel_id) as channels_total from channel left join account on account_id = channel_account_id
where account_flags = 0 ");
if($r) {
$channels_total_stat = intval($r[0]['channels_total']);
- set_config('system','channels_total_stat',$channels_total_stat);
+ Config::Set('system','channels_total_stat',$channels_total_stat);
} else {
- set_config('system','channels_total_stat',0);
+ Config::Set('system','channels_total_stat',0);
}
}
@@ -17,10 +19,10 @@ function update_channels_active_halfyear_stat() {
db_utcnow(), db_quoteinterval('6 MONTH')
);
if($r) {
- set_config('system','channels_active_halfyear_stat',count($r));
+ Config::Set('system','channels_active_halfyear_stat',count($r));
}
else {
- set_config('system','channels_active_halfyear_stat','0');
+ Config::Set('system','channels_active_halfyear_stat','0');
}
}
@@ -30,10 +32,10 @@ function update_channels_active_monthly_stat() {
db_utcnow(), db_quoteinterval('1 MONTH')
);
if($r) {
- set_config('system','channels_active_monthly_stat',count($r));
+ Config::Set('system','channels_active_monthly_stat',count($r));
}
else {
- set_config('system','channels_active_monthly_stat','0');
+ Config::Set('system','channels_active_monthly_stat','0');
}
}
@@ -41,9 +43,9 @@ function update_local_posts_stat() {
$posts = q("SELECT COUNT(*) AS local_posts FROM item WHERE item_wall = 1 and id = parent");
if (is_array($posts)) {
$local_posts_stat = intval($posts[0]["local_posts"]);
- set_config('system','local_posts_stat',$local_posts_stat);
+ Config::Set('system','local_posts_stat',$local_posts_stat);
} else {
- set_config('system','local_posts_stat',0);
+ Config::Set('system','local_posts_stat',0);
}
}
@@ -54,5 +56,5 @@ function update_local_comments_stat() {
else
$local_posts = $posts[0]["local_posts"];
- set_config('system','local_comments_stat', $local_posts);
-} \ No newline at end of file
+ Config::Set('system','local_comments_stat', $local_posts);
+}
diff --git a/include/taxonomy.php b/include/taxonomy.php
index dd56ab956..45287fa63 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -6,8 +6,10 @@
// To do this we need to escape these characters if they appear in our tag.
use Zotlabs\Lib\Cache;
+use Zotlabs\Lib\Config;
use Zotlabs\Daemon\Master;
+
function file_tag_encode($s) {
return str_replace(array('<','>','[',']'),array('%3c','%3e','%5b','%5d'),$s);
}
@@ -351,7 +353,7 @@ function pub_tagadelic($net, $site, $limit, $recent, $safemode, $type) {
}
if($safemode) {
- $unsafetags = get_config('system','unsafepubtags', [ 'boobs', 'bot', 'rss', 'girl','girls', 'nsfw', 'sexy', 'nude' ]);
+ $unsafetags = Config::Get('system','unsafepubtags', [ 'boobs', 'bot', 'rss', 'girl','girls', 'nsfw', 'sexy', 'nude' ]);
if($unsafetags) {
$sql_extra .= " and not term.term in ( " . stringify_array($unsafetags,true) . ") ";
}
diff --git a/include/text.php b/include/text.php
index 713911af2..7692a6f3e 100644
--- a/include/text.php
+++ b/include/text.php
@@ -9,6 +9,7 @@ use Michelf\MarkdownExtra;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Crypto;
use Zotlabs\Lib\SvgSanitizer;
use Zotlabs\Lib\Libzot;
@@ -741,9 +742,9 @@ function logger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) {
$loglevel = LOGGER_ALL;
}
else {
- $debugging = get_config('system', 'debugging');
- $loglevel = intval(get_config('system', 'loglevel'));
- $logfile = get_config('system', 'logfile');
+ $debugging = Config::Get('system', 'debugging');
+ $loglevel = intval(Config::Get('system', 'loglevel'));
+ $logfile = Config::Get('system', 'logfile');
}
if((! $debugging) || (! $logfile) || ($level > $loglevel))
@@ -846,9 +847,9 @@ function dlogger($msg, $level = 0) {
if(App::$module == 'setup')
return;
- $debugging = get_config('system','debugging');
- $loglevel = intval(get_config('system','loglevel'));
- $logfile = get_config('system','dlogfile');
+ $debugging = Config::Get('system','debugging');
+ $loglevel = intval(Config::Get('system','loglevel'));
+ $logfile = Config::Get('system','dlogfile');
if((! $debugging) || (! $logfile) || ($level > $loglevel))
return;
@@ -1144,7 +1145,7 @@ function chanlink_cid($d) {
function magiclink_url($observer,$myaddr,$url) {
return (($observer)
- ? z_root() . '/magic?f=&owa=1&bdest=' . bin2hex($url) . '&addr=' . $myaddr
+ ? z_root() . '/magic?owa=1&bdest=' . bin2hex($url) . '&addr=' . $myaddr
: $url
);
}
@@ -1253,7 +1254,7 @@ function sslify($s) {
// The downside is that http: media files will likely be blocked by your browser
// Complain to your browser maker
- $allow = get_config('system','sslify_everything');
+ $allow = Config::Get('system','sslify_everything');
$pattern = (($allow) ? "/\<(.*?)src=[\"|'](http\:.*?)[\"|'](.*?)\>/" : "/\<img(.*?)src=[\"|'](http\:.*?)[\"|'](.*?)\>/" );
$matches = null;
@@ -1407,7 +1408,7 @@ function list_smilies($default_only = false) {
*/
function smilies($s, $sample = false) {
- if(intval(get_config('system', 'no_smilies'))
+ if(intval(Config::Get('system', 'no_smilies'))
|| (local_channel() && intval(get_pconfig(local_channel(), 'system', 'no_smilies'))))
return $s;
@@ -1578,15 +1579,13 @@ function theme_attachments(&$item) {
$title = t('Size') . ' ' . (isset($r['length']) ? userReadableSize($r['length']) : t('unknown'));
- $revision = $r['revision'] ?? '';
-
require_once('include/channel.php');
if (isset($r['href'])) {
if(is_foreigner($item['author_xchan']))
$url = $r['href'];
else
- $url = z_root() . '/magic?f=&owa=1&hash=' . $item['author_xchan'] . '&bdest=' . bin2hex($r['href'] . '/' . $revision);
+ $url = z_root() . '/magic?owa=1&bdest=' . bin2hex($r['href']);
}
if (isset($label) && isset($url) && isset($icon) && isset($title)) {
@@ -1651,7 +1650,7 @@ function format_hashtags(&$item) {
if($s)
$s .= ' ';
- $s .= '<span class="badge rounded-pill bg-info"><i class="fa fa-hashtag"></i>&nbsp;<a class="text-white" href="' . zid($t['url']) . '" >' . $term . '</a></span>';
+ $s .= '<span class="badge rounded-pill bg-info"><i class="bi bi-hash"></i>&nbsp;<a class="text-white" href="' . zid($t['url']) . '" >' . $term . '</a></span>';
}
}
@@ -1674,7 +1673,7 @@ function format_mentions(&$item) {
continue;
if($s)
$s .= ' ';
- $s .= '<span class="badge rounded-pill bg-success"><i class="fa fa-at"></i>&nbsp;<a class="text-white" href="' . zid($t['url']) . '" >' . $term . '</a></span>';
+ $s .= '<span class="badge rounded-pill bg-success"><i class="bi bi-at"></i>&nbsp;<a class="text-white" href="' . zid($t['url']) . '" >' . $term . '</a></span>';
}
}
@@ -2003,7 +2002,7 @@ function format_poll($item,$s,$opts) {
$message .= t('Poll has ended');
}
else {
- $message .= sprintf(t('Poll ends in %s'), '<span class="autotime" title="' . $t . '"></span>');
+ $message .= sprintf(t('Poll ends %s'), '<span class="autotime" title="' . $t . '"></span>');
}
}
@@ -2081,10 +2080,15 @@ function prepare_text($text, $content_type = 'text/bbcode', $opts = false) {
default:
require_once('include/bbcode.php');
- if(stristr($text, '[nosmile]'))
- $s = bbcode($text, ((is_array($opts)) ? $opts : [] ));
- else
- $s = smilies(bbcode($text, ((is_array($opts)) ? $opts : [] )));
+ // events are handled in format_event_obj()
+ if (empty($opts['is_event_item'])) {
+ if(stristr($text, '[nosmile]')) {
+ $s = bbcode($text, ((is_array($opts)) ? $opts : [] ));
+ }
+ else {
+ $s = smilies(bbcode($text, ((is_array($opts)) ? $opts : [] )));
+ }
+ }
$s = zidify_links($s);
@@ -2113,7 +2117,7 @@ function create_export_photo_body(&$item) {
* @return string
*/
function feed_hublinks() {
- $hub = get_config('system', 'huburl');
+ $hub = Config::Get('system', 'huburl');
$hubxml = '';
if(strlen($hub)) {
@@ -2496,7 +2500,7 @@ function check_webbie($arr) {
// These names conflict with the CalDAV server
$taken = [ 'principals', 'addressbooks', 'calendars' ];
- $reservechan = get_config('system','reserved_channels');
+ $reservechan = Config::Get('system','reserved_channels');
if(strlen($reservechan)) {
$taken = array_merge($taken,explode(',', $reservechan));
}
@@ -2633,13 +2637,13 @@ function xchan_query(&$items, $abook = true, $effective_uid = 0) {
if(count($arr)) {
if($abook) {
$chans = q("select * from xchan left join hubloc on hubloc_hash = xchan_hash left join abook on abook_xchan = xchan_hash and abook_channel = %d
- where xchan_hash in (" . protect_sprintf(implode(',', $arr)) . ") and hubloc_deleted = 0 order by hubloc_primary desc",
+ where xchan_hash in (" . protect_sprintf(implode(',', $arr)) . ") order by hubloc_primary desc, hubloc_deleted ASC",
intval($item['uid'])
);
}
else {
$chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash
- where xchan_hash in (" . protect_sprintf(implode(',', $arr)) . ") and hubloc_deleted = 0 order by hubloc_primary desc");
+ where xchan_hash in (" . protect_sprintf(implode(',', $arr)) . ") order by hubloc_primary desc, hubloc_deleted ASC");
}
$xchans = q("select * from xchan where xchan_hash in (" . protect_sprintf(implode(',',$arr)) . ") and xchan_network in ('rss','unknown', 'anon', 'token')");
if(! $chans)
@@ -3197,53 +3201,53 @@ function linkify_tags(&$body, $uid, $in_network = true) {
function getIconFromType($type) {
$iconMap = array(
//Folder
- 'Collection' => 'fa-folder-o',
- 'multipart/mixed' => 'fa-folder-o', //dirs in attach use this mime type
+ 'Collection' => 'bi-folder',
+ 'multipart/mixed' => 'bi-folder', //dirs in attach use this mime type
//Common file
- 'application/octet-stream' => 'fa-file-o',
+ 'application/octet-stream' => 'bi-file-earmark',
//Text
- 'text/plain' => 'fa-file-text-o',
- 'text/markdown' => 'fa-file-text-o',
- 'text/bbcode' => 'fa-file-text-o',
- 'text/html' => 'fa-file-text-o',
- 'application/msword' => 'fa-file-word-o',
- 'application/pdf' => 'fa-file-pdf-o',
- 'application/vnd.oasis.opendocument.text' => 'fa-file-word-o',
- 'application/epub+zip' => 'fa-book',
+ 'text/plain' => 'bi-file-earmark-text',
+ 'text/markdown' => 'bi-filetype-md',
+ 'text/bbcode' => 'bi-file-earmark-text',
+ 'text/html' => 'bi-filetype-html',
+ 'application/msword' => 'bi-file-earmark-word',
+ 'application/pdf' => 'bi-file-earmark-pdf',
+ 'application/vnd.oasis.opendocument.text' => 'bifile--earmark-text',
+ 'application/epub+zip' => 'bi-file-earmark-text',
//Spreadsheet
- 'application/vnd.oasis.opendocument.spreadsheet' => 'fa-file-excel-o',
- 'application/vnd.ms-excel' => 'fa-file-excel-o',
+ 'application/vnd.oasis.opendocument.spreadsheet' => 'bi-file-earmark-spreadsheet',
+ 'application/vnd.ms-excel' => 'bi-file-earmark-spreadsheet',
//Image
- 'image/jpeg' => 'fa-picture-o',
- 'image/png' => 'fa-picture-o',
- 'image/gif' => 'fa-picture-o',
- 'image/webp' => 'fa-picture-o',
- 'image/svg+xml' => 'fa-picture-o',
+ 'image/jpeg' => 'bi-file-earmark-image',
+ 'image/png' => 'bi-file-earmark-image',
+ 'image/gif' => 'bi-file-earmark-image',
+ 'image/webp' => 'bi-file-earmark-image',
+ 'image/svg+xml' => 'bi-filetype-svg',
//Archive
- 'application/zip' => 'fa-file-archive-o',
- 'application/x-rar-compressed' => 'fa-file-archive-o',
+ 'application/zip' => 'bi-file-earmark-zip',
+ 'application/x-rar-compressed' => 'bi-file-earmark-zip',
//Audio
- 'audio/mpeg' => 'fa-file-audio-o',
- 'audio/wav' => 'fa-file-audio-o',
- 'application/ogg' => 'fa-file-audio-o',
- 'audio/ogg' => 'fa-file-audio-o',
- 'audio/webm' => 'fa-file-audio-o',
- 'audio/mp4' => 'fa-file-audio-o',
+ 'audio/mpeg' => 'bi-file-earmark-music',
+ 'audio/wav' => 'bi-file-earmark-music',
+ 'application/ogg' => 'bi-file-earmark-music',
+ 'audio/ogg' => 'bi-file-earmark-music',
+ 'audio/webm' => 'bi-file-earmark-music',
+ 'audio/mp4' => 'bi-file-earmark-music',
//Video
- 'video/quicktime' => 'fa-file-video-o',
- 'video/webm' => 'fa-file-video-o',
- 'video/mp4' => 'fa-file-video-o',
- 'video/x-matroska' => 'fa-file-video-o'
+ 'video/quicktime' => 'bi-file-earmark-play',
+ 'video/webm' => 'bi-file-earmark-play',
+ 'video/mp4' => 'bi-file-earmark-play',
+ 'video/x-matroska' => 'bi-file-earmark-play'
);
$catMap = [
- 'application' => 'fa-file-code-o',
- 'multipart' => 'fa-folder',
- 'audio' => 'fa-file-audio-o',
- 'video' => 'fa-file-video-o',
- 'text' => 'fa-file-text-o',
- 'image' => 'fa=file-picture-o',
- 'message' => 'fa-file-text-o'
+ 'application' => 'bi-file-earmark',
+ 'multipart' => 'bi-folder',
+ 'audio' => 'bi-file-earmark-music',
+ 'video' => 'bi-file-earmark-play',
+ 'text' => 'bi-file-earmark-text',
+ 'image' => 'bi-file-earmark-image',
+ 'message' => 'bi-file-earmark-text'
];
@@ -3260,7 +3264,7 @@ function getIconFromType($type) {
}
if(! $iconFromType) {
- $iconFromType = 'fa-file-o';
+ $iconFromType = 'bi-file-earmark';
}
@@ -3749,12 +3753,9 @@ function cleanup_bbcode($body) {
$body = preg_replace_callback('/\[img(.*?)\[\/(img)\]/ism','\red_escape_codeblock',$body);
$body = preg_replace_callback('/\[zmg(.*?)\[\/(zmg)\]/ism','\red_escape_codeblock',$body);
- $body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
-+\,\(\)]+)/ismu", '\nakedoembed', $body);
-
- $body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\
-+\,\(\)]+)/ismu", '\red_zrl_callback', $body);
+ $body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\+\,\(\)]+)/ismu", '\nakedoembed', $body);
+ $body = preg_replace_callback("/([^\]\='".'"'."\;\/\{]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\\+\,\(\)]+)/ismu", '\red_zrl_callback', $body);
$body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','\red_unescape_codeblock',$body);
$body = preg_replace_callback('/\[\$b64summary(.*?)\[\/(summary)\]/ism','\red_unescape_codeblock',$body);
@@ -3840,7 +3841,7 @@ function featured_sort($a,$b) {
function unpunify($s) {
- if (function_exists('idn_to_utf8') && isset($s)) {
+ if (function_exists('idn_to_utf8') && !empty($s)) {
return idn_to_utf8($s);
}
return $s;
@@ -3848,7 +3849,7 @@ function unpunify($s) {
function punify($s) {
- if (function_exists('idn_to_ascii') && isset($s)) {
+ if (function_exists('idn_to_ascii') && !empty($s)) {
return idn_to_ascii($s);
}
return $s;
diff --git a/include/xchan.php b/include/xchan.php
index b8677c8c4..c492a77dc 100644
--- a/include/xchan.php
+++ b/include/xchan.php
@@ -217,6 +217,10 @@ function xchan_keychange_acl($table,$column,$oldxchan,$newxchan) {
function xchan_change_key($oldx,$newx,$data) {
+ // TODO: this will need a refactor to eliminate duplicate keys
+ // E.G. item => [author_xchan, owner_xchan, source_kchan]
+ // Also: add a test!
+
$tables = [
'abook' => 'abook_xchan',
'abconfig' => 'xchan',
@@ -227,8 +231,6 @@ function xchan_change_key($oldx,$newx,$data) {
'item' => 'owner_xchan',
'item' => 'author_xchan',
'item' => 'source_xchan',
- 'mail' => 'from_xchan',
- 'mail' => 'to_xchan',
'shares' => 'share_xchan',
'source' => 'src_channel_xchan',
'source' => 'src_xchan',
diff --git a/include/zid.php b/include/zid.php
index b38457d99..b74e82930 100644
--- a/include/zid.php
+++ b/include/zid.php
@@ -1,5 +1,6 @@
<?php
+use Zotlabs\Lib\Config;
use Zotlabs\Lib\Libzot;
use Zotlabs\Lib\Verify;
@@ -37,10 +38,16 @@ function is_matrix_url($url) {
* @return string
*/
function zid($s, $address = '') {
- if (!$s || strpos($s,'zid='))
+ if (!$s || strpos($s,'zid=')) {
return $s;
+ }
$m = parse_url($s);
+
+ if (!is_array($m)) {
+ return $s;
+ }
+
$fragment = ((array_key_exists('fragment',$m) && $m['fragment']) ? $m['fragment'] : false);
if($fragment !== false)
$s = str_replace('#' . $fragment,'',$s);
@@ -143,6 +150,9 @@ function clean_query_string($s = '') {
*/
function drop_query_params($s, $p) {
+
+ $s = unescape_tags($s);
+
$parsed = parse_url($s);
$query = '';
$query_args = null;
@@ -165,7 +175,7 @@ function drop_query_params($s, $p) {
$parsed['query'] = $query;
}
- return unparse_url($parsed);
+ return escape_tags(unparse_url($parsed));
}
@@ -254,25 +264,25 @@ function zidify_text($s) {
*/
function red_zrl_callback($matches) {
- // Catch and exclude trailing punctuation
- preg_match("/[.,;:!?)]*$/i", $matches[2], $pts);
- $matches[2] = substr($matches[2], 0, strlen($matches[2])-strlen($pts[0]));
+ // Catch and exclude trailing punctuation
+ preg_match("/[.,;:!?)]*$/i", $matches[2], $pts);
+ $matches[2] = substr($matches[2], 0, strlen($matches[2])-strlen($pts[0]));
- $zrl = is_matrix_url($matches[2]);
+ $zrl = is_matrix_url($matches[2]);
- $t = strip_zids($matches[2]);
- if($t !== $matches[2]) {
- $zrl = true;
- $matches[2] = $t;
- }
+ $t = strip_zids($matches[2]);
+ if($t !== $matches[2]) {
+ $zrl = true;
+ $matches[2] = $t;
+ }
- if($matches[1] === '#^')
- $matches[1] = '';
+ if($matches[1] === '#^')
+ $matches[1] = '';
- if($zrl)
- return $matches[1] . '#^[zrl=' . $matches[2] . ']' . $matches[2] . '[/zrl]' . $pts[0];
+ if($zrl)
+ return $matches[1] . '#^[zrl=' . $matches[2] . ']' . $matches[2] . '[/zrl]' . $pts[0];
- return $matches[1] . '#^[url=' . $matches[2] . ']' . $matches[2] . '[/url]' . $pts[0];
+ return $matches[1] . '#^[url=' . $matches[2] . ']' . $matches[2] . '[/url]' . $pts[0];
}
/**
@@ -406,7 +416,7 @@ function owt_init($token) {
App::set_observer($hubloc);
require_once('include/security.php');
App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
- if(! get_config('system', 'hide_owa_greeting'))
+ if(! Config::Get('system', 'hide_owa_greeting'))
info(sprintf( t('OpenWebAuth: %1$s welcomes %2$s'),App::get_hostname(), $hubloc['xchan_name']));
logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);