Merge branch 'dev' of https://codeberg.org/zot/zap into dev

This commit is contained in:
nobody 2022-01-05 08:19:07 +11:00
commit 193a5403a7
35 changed files with 21017 additions and 20826 deletions

View file

@ -2975,8 +2975,10 @@ class Activity
$s['verb'] = self::activity_mapper($act->type);
// Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here.
if ($act->type === 'Update' && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) {
$s['edited'] = datetime_convert();
if (in_array($act->type,['Create','Update']) && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) {
if (isset($act->obj['votersCount']) && intval($act->obj['votersCount'])) {
$s['edited'] = datetime_convert();
}
}

View file

@ -317,12 +317,30 @@ class ActivityStreams
return Activity::fetch($url, $channel, $hub);
}
public static function is_an_actor($s)
/**
* @brief given a type, determine if this object represents an actor
*
* If $type is an array, recurse through each element and return true if any
* of the elements are a known actor type
*
* @param string|array $type
* @return boolean
*/
public static function is_an_actor($type)
{
if (!$s) {
if (!$type) {
return false;
}
return (in_array($s, ['Application', 'Group', 'Organization', 'Person', 'Service']));
if (is_array($type)) {
foreach ($type as $x) {
if (self::is_an_actor($x)) {
return true;
}
}
return false;
}
return (in_array($type, ['Application', 'Group', 'Organization', 'Person', 'Service']));
}
public static function is_response_activity($s)

View file

@ -446,6 +446,9 @@ class Apps
* nav: render apps for app-bin
*/
$channel_id = local_channel();
$sys_channel = is_sys_channel($channel_id);
$installed = false;
if (!$papp) {
@ -469,7 +472,7 @@ class Apps
if (strpos($papp['url'], '$baseurl') !== false || strpos($papp['url'], '$nick') !== false || strpos($papp['photo'], '$baseurl') !== false || strpos($papp['photo'], '$nick') !== false) {
$view_channel = local_channel();
$view_channel = $channel_id;
if (!$view_channel) {
$sys = get_sys_channel();
$view_channel = $sys['channel_id'];
@ -490,7 +493,7 @@ class Apps
foreach ($papp as $k => $v) {
if (strpos($v, 'http') === 0 && $k != 'papp') {
if (!(local_channel() && strpos($v, z_root()) === 0)) {
if (!($channel_id && strpos($v, z_root()) === 0)) {
$papp[$k] = zid($v);
}
}
@ -513,17 +516,17 @@ class Apps
switch ($require) {
case 'nologin':
if (local_channel()) {
if ($channel_id) {
return '';
}
break;
case 'admin':
if (!is_site_admin()) {
if (!(is_site_admin() || $sys_channel)) {
return '';
}
break;
case 'local_channel':
if (!local_channel()) {
if (!$channel_id) {
return '';
}
break;
@ -538,7 +541,7 @@ class Apps
}
break;
case 'custom_role':
if (get_pconfig(local_channel(), 'system', 'permissions_role') != 'custom') {
if (get_pconfig($channel_id, 'system', 'permissions_role') != 'custom') {
return '';
}
break;
@ -552,7 +555,7 @@ class Apps
if ($config) {
$unset = ((get_config('system', $require[0]) === $require[1]) ? false : true);
} else {
$unset = ((local_channel() && feature_enabled(local_channel(), $require)) ? false : true);
$unset = (($channel_id && feature_enabled($channnel_id, $require)) ? false : true);
}
if ($unset) {
return '';
@ -565,14 +568,13 @@ class Apps
$hosturl = '';
if (local_channel()) {
if (self::app_installed(local_channel(), $papp) && (!(isset($papp['deleted']) && intval($papp['deleted'])))) {
if ($channel_id || $sys_channel) {
if (self::app_installed(($sys_channel) ? 0 : $channel_id, $papp)) {
$installed = true;
if ($mode === 'install') {
return '';
}
}
$hosturl = z_root() . '/';
} elseif (remote_channel()) {
$observer = App::get_observer();
@ -612,10 +614,10 @@ class Apps
'$purchase' => ((isset($papp['page']) && $papp['page'] && (!$installed)) ? t('Purchase') : ''),
'$installed' => $installed,
'$action_label' => (($hosturl && in_array($mode, ['view', 'install'])) ? $install_action : ''),
'$edit' => ((local_channel() && $installed && $mode === 'edit') ? t('Edit') : ''),
'$delete' => ((local_channel() && $installed && $mode === 'edit') ? t('Delete') : ''),
'$undelete' => ((local_channel() && $installed && $mode === 'edit') ? t('Undelete') : ''),
'$settings_url' => ((local_channel() && $installed && $mode === 'list' && isset($papp['settings_url'])) ? $papp['settings_url'] : ''),
'$edit' => (($channel_id && $installed && $mode === 'edit') ? t('Edit') : ''),
'$delete' => (($channel_id && $installed && $mode === 'edit') ? t('Delete') : ''),
'$undelete' => (($channel_id && $installed && $mode === 'edit') ? t('Undelete') : ''),
'$settings_url' => (($channel_id && $installed && $mode === 'list' && isset($papp['settings_url'])) ? $papp['settings_url'] : ''),
'$deleted' => ((isset($papp['deleted'])) ? intval($papp['deleted']) : false),
'$feature' => (((isset($papp['embed']) && $papp['embed']) || $mode === 'edit') ? false : true),
'$pin' => (((isset($papp['embed']) && $papp['embed']) || $mode === 'edit') ? false : true),
@ -649,6 +651,16 @@ class Apps
$app['uid'] = $uid;
if (self::app_installed($uid, $app, true)) {
// preserve the existing deleted status across app updates
if (isset($app['guid'])) {
$check = q("select * from app where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
);
if ($check) {
$app['deleted'] = intval($check[0]['app_deleted']);
}
}
$x = self::app_update($app);
} else {
$x = self::app_store($app);
@ -684,6 +696,8 @@ class Apps
public static function can_delete($uid, $app)
{
// $uid 0 cannot delete, only archive
if (!$uid) {
return false;
}
@ -703,11 +717,11 @@ class Apps
public static function app_destroy($uid, $app)
{
if ($uid && $app['guid']) {
if ($app['guid']) {
$x = q(
"select * from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($app['guid']),
intval($uid)
intval($target_uid)
);
if ($x) {
if (!intval($x[0]['app_deleted'])) {
@ -728,14 +742,16 @@ class Apps
$r = q(
"update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
dbesc($app['guid']),
intval($uid)
intval($target_uid)
);
}
if (intval($x[0]['app_system'])) {
Libsync::build_sync_packet($uid, array('sysapp' => $x));
} else {
Libsync::build_sync_packet($uid, array('app' => $x));
}
if ($uid) {
if (intval($x[0]['app_system'])) {
Libsync::build_sync_packet($uid, array('sysapp' => $x));
} else {
Libsync::build_sync_packet($uid, array('app' => $x));
}
}
} else {
self::app_undestroy($uid, $app);
}
@ -748,7 +764,7 @@ class Apps
// undelete a system app
if ($uid && $app['guid']) {
if ($app['guid']) {
$x = q(
"select * from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($app['guid']),
@ -795,7 +811,6 @@ class Apps
public static function app_installed($uid, $app, $bypass_filter = false)
{
$r = q(
"select id from app where app_id = '%s' and app_channel = %d limit 1",
dbesc((array_key_exists('guid', $app)) ? $app['guid'] : ''),

View file

@ -280,6 +280,23 @@ class Libprofile
*/
call_hooks('profile_sidebar_enter', $profile);
$profdm = EMPTY_STR;
$profdm_url = EMPTY_STR;
$can_dm = perm_is_allowed($profile['uid'], (is_array($observer)) ? $observer['xchan_hash'] : EMPTY_STR, 'post_mail') && intval($observer['xchan_type']) !== XCHAN_TYPE_GROUP ;
if ($can_dm) {
$dm_path = Libzot::get_rpost_path($observer);
if ($dm_path) {
$profdm = t('Direct Message');
$profdm_url = $dm_path
. '&to='
. urlencode($profile['channel_hash'])
. '&body='
. urlencode('@!{' . $profile['channel_address'] . '@' . App::get_hostname() . '}');
}
}
if ($show_connect) {
// This will return an empty string if we're already connected.
@ -364,7 +381,9 @@ class Libprofile
'$profile' => $profile,
'$connect' => $connect,
'$connect_url' => $connect_url,
'$location' => $location,
'$profdm' => $profdm,
'$profdm_url' => $profdm_url,
'$location' => $location,
'$gender' => $gender,
'$pronouns' => $pronouns,
'$pdesc' => $pdesc,

View file

@ -801,13 +801,14 @@ class Libzot
$deleted_changed = 1;
}
if ($arr['channel_type'] === 'collection') {
$px = 2;
} elseif ($arr['channel_type'] === 'group') {
$px = 1;
} else {
$px = 0;
}
$px = 0;
if (isset($arr['channel_type'])) {
if ($arr['channel_type'] === 'collection') {
$px = 2;
} elseif ($arr['channel_type'] === 'group') {
$px = 1;
}
}
if (array_key_exists('public_forum', $arr) && intval($arr['public_forum'])) {
$px = 1;
}
@ -1451,17 +1452,16 @@ class Libzot
$arr['item_verified'] = true;
if (!array_key_exists('comment_policy', $arr)) {
// set comment policy depending on source hub. Unknown or osada is ActivityPub.
// Anything else we'll say is zot - which could have a range of project names
// set comment policy based on type of site.
$s = q(
"select site_project from site where site_url = '%s' limit 1",
"select site_type from site where site_url = '%s' limit 1",
dbesc($r[0]['hubloc_url'])
);
if ((!$s) || (in_array($s[0]['site_project'], ['', 'osada']))) {
$arr['comment_policy'] = 'authenticated';
} else {
if ($s && intval($s[0]['site_type']) === SITE_TYPE_ZOT) {
$arr['comment_policy'] = 'contacts';
} else {
$arr['comment_policy'] = 'authenticated';
}
}
}
@ -3020,9 +3020,11 @@ class Libzot
return EMPTY_STR;
}
$parsed = parse_url($observer['xchan_url']);
return $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') . '/rpost?f=';
if ($observer['xchan_network'] === 'zot6') {
$parsed = parse_url($observer['xchan_url']);
return $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') . '/rpost?f=';
}
return EMPTY_STR;
}
/**
@ -3587,7 +3589,7 @@ class Libzot
public static function is_zot_request()
{
$x = getBestSupportedMimeType(['application/x-zot+json', 'application/x-nomad']);
$x = getBestSupportedMimeType(['application/x-zot+json', 'application/x-nomad+json']);
return (($x) ? true : false);
}

View file

@ -297,7 +297,11 @@ class Libzotdir
$arr = [];
$arr['xprof_hash'] = $hash;
$arr['xprof_dob'] = ((isset($profile['birthday']) && $profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('', '', $profile['birthday'], 'Y-m-d')); // !!!! check this for 0000 year
if (isset($profile['birthday'])) {
$arr['xprof_dob'] = (($profile['birthday'] === '0000-00-00')
? $profile['birthday']
: datetime_convert('', '', $profile['birthday'], 'Y-m-d')); // !!!! check this for 0000 year
}
$arr['xprof_age'] = (isset($profile['age']) ? intval($profile['age']) : 0);
$arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT, 'UTF-8', false) : '');
$arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT, 'UTF-8', false) : '');

View file

@ -113,12 +113,15 @@ class ThreadItem
$conv = $this->get_conversation();
$observer = $conv->get_observer();
$lock = (((intval($item['item_private'])) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
? t('Private Message')
: false);
$lock = t('Public visibility');
if (intval($item['item_private']) === 2) {
$lock = t('Direct message (private mail)');
}
if (intval($item['item_private']) === 1) {
$lock = t('Restricted visibility');
}
$locktype = $item['item_private'];
$locktype = intval($item['item_private']);
$shareable = ((($conv->get_profile_owner() == local_channel() && local_channel()) && (! intval($item['item_private']))) ? true : false);

View file

@ -12,9 +12,13 @@ class Appman extends Controller
public function post()
{
if (!local_channel()) {
$channel_id = local_channel();
if (! $channel_id) {
return;
}
if (is_sys_channel($channel_id)) {
$channel_id = 0;
}
if ($_POST['url']) {
$arr = [
@ -36,9 +40,9 @@ class Appman extends Controller
'categories' => escape_tags($_REQUEST['categories'])
];
$_REQUEST['appid'] = Apps::app_install(local_channel(), $arr);
$_REQUEST['appid'] = Apps::app_install($channel_id, $arr);
if (Apps::app_installed(local_channel(), $arr)) {
if (Apps::app_installed($channel_id, $arr)) {
info(t('App installed.') . EOL);
}
@ -54,14 +58,14 @@ class Appman extends Controller
}
if ($_POST['install']) {
Apps::app_install(local_channel(), $papp);
if (Apps::app_installed(local_channel(), $papp)) {
Apps::app_install($channel_id, $papp);
if (Apps::app_installed($channel_id, $papp)) {
info(t('App installed.') . EOL);
}
}
if ($_POST['delete']) {
Apps::app_destroy(local_channel(), $papp);
Apps::app_destroy($channel_id, $papp);
}
if ($_POST['edit']) {
@ -69,11 +73,11 @@ class Appman extends Controller
}
if ($_POST['feature']) {
Apps::app_feature(local_channel(), $papp, $_POST['feature']);
Apps::app_feature($channel_id, $papp, $_POST['feature']);
}
if ($_POST['pin']) {
Apps::app_feature(local_channel(), $papp, $_POST['pin']);
Apps::app_feature($channel_id, $papp, $_POST['pin']);
}
if ($_SESSION['return_url']) {
@ -87,19 +91,25 @@ class Appman extends Controller
public function get()
{
if (!local_channel()) {
$channel_id = local_channel();
if (!$channel_id) {
notice(t('Permission denied.') . EOL);
return;
}
if (is_sys_channel($channel_id)) {
$channel_id = 0;
}
$channel = App::get_channel();
if (argc() > 3) {
if (argv(2) === 'moveup') {
Apps::moveup(local_channel(), argv(1), argv(3));
Apps::moveup($channel_id, argv(1), argv(3));
}
if (argv(2) === 'movedown') {
Apps::movedown(local_channel(), argv(1), argv(3));
Apps::movedown($channel_id, argv(1), argv(3));
}
goaway(z_root() . '/apporder');
}
@ -110,7 +120,7 @@ class Appman extends Controller
$r = q(
"select * from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($_REQUEST['appid']),
dbesc(local_channel())
dbesc($channel_id)
);
if ($r) {
$app = $r[0];
@ -119,7 +129,7 @@ class Appman extends Controller
"select * from term where otype = %d and oid = %d and uid = %d",
intval(TERM_OBJ_APP),
intval($r[0]['id']),
intval(local_channel())
intval($channel_id)
);
if ($term) {
$app['categories'] = array_elm_to_str($term, 'term');

View file

@ -30,7 +30,7 @@ class Apps extends Controller
Zlib\Apps::import_system_apps();
$syslist = [];
$cat = ((array_key_exists('cat', $_GET) && $_GET['cat']) ? [escape_tags($_GET['cat'])] : '');
$list = Zlib\Apps::app_list((($available) ? 0 : local_channel()), (($mode == 'edit') ? true : false), $cat);
$list = Zlib\Apps::app_list(($available || is_sys_channel(local_channel()) ? 0 : local_channel()), (($mode == 'edit') ? true : false), $cat);
if ($list) {
foreach ($list as $x) {
$syslist[] = Zlib\Apps::app_encode($x);
@ -48,7 +48,7 @@ class Apps extends Controller
foreach ($syslist as $app) {
$apps[] = Zlib\Apps::app_render($app, (($available) ? 'install' : $mode));
}
return replace_macros(get_markup_template('myapps.tpl'), array(
'$sitename' => get_config('system', 'sitename'),
'$cat' => $cat,

View file

@ -185,7 +185,7 @@ class Directory extends Controller
$directory_admin = false;
$url = z_root() . '/dirsearch';
if (is_site_admin()) {
if (is_sys_channel(local_channel())) {
$directory_admin = true;
}

View file

@ -13,7 +13,8 @@ use Zotlabs\Lib\Libprofile;
class Followers extends Controller
{
private $results = [];
public function init()
{
@ -30,10 +31,6 @@ class Followers extends Controller
http_status_exit(404, 'Not found');
}
// if (intval($channel['channel_system'])) {
// http_status_exit(403,'Permission denied');
// }
Libprofile::load(argv(1));
$observer_hash = get_observer_hash();
@ -69,11 +66,26 @@ class Followers extends Controller
dbesc($channel['channel_hash'])
);
$ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']);
$this->results = $r;
$ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']);
}
if (ActivityStreams::is_as_request()) {
as_return_and_die($ret, $channel);
}
}
function get() {
if ($this->results) {
foreach ($this->results as $member) {
$members[] = micropro($member, true, 'mpgroup', 'card');
}
}
$o = replace_macros(get_markup_template('listmembers.tpl'), [
'$title' => t('List members'),
'$members' => $members
]);
return $o;
}
}

View file

@ -13,6 +13,8 @@ use Zotlabs\Lib\Libprofile;
class Following extends Controller
{
private $results = [];
public function init()
{
@ -29,10 +31,6 @@ class Following extends Controller
http_status_exit(404, 'Not found');
}
// if (intval($channel['channel_system'])) {
// http_status_exit(403,'Permission denied');
// }
Libprofile::load(argv(1));
$observer_hash = get_observer_hash();
@ -69,6 +67,8 @@ class Following extends Controller
dbesc($channel['channel_hash'])
);
$this->results = $r;
$ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']);
}
@ -76,4 +76,19 @@ class Following extends Controller
as_return_and_die($ret, $channel);
}
}
function get() {
if ($this->results) {
foreach ($this->results as $member) {
$members[] = micropro($member, true, 'mpgroup', 'card');
}
}
$o = replace_macros(get_markup_template('listmembers.tpl'), [
'$title' => t('List members'),
'$members' => $members
]);
return $o;
}
}

View file

@ -1369,6 +1369,12 @@ class Item extends Controller
$datarray['obj']['id'] = $mid;
}
if ($private && !$parent) {
if ( intval($private) === 1 && (!$str_group_allow)) {
$private = 2;
}
}
$datarray['aid'] = $channel['channel_account_id'];
$datarray['uid'] = $profile_uid;
$datarray['uuid'] = $uuid;

View file

@ -158,57 +158,18 @@ class Lists extends Controller
$change = false;
logger('mod_lists: ' . App::$cmd, LOGGER_DEBUG);
if (argc() > 2 && argv(1) === 'view') {
$grp = argv(2);
if ($grp) {
$r = q(
"select * from pgrp where hash = '%s' and deleted = 0",
dbesc($grp)
);
if ($r) {
$uid = $r[0]['uid'];
if (local_channel() && local_channel() == $uid) {
goaway(z_root() . '/lists/' . $r[0]['id']);
}
if (!($r[0]['visible'] && perm_is_allowed($uid, get_observer_hash(), 'view_contacts'))) {
notice(t('Permission denied') . EOL);
return;
}
$members = [];
$memberlist = AccessList::members($uid, $r[0]['id']);
if ($memberlist) {
foreach ($memberlist as $member) {
$members[] = micropro($member, true, 'mpgroup', 'card');
}
}
$o = replace_macros(get_markup_template('listmembers.tpl'), [
'$title' => t('List members'),
'$members' => $members
]);
return $o;
} else {
notice(t('List not found') . EOL);
return;
}
}
}
if (!local_channel()) {
notice(t('Permission denied') . EOL);
return;
}
// logger('mod_lists: ' . App::$cmd, LOGGER_DEBUG);
// Switch to text mode interface if we have more than 'n' contacts or group members, else loading avatars will lead to poor interactivity
$switchtotext = get_pconfig(local_channel(), 'system', 'listedit_image_limit', get_config('system', 'listedit_image_limit', 1000));
if ((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) {
if (!local_channel()) {
notice(t('Permission denied') . EOL);
return;
}
$new = (((argc() == 2) && (argv(1) === 'new')) ? true : false);
$groups = q(
@ -250,7 +211,13 @@ class Lists extends Controller
$tpl = get_markup_template('group_edit.tpl');
if ((argc() == 3) && (argv(1) === 'drop')) {
check_form_security_token_redirectOnErr('/lists', 'group_drop', 't');
if (!local_channel()) {
notice(t('Permission denied') . EOL);
return;
}
check_form_security_token_redirectOnErr('/lists', 'group_drop', 't');
if (intval(argv(2))) {
$r = q(
@ -273,6 +240,11 @@ class Lists extends Controller
if ((argc() > 2) && intval(argv(1)) && argv(2)) {
if (!local_channel()) {
notice(t('Permission denied') . EOL);
return;
}
check_form_security_token_ForbiddenOnErr('group_member_change', 't');
$r = q(
@ -290,31 +262,45 @@ class Lists extends Controller
if (strlen(argv(1)) <= 11 && intval(argv(1))) {
$r = q(
"SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1",
intval(argv(1)),
intval(local_channel())
"SELECT * FROM pgrp WHERE id = %d AND deleted = 0 LIMIT 1",
intval(argv(1))
);
} else {
$r = q(
"SELECT * FROM pgrp WHERE hash = '%s' AND uid = %d AND deleted = 0 LIMIT 1",
dbesc(argv(1)),
intval(local_channel())
"SELECT * FROM pgrp WHERE hash = '%s' AND deleted = 0 LIMIT 1",
dbesc(argv(1))
);
}
if (!$r) {
$r = q(
"SELECT * FROM pgrp WHERE id = %d AND deleted = 0 LIMIT 1",
intval(argv(1)),
);
if ($r) {
notice(t('Permission denied.') . EOL);
} else {
notice(t('Access list not found.') . EOL);
if (! $r) {
notice(t('Access list not found.') . EOL);
return;
}
$group = array_shift($r);
$uid = $group['uid'];
$owner = (local_channel() && intval(local_channel()) === intval($group['uid']));
if (!$owner) {
// public view of group members if permitted
if (!($group['visible'] && perm_is_allowed($uid, get_observer_hash(), 'view_contacts'))) {
notice(t('Permission denied') . EOL);
return;
}
goaway(z_root() . '/connections');
}
$group = $r[0];
$members = [];
$memberlist = AccessList::members($uid, $group['id']);
if ($memberlist) {
foreach ($memberlist as $member) {
$members[] = micropro($member, true, 'mpgroup', 'card');
}
}
$o = replace_macros(get_markup_template('listmembers.tpl'), [
'$title' => t('List members'),
'$members' => $members
]);
return $o;
}
$members = AccessList::members(local_channel(), $group['id']);

View file

@ -98,11 +98,13 @@ class Lockview extends Controller
$l = array_merge($l, $recips['cc']);
}
for ($x = 0; $x < count($l); $x++) {
if ($l[$x] !== ACTIVITY_PUBLIC_INBOX) {
if ($l[$x] === ACTIVITY_PUBLIC_INBOX) {
$l[$x] = '<strong><em>' . t('Everybody') . '</em></strong>';
} else {
$l[$x] = '<a href="' . $l[$x] . '">' . $l[$x] . '</a>';
}
}
echo $o . implode(', ', $l);
echo $o . implode('<br>', $l);
killme();
}
}

View file

@ -349,7 +349,7 @@ class Ping extends Controller
"SELECT * FROM item
WHERE uid = %d
AND author_xchan != '%s'
AND changed > '%s'
AND edited > '%s'
$seenstr
$item_normal_moderate
$sql_extra
@ -386,7 +386,7 @@ class Ping extends Controller
"SELECT * FROM item
WHERE uid = %d
AND author_xchan != '%s'
AND changed > '%s'
AND edited > '%s'
$seenstr
$item_normal_moderate
$sql_extra
@ -600,7 +600,7 @@ class Ping extends Controller
$loadtime = get_loadtime('stream');
$r = q(
"SELECT id, author_xchan FROM item
WHERE uid = %d and changed > '%s'
WHERE uid = %d and edited > '%s'
$seenstr
$item_normal
$sql_extra ",
@ -629,7 +629,7 @@ class Ping extends Controller
$loadtime = get_loadtime('channel');
$r = q(
"SELECT id, author_xchan FROM item
WHERE item_wall = 1 and uid = %d and changed > '%s'
WHERE item_wall = 1 and uid = %d and edited > '%s'
$seenstr
$item_normal
$sql_extra ",

View file

@ -42,10 +42,6 @@ class Rpost extends Controller
if (!local_channel()) {
if (remote_channel()) {
// redirect to your own site.
// We can only do this with a GET request so you'll need to keep the text short or risk getting truncated
// by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin
// blocks them.
$url = Libzot::get_rpost_path(App::get_observer());
// make sure we're not looping to our own hub
if (($url) && (!stristr($url, App::get_hostname()))) {
@ -198,6 +194,15 @@ class Rpost extends Controller
'allow_gid' => EMPTY_STR,
'deny_cid' => EMPTY_STR,
'deny_gid' => EMPTY_STR]);
if (! (isset($_REQUEST['body']) && $_REQUEST['body'])) {
$xchan = q("select * from xchan where xchan_hash = '%s'",
dbesc($_REQUEST['to'])
);
if ($xchan) {
$_REQUEST['body'] .= '@!{' . (($xchan[0]['xchan_addr']) ? $xchan[0]['xchan_addr'] : $xchan[0]['xchan_url']) . '} ' ;
}
}
}
$channel_acl = $acl->get();

View file

@ -724,7 +724,7 @@ class Channel
'$desktop_notifications_request' => t('Grant permission'),
'$mailhost' => ['mailhost', t('Email notifications sent from (hostname)'), get_pconfig(local_channel(), 'system', 'email_notify_host', App::get_hostname()), sprintf(t('If your channel is mirrored to multiple locations, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'), App::get_hostname())],
'$always_show_in_notices' => array('always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no),
'$permit_all_mentions' => ['permit_all_mentions', t('Accept messages from strangers which mention me'), get_pconfig(local_channel(), 'system', 'permit_all_mentions'), t('This setting bypasses normal permissions'), $yes_no],
'$permit_all_mentions' => ['permit_all_mentions', t('Accept messages from strangers which mention you'), get_pconfig(local_channel(), 'system', 'permit_all_mentions'), t('This setting bypasses normal permissions'), $yes_no],
'$followed_tags' => ['followed_tags', t('Accept messages from strangers which include any of the following hashtags'), $followed, t('comma separated, do not include the #')],
'$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')),
'$basic_addon' => $plugin['basic'],

View file

@ -27,7 +27,7 @@ class Tasks extends Controller
$x['html'] = '';
if (isset($x['tasks']) && is_array($x['tasks'])) {
foreach ($x['tasks'] as $y) {
$x['html'] .= '<div class="tasklist-item"><input type="checkbox" onchange="taskComplete(' . $y['id'] . ') return false;" /> ' . $y['summary'] . '</div>';
$x['html'] .= '<div class="tasklist-item"><input type="checkbox" onchange="taskComplete(' . $y['id'] . '); return false;" /> ' . $y['summary'] . '</div>';
}
}
json_return_and_die($x);

View file

@ -891,11 +891,11 @@ class App {
// normally self::$hostname (also scheme and port) will be filled in during startup.
// Set it manually from $_SERVER variables only if it wasn't.
if (! self::$hostname) {
self::$hostname = punify(get_host());
self::$scheme = 'http';
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) {
self::$scheme = 'https';
}
@ -920,7 +920,7 @@ class App {
// Rewrite rules on the server will convert incoming paths to a request parameter.
// Strip this path information from our stored copy of the query_string, in case
// we need to re-use the rest of the original query.
if (isset($_SERVER['QUERY_STRING']) && substr($_SERVER['QUERY_STRING'], 0, 4) === "req=") {
self::$query_string = str_replace(['<','>'],['&lt;','&gt;'],substr($_SERVER['QUERY_STRING'], 4));
// removing leading '/' - maybe a nginx problem
@ -934,7 +934,7 @@ class App {
// Here is where start breaking out the URL path information to both route the
// web request based on the leading path component, and also to use remaining
// path components as C-style arguments to our individual controller modules.
if (isset($_GET['req'])) {
self::$cmd = escape_tags(trim($_GET['req'],'/\\'));
}
@ -1416,8 +1416,9 @@ function z_root() {
* @return string
*/
function absurl($path) {
if (strpos($path, '/') === 0)
if (strpos($path, '/') === 0) {
return z_path() . $path;
}
return $path;
}
@ -2069,7 +2070,7 @@ function load_contact_links($uid) {
// logger('load_contact_links');
$r = q("SELECT abook_id, abook_flags, abook_self, abook_incl, abook_excl, abook_my_perms, abook_their_perms, xchan_hash, xchan_photo_m, xchan_name, xchan_url, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d ",
$r = q("SELECT abook_id, abook_flags, abook_self, abook_incl, abook_excl, abook_my_perms, abook_their_perms, xchan_hash, xchan_photo_m, xchan_name, xchan_url, xchan_addr, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d ",
intval($uid)
);
if($r) {

View file

@ -123,7 +123,7 @@ Let's go ahead and add some code to implement our post_local hook handler.
$cities = [];
$zones = timezone_identifiers_list();
foreach ($zones as $zone) {
if ((strpos($zone,'/')) &amp;&amp; (! stristr($zone,'US/')) &amp;&amp; (! stristr($zone,'Etc/'))) {
if ((strpos($zone,'/')) &amp;&amp; (stristr($zone,'US/') === false) &amp;&amp; (stristr($zone,'Etc/') === false)) {
$cities[] = str_replace('_', ' ',substr($zone,strrpos($zone,'/') + 1));
}
}

View file

@ -163,12 +163,36 @@ function vcard_from_xchan($xchan, $observer = null, $mode = '')
: $xchan['xchan_url']
);
$profdm = EMPTY_STR;
$profdm_url = EMPTY_STR;
if (local_channel()) {
$can_dm = their_perms_contains(local_channel(),$xchan['xchan_hash'],'post_mail') && $xchan['xchan_type'] !== XCHAN_TYPE_GROUP;
if ($can_dm) {
$profdm = t('Direct Message');
$profdm_url = z_root() . '/rpost?f='
. '&to='
. urlencode($xchan['xchan_hash'])
. '&body='
. urlencode('@!{' . $xchan['xchan_addr'] ? $xchan['xchan_addr'] : $xchan['xchan_url'] . '}');
}
}
return replace_macros(get_markup_template('xchan_vcard.tpl'), [
'$name' => $xchan['xchan_name'],
'$photo' => ((is_array(App::$profile) && array_key_exists('photo', App::$profile)) ? App::$profile['photo'] : $xchan['xchan_photo_l']),
'$follow' => urlencode(($xchan['xchan_addr']) ? $xchan['xchan_addr'] : $xchan['xchan_url']),
'$link' => zid($xchan['xchan_url']),
'$connect' => $connect,
'$profdm' => $profdm,
'$profdm_url' => $profdm_url,
'$newwin' => (($mode === 'chanview') ? t('New window') : EMPTY_STR),
'$newtit' => t('Open the selected location in a different window or browser tab'),
'$url' => $url,
@ -1007,6 +1031,6 @@ function micropro($contact, $redirect = false, $class = '', $mode = false)
'$name' => $contact['xchan_name'],
'$addr' => $contact['xchan_addr'],
'$title' => $contact['xchan_name'] . ' [' . $contact['xchan_addr'] . ']',
'$network' => sprintf(t('Network: %s'), $contact['xchan_network'])
'$network' => sprintf(t('Network: %s'), network_to_name($contact['xchan_network']))
));
}

View file

@ -605,10 +605,15 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
'isstarred' => ((intval($item['item_starred'])) ? true : false),
);
$lock = (($item['item_private'] || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']))
? t('Private Message')
: false
);
$lock = t('Public visibility');
if (intval($item['item_private']) === 2) {
$lock = t('Direct message (private mail)');
}
if (intval($item['item_private']) === 1) {
$lock = t('Restricted visibility');
}
$locktype = intval($item['item_private']);
$likebuttons = false;
$shareable = false;
@ -656,6 +661,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
'name' => $profile_name,
'sparkle' => $sparkle,
'lock' => $lock,
'locktype' => $locktype,
'thumb' => $profile_avatar,
'title' => $item['title'],
'body' => $body['html'],
@ -931,13 +937,15 @@ function thread_author_menu($item, $mode = '')
$can_dm = false;
if ($local_channel && $contact) {
$can_dm = perm_is_allowed($local_channel, $item['author_xchan'], 'send_stream');
$can_dm = perm_is_allowed($local_channel, $item['author_xchan'], 'post_mail') && intval($contact['xchan_type']) !== XCHAN_TYPE_GROUP ;
} elseif ($item['author']['xchan_network'] === 'activitypub') {
$can_dm = true;
}
// if ($can_dm) {
// $pm_url = z_root() . '/rpost?to=' . urlencode($item['author_xchan']);
// }
if ($can_dm) {
$pm_url = z_root()
. '/rpost?to='
. urlencode($item['author_xchan']);
}
if ($profile_link) {
$menu[] = [

View file

@ -2996,7 +2996,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
}
// is the link already in str_tags?
if (! stristr($str_tags, $newtag)) {
if (is_string($newtag) && ! stristr($str_tags, $newtag)) {
// append or set str_tags
if (strlen($str_tags)) {
$str_tags .= ',';

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,2 @@
<?php
define ( 'STD_VERSION', '21.12.04' );
define ( 'STD_VERSION', '22.01.02' );

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -454,7 +454,7 @@ footer {
margin-bottom: 0px;
}
.connect-btn-wrapper {
.connect-btn-wrapper, .profdm-btn-wrapper {
margin-bottom: 10px;
}
@ -908,6 +908,12 @@ div.jGrowl div.jGrowl-notification {
}
.dimmer {
opacity: 0.5;
filter:alpha(opacity=50);
}
.profile-match-connect { margin-top: 5px; }
.reshared-content { margin-left: 20px; }
@ -1517,6 +1523,7 @@ blockquote {
.wall-item-lock .dropdown-menu {
min-width: 20rem;
padding: 5px;
}

View file

@ -56,12 +56,10 @@
{{/if}}
</div>
</div>
{{if $item.lock}}
<div class="wall-item-lock dropdown">
<i class="fa {{if $item.locktype == 2}}fa-envelope{{else}}fa-lock{{/if}} lockview{{if $item.privacy_warning}} text-warning{{/if}}" data-toggle="dropdown" title="{{$item.lock}}" onclick="lockview('item',{{$item.id}});" ></i>&nbsp;
<i class="fa {{if $item.locktype == 2}}fa-envelope{{elseif $item.locktype == 1}}fa-lock dimmer{{else}}fa-globe dimmer{{/if}} lockview{{if $item.privacy_warning}} text-warning{{/if}}" data-toggle="dropdown" title="{{$item.lock}}" onclick="lockview('item',{{$item.id}});" ></i>&nbsp;
<div id="panel-{{$item.id}}" class="dropdown-menu"></div>
</div>
{{/if}}
<div class="wall-item-author">
{{if $item.previewing}}<span class="preview-indicator"><i class="fa fa-eye" title="{{$item.preview_lbl}}"></i></span>&nbsp;{{/if}}
<a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link u-url"><span class="wall-item-name{{$item.sparkle}}" id="wall-item-name-{{$item.id}}" >{{$item.name}}</span></a>{{if $item.owner_url}}&nbsp;{{$item.via}}&nbsp;<a href="{{$item.owner_url}}" title="{{$item.olinktitle}}" class="wall-item-name-link"><span class="wall-item-name{{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span></a>{{/if}}

View file

@ -5,6 +5,9 @@
{{if $connect}}
<div class="connect-btn-wrapper"><a href="{{$connect_url}}" class="btn btn-block btn-success btn-sm"><i class="fa fa-plus"></i> {{$connect}}</a></div>
{{/if}}
{{if $profdm}}
<div class="profdm-btn-wrapper"><a href="{{$profdm_url}}" class="btn btn-block btn-success btn-sm"><i class="fa fa-envelope"></i> {{$profdm}}</a></div>
{{/if}}
{{if ! $zcard}}
{{if $editmenu.multi}}
<div class="dropdown float-right">

View file

@ -37,11 +37,10 @@
{{/if}}
</div>
</div>
{{if $item.lock}}
<div class="wall-item-lock dropdown">
<i class="fa fa-lock lockview" data-toggle="dropdown" title="{{$item.lock}}" onclick="lockview('item',{{$item.id}});" ></i><ul id="panel-{{$item.id}}" class="lockview-panel dropdown-menu"></ul>&nbsp;
<i class="fa {{if $item.locktype == 2}}fa-envelope{{elseif $item.locktype == 1}}fa-lock dimmer{{else}}fa-globe dimmer{{/if}} lockview{{if $item.privacy_warning}} text-warning{{/if}}" data-toggle="dropdown" title="{{$item.lock}}" onclick="lockview('item',{{$item.id}});" ></i>&nbsp;
<div id="panel-{{$item.id}}" class="dropdown-menu"></div>
</div>
{{/if}}
<div class="wall-item-author">
{{if $item.previewing}}<span class="preview-indicator"><i class="fa fa-eye" title="{{$item.preview_lbl}}"></i></span>&nbsp;{{/if}}
<a href="{{$item.profile_url}}" title="{{$item.linktitle}}" class="wall-item-name-link"><span class="wall-item-name{{$item.sparkle}}" id="wall-item-name-{{$item.id}}" >{{$item.name}}</span></a>{{if $item.owner_url}}&nbsp;{{$item.via}}&nbsp;<a href="{{$item.owner_url}}" title="{{$item.olinktitle}}" class="wall-item-name-link"><span class="wall-item-name{{$item.osparkle}}" id="wall-item-ownername-{{$item.id}}">{{$item.owner_name}}</span></a>{{/if}}

View file

@ -3,6 +3,10 @@
{{if $connect}}
<div class="connect-btn-wrapper"><a href="follow?f=&url={{$follow}}" rel="nofollow noopener" class="btn btn-block btn-success btn-sm"><i class="fa fa-plus"></i> {{$connect}}</a></div>
{{/if}}
{{if $profdm}}
<div class="profdm-btn-wrapper"><a href="{{$profdm_url}}" class="btn btn-block btn-success btn-sm"><i class="fa fa-envelope"></i> {{$profdm}}</a></div>
{{/if}}
<div class="fn p-name">{{$name}}</div>
</div>