Merge branch 'master' of ../z

This commit is contained in:
zotlabs 2019-10-04 16:31:41 -07:00
commit d7a0456bdc
2100 changed files with 222428 additions and 290655 deletions

View file

View file

@ -1,11 +1,34 @@
ZAP
===
Zap is a decentralised social network server application with a number of powerful features, yet very easy to use.
Zap is an open source decentralised social network with more privacy and less drama.
=====
Installation
============
The Zot Manifesto
You have the right to a permanent internet identity which is not associated with what server you are currently using and cannot be taken away from you by anybody, ever.
You have the right to refuse/reject or possibly moderate comments on your posts by anybody you don't know.
You also have the right to not allow them to comment on your posts in the first place, until such time as they have earned your trust.
You have the right to show your photos and videos to anybody you desire and also NOT show them to anybody you desire.
If your software does not implement these rights, you have the right to fix it or replace it.
=====
The Earth Manifesto
The earth is your mother. She gave you life. Respect her or she will take it away.
Silence is complicity. Speak.
Those who are leading us to destruction can be stopped.
7.5 billion people cannot be stopped.
=====
Read `install/INSTALL.txt` for installation instructions.

View file

@ -17,7 +17,7 @@ class PermissionRoles {
* @return number
*/
static public function version() {
return 2;
return 3;
}
static function role_perms($role) {
@ -34,7 +34,7 @@ class PermissionRoles {
$ret['online'] = true;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'send_stream', 'post_wall', 'post_comments'
'view_pages', 'send_stream', 'post_wall', 'post_comments', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
@ -43,13 +43,13 @@ class PermissionRoles {
$ret['perms_auto'] = false;
$ret['default_collection'] = true;
$ret['directory_publish'] = true;
$ret['online'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'send_stream', 'post_wall', 'post_comments'
'view_stream', 'view_profile', 'view_storage',
'view_pages', 'send_stream', 'post_wall', 'post_comments', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
break;
case 'forum':
@ -58,10 +58,11 @@ class PermissionRoles {
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'post_wall', 'post_comments'
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage',
'view_pages', 'post_wall', 'post_comments', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'group';
break;
@ -73,9 +74,10 @@ class PermissionRoles {
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'post_wall', 'post_comments', 'moderated'
'view_pages', 'post_wall', 'post_comments', 'post_like', 'moderated'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'group';
break;
@ -85,10 +87,12 @@ class PermissionRoles {
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'post_wall', 'post_comments'
'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage',
'view_pages', 'post_wall', 'post_comments', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
$ret['channel_type'] = 'group';
break;
case 'collection':
@ -98,9 +102,10 @@ class PermissionRoles {
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'post_comments'
'view_pages', 'post_comments', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['channel_type'] = 'collection';
break;
@ -110,10 +115,12 @@ class PermissionRoles {
$ret['directory_publish'] = true;
$ret['online'] = false;
$ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'post_comments'
'view_stream', 'view_profile', 'view_storage',
'view_pages', 'post_comments', 'post_like'
];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
$ret['channel_type'] = 'collection';
break;
case 'feed':
@ -130,6 +137,10 @@ class PermissionRoles {
break;
case 'repository':
//Legacy settings to cover all channel_types previously in Libzot.php
$ret['channel_type'] = 'group';
default:
break;
}
@ -188,4 +199,4 @@ class PermissionRoles {
return $roles;
}
}
}

View file

@ -41,7 +41,7 @@ class Permissions {
* @return number
*/
static public function version() {
return 2;
return 3;
}
/**
@ -53,18 +53,18 @@ class Permissions {
static public function Perms($filter = '') {
$perms = [
'view_stream' => t('Can view my channel stream and posts'),
'send_stream' => t('Can send me their channel stream and posts'),
'view_profile' => t('Can view my default channel profile'),
'view_contacts' => t('Can view my connections'),
'view_storage' => t('Can view my file storage and photos'),
'write_storage' => t('Can upload/modify my file storage and photos'),
'post_wall' => t('Can post on my channel (wall) page'),
'post_comments' => t('Can comment on or like my posts'),
'post_like' => t('Can like/dislike profiles and profile things'),
'republish' => t('Can source my public posts in derived channels'),
'moderated' => t('Comments are moderated'),
'delegate' => t('Can administer my channel')
'view_stream' => t('Grant viewing access to and delivery of your channel stream and posts'),
'view_profile' => t('Grant viewing access to your default channel profile'),
'view_contacts' => t('Grant viewing access to your address book (connections)'),
'view_storage' => t('Grant viewing access to your file storage and photos'),
'post_wall' => t('Grant permission to post on your channel (wall) page'),
'send_stream' => t('Accept delivery of their posts and comments to their posts'),
'post_comments' => t('Accept delivery of their comments and likes on your posts'),
'post_like' => t('Accept delivery of their likes of your profile'),
'write_storage' => t('Grant upload permissions to your file storage and photos'),
'republish' => t('Grant permission to republish/mirror your posts'),
'moderated' => t('Accept comments and wall posts only after approval (moderation)'),
'delegate' => t('Grant channel administration (delegation) permission')
];
$x = [
@ -279,4 +279,4 @@ class Permissions {
return implode(',',$n);
}
}
}

View file

@ -193,7 +193,7 @@ class Cron {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
killme();
return;
}
reload_plugins();

View file

@ -13,7 +13,7 @@ class CurlAuth {
static public function run($argc,$argv) {
if($argc != 2)
killme();
return;
\App::$session->start();
@ -50,6 +50,6 @@ class CurlAuth {
file_put_contents($c,$x);
killme();
return;
}
}
}

View file

@ -13,11 +13,11 @@ class Delxitems {
cli_startup();
if($argc != 3) {
killme();
return;
}
remove_abook_items($argv[1],$argv[2]);
killme();
return;
}
}

View file

@ -27,11 +27,6 @@ class Expire {
db_utcnow(), db_quoteinterval('36 DAY')
);
/** @FIXME make this optional as it could have a performance impact on large sites */
if (intval(get_config('system', 'optimize_items')))
q("optimize table item");
logger('expire: start', LOGGER_DEBUG);
$site_expire = intval(get_config('system', 'default_expire_days'));
@ -51,15 +46,18 @@ class Expire {
// service class default (if non-zero) over-rides the site default
$service_class_expire = service_class_fetch($rr['channel_id'], 'expire_days');
if (intval($service_class_expire))
if (intval($service_class_expire)) {
$channel_expire = $service_class_expire;
else
}
else {
$channel_expire = $site_expire;
}
if (intval($channel_expire) && (intval($channel_expire) < intval($rr['channel_expire_days'])) ||
intval($rr['channel_expire_days'] == 0)) {
$expire_days = $channel_expire;
} else {
}
else {
$expire_days = $rr['channel_expire_days'];
}
@ -75,9 +73,7 @@ class Expire {
// this should probably just fetch the channel_expire_days from the sys channel,
// but there's no convenient way to set it.
$expire_days = get_config('system', 'sys_expire_days');
if ($expire_days === false)
$expire_days = 30;
$expire_days = get_config('system', 'sys_expire_days',30);
if (intval($site_expire) && (intval($site_expire) < intval($expire_days))) {
$expire_days = $site_expire;
@ -85,9 +81,10 @@ class Expire {
logger('Expire: sys interval: ' . $expire_days, LOGGER_DEBUG);
if ($expire_days)
if ($expire_days) {
item_expire($x['channel_id'], $expire_days, $commented_days);
}
logger('Expire: sys: done', LOGGER_DEBUG);
}
}

View file

@ -1,30 +1,28 @@
<?php /** @file */
<?php
namespace Zotlabs\Daemon;
use Zotlabs\Lib\Libzot;
require_once('include/channel.php');
class Externals {
static public function run($argc,$argv){
static public function run($argc, $argv){
$total = 0;
$attempts = 0;
$sys = get_sys_channel();
logger('externals: startup', LOGGER_DEBUG);
// pull in some public posts
while($total == 0 && $attempts < 3) {
$arr = array('url' => '');
while ($total == 0 && $attempts < 3) {
$arr = [ 'url' => EMPTY_STR ];
call_hooks('externals_url_select',$arr);
if($arr['url']) {
if ($arr['url']) {
$url = $arr['url'];
}
else {
@ -37,13 +35,14 @@ class Externals {
intval(DIRECTORY_MODE_STANDALONE),
intval(SITE_TYPE_ZOT)
);
if($r)
if ($r) {
$url = $r[0]['site_url'];
}
}
$blacklisted = false;
if(! check_siteallowed($url)) {
if (! check_siteallowed($url)) {
logger('blacklisted site: ' . $url);
$blacklisted = true;
}
@ -52,20 +51,20 @@ class Externals {
// make sure we can eventually break out if somebody blacklists all known sites
if($blacklisted) {
if($attempts > 20)
if ($blacklisted) {
if ($attempts > 20) {
break;
}
$attempts --;
continue;
}
if($url) {
if($r[0]['site_pull'] > NULL_DATE)
if ($url) {
if ($r[0]['site_pull'] > NULL_DATE) {
$mindate = urlencode(datetime_convert('','',$r[0]['site_pull'] . ' - 1 day'));
}
else {
$days = get_config('externals','since_days');
if($days === false)
$days = 15;
$days = get_config('externals','since_days',15);
$mindate = urlencode(datetime_convert('','','now - ' . intval($days) . ' days'));
}
@ -74,7 +73,7 @@ class Externals {
logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG);
$x = z_fetch_url($feedurl);
if(($x) && ($x['success'])) {
if (($x) && ($x['success'])) {
q("update site set site_pull = '%s' where site_url = '%s'",
dbesc(datetime_convert()),
@ -83,10 +82,9 @@ class Externals {
$j = json_decode($x['body'],true);
if($j['success'] && $j['messages']) {
$sys = get_sys_channel();
foreach($j['messages'] as $message) {
// on these posts, clear any route info.
$message['route'] = '';
$message['route'] = EMPTY_STR;
$results = Libzot::process_delivery('undefined', null, get_item_elements($message), [ $sys['xchan_hash'] ], false, true);
$total ++;
}

View file

@ -10,7 +10,7 @@ if(array_search( __file__ , get_included_files()) === 0) {
if($argc)
Master::Release($argc,$argv);
killme();
return;
}

View file

@ -87,58 +87,42 @@ class Notifier {
static public $channel = null;
static public $private = false;
static public function run($argc,$argv){
static public function run($argc,$argv) {
if($argc < 3)
if ($argc < 3) {
return;
}
logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG);
logger('notifier: invoked: ' . print_r($argv,true), LOGGER_DEBUG, LOG_INFO);
$cmd = $argv[1];
$item_id = $argv[2];
if(! $item_id)
if (! $item_id) {
return;
}
self::$deliveries = [];
self::$recipients = [];
self::$env_recips = [];
self::$packet_type = 'activity';
self::$encoding = 'activitystreams';
self::$encoded_item = null;
self::$channel = null;
self::$private = false;
$sys = get_sys_channel();
$mail = false;
$top_level = false;
$url_recipients = array();
$normal_mode = true;
if($cmd === 'mail' || $cmd === 'single_mail') {
$normal_mode = false;
$mail = true;
self::$private = true;
$message = q("SELECT * FROM mail WHERE id = %d LIMIT 1",
intval($item_id)
);
if(! $message) {
return;
}
xchan_mail_query($message[0]);
self::$recipients[] = $message[0]['to_xchan'];
$item = $message[0];
self::$encoded_item = encode_mail($item);
$s = q("select * from channel where channel_id = %d limit 1",
intval($item['channel_id'])
);
if($s)
self::$channel = $s[0];
self::$packet_type = 'mail';
self::$encoding = 'zot';
}
elseif($cmd === 'request') {
if ($cmd === 'request') {
$xchan = $argv[3];
if($argc < 5) {
if ($argc < 5) {
return;
}
@ -151,13 +135,13 @@ class Notifier {
self::$encoding = 'zot';
$normal_mode = false;
}
elseif($cmd === 'keychange') {
elseif ($cmd === 'keychange') {
self::$channel = channelx_by_n($item_id);
$r = q("select abook_xchan from abook where abook_channel = %d",
intval($item_id)
);
if($r) {
foreach($r as $rr) {
if ($r) {
foreach ($r as $rr) {
self::$recipients[] = $rr['abook_xchan'];
}
}
@ -167,7 +151,7 @@ class Notifier {
self::$encoding = 'zot';
$normal_mode = false;
}
elseif(in_array($cmd, [ 'permissions_update', 'permissions_reject', 'permissions_accept', 'permissions_create' ])) {
elseif (in_array($cmd, [ 'permissions_update', 'permissions_reject', 'permissions_accept', 'permissions_create' ])) {
// Get the (single) recipient
@ -175,62 +159,62 @@ class Notifier {
intval($item_id)
);
if($r) {
$uid = $r[0]['abook_channel'];
if ($r) {
$recip = array_shift($r);
$uid = $recip['abook_channel'];
// Get the sender
self::$channel = channelx_by_n($uid);
if(self::$channel) {
if (self::$channel) {
$perm_update = array('sender' => self::$channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
$perm_update = [ 'sender' => self::$channel, 'recipient' => $recip, 'success' => false, 'deliveries' => '' ];
switch($cmd) {
switch ($cmd) {
case 'permissions_create':
ActivityPub::permissions_create($perm_update);
break;
case 'permissions_accept':
ActivityPub::permissions_accept($perm_update);
break;
default:
break;
}
if(! $perm_update['success']) {
if (! $perm_update['success']) {
call_hooks($cmd,$perm_update);
}
if($perm_update['success']) {
if($perm_update['deliveries']) {
if ($perm_update['success']) {
if ($perm_update['deliveries']) {
self::$deliveries[] = $perm_update['deliveries'];
do_delivery(self::$deliveries);
}
return;
}
else {
self::$recipients[] = $r[0]['abook_xchan'];
self::$recipients[] = $recip['abook_xchan'];
self::$private = false;
self::$packet_type = 'refresh';
self::$env_recips = [ $r[0]['xchan_hash'] ];
self::$env_recips = [ $$recip['xchan_hash'] ];
}
}
}
}
elseif($cmd === 'refresh_all') {
elseif ($cmd === 'refresh_all') {
logger('notifier: refresh_all: ' . $item_id);
self::$channel = channelx_by_n($item_id);
$r = q("select abook_xchan from abook where abook_channel = %d",
intval($item_id)
);
if($r) {
foreach($r as $rr) {
if ($r) {
foreach ($r as $rr) {
self::$recipients[] = $rr['abook_xchan'];
}
}
self::$private = false;
self::$packet_type = 'refresh';
}
elseif($cmd === 'purge') {
$xchan = argv(3);
elseif ($cmd === 'purge') {
$xchan = $argv[3];
logger('notifier: purge: ' . $item_id . ' => ' . $xchan);
if (! $xchan) {
return;
@ -241,19 +225,21 @@ class Notifier {
self::$private = true;
self::$packet_type = 'purge';
}
elseif($cmd === 'purge_all') {
elseif ($cmd === 'purge_all') {
logger('notifier: purge_all: ' . $item_id);
self::$channel = channelx_by_n($item_id);
self::$recipients = array();
self::$recipients = [];
$r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0",
intval($item_id)
);
if($r) {
foreach($r as $rr) {
self::$recipients[] = $rr['abook_xchan'];
}
if (! $r) {
return;
}
foreach ($r as $rr) {
self::$recipients[] = $rr['abook_xchan'];
}
self::$private = false;
self::$packet_type = 'purge';
}
@ -267,57 +253,65 @@ class Notifier {
intval($item_id)
);
if(! $r)
if (! $r) {
return;
}
xchan_query($r);
$r = fetch_post_tags($r);
$target_item = $r[0];
$target_item = array_shift($r);
$deleted_item = false;
if(intval($target_item['item_deleted'])) {
if (intval($target_item['item_deleted'])) {
logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
$deleted_item = true;
}
if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST, ITEM_TYPE_MAIL ] )) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
if (! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST, ITEM_TYPE_MAIL ] )) {
if (intval($target_item['item_type'] == ITEM_TYPE_CUSTOM)) {
$hookinfo=[
'targetitem'=>$target_item,
'deliver'=>false
];
call_hooks('customitem_deliver',$hookinfo);
}
if (!$hookinfo['deliver']) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
}
}
// Check for non published items, but allow an exclusion for transmitting hidden file activities
if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
if (intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
intval($target_item['item_blocked']) ||
( intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) {
logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
return;
}
if(strpos($target_item['postopts'],'nodeliver') !== false) {
logger('notifier: target item is undeliverable', LOGGER_DEBUG);
return;
}
$s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
intval($target_item['uid'])
);
if($s)
self::$channel = $s[0];
if ($s) {
self::$channel = array_shift($s);
}
if(self::$channel['channel_hash'] !== $target_item['author_xchan'] && self::$channel['channel_hash'] !== $target_item['owner_xchan']) {
if (self::$channel['channel_hash'] !== $target_item['author_xchan'] && self::$channel['channel_hash'] !== $target_item['owner_xchan']) {
logger("notifier: Sending channel is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}", LOGGER_NORMAL, LOG_WARNING);
return;
}
$thread_is_public = false;
if($target_item['mid'] === $target_item['parent_mid']) {
if ($target_item['mid'] === $target_item['parent_mid']) {
$parent_item = $target_item;
$top_level_post = true;
}
else {
@ -326,26 +320,28 @@ class Notifier {
intval($target_item['parent'])
);
if(! $r)
if (! $r) {
return;
}
xchan_query($r);
$r = fetch_post_tags($r);
$parent_item = $r[0];
$parent_item = array_shift($r);
$top_level_post = false;
$thread_is_public = 1 - intval($parent_item['item_private']) ;
}
// avoid looping of discover items 12/4/2014
if($sys && $parent_item['uid'] == $sys['channel_id'])
if ($sys && $parent_item['uid'] == $sys['channel_id']) {
return;
}
$m = get_iconfig($target_item,'activitypub','signed_data');
if($m)
if ($m) {
self::$encoded_item = json_decode($m,true);
}
else {
self::$encoded_item = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
@ -354,13 +350,8 @@ class Notifier {
]], Activity::encode_activity($target_item)
);
}
logger('target_item: ' . print_r($target_item,true));
// self::$encoded_item = encode_item($target_item);
logger('encoded: ' . print_r(self::$encoded_item,true));
// Send comments to the owner to re-deliver to everybody in the conversation
@ -374,8 +365,6 @@ class Notifier {
$relay_to_owner = (((! $top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item) && $cmd !== 'hyper') ? true : false);
$uplink = false;
// $cmd === 'relay' indicates the owner is sending it to the original recipients
@ -386,13 +375,13 @@ class Notifier {
// tag_deliver'd post which needs to be sent back to the original author
if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) {
if (($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) {
logger('notifier: uplink');
$uplink = true;
self::$packet_type = 'response';
}
if(($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
logger('followup relay (upstream delivery)', LOGGER_DEBUG);
$sendto = ($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan'];
self::$recipients = [ $sendto ];
@ -400,13 +389,15 @@ class Notifier {
$upstream = true;
self::$packet_type = 'response';
$is_moderated = their_perms_contains($parent_item['uid'],$sendto,'moderated');
if($relay_to_owner && $thread_is_public && (! $is_moderated)) {
Master::Summon([ 'Notifier' , 'hyper', $item_id ]);
if ($relay_to_owner && $thread_is_public && (! $is_moderated)) {
if (get_pconfig($target_item['uid'],'system','hyperdrive',false)) {
Master::Summon([ 'Notifier' , 'hyper', $item_id ]);
}
}
}
else {
if($cmd === 'relay') {
if ($cmd === 'relay') {
logger('owner relay (downstream delivery)');
}
else {
@ -416,29 +407,28 @@ class Notifier {
// if our parent is a tag_delivery recipient, uplink to the original author causing
// a delivery fork.
if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) {
if (($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) {
// don't uplink a relayed post to the relay owner
if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
if ($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
logger('notifier: uplinking this item');
Master::Summon(array('Notifier','uplink',$item_id));
}
}
if($thread_is_public && $cmd === 'hyper') {
$rcps = [];
if ($thread_is_public && $cmd === 'hyper') {
self::$recipients = [];
$r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 and not abook_xchan in ( '%s', '%s', '%s' ) ",
intval($target_item['uid']),
dbesc($target_item['author_xchan']),
dbesc($target_item['owner_xchan']),
dbesc($target_item['source_xchan'])
);
if($r) {
foreach($r as $rv) {
$rcps[] = $rv['abook_xchan'];
if ($r) {
foreach ($r as $rv) {
self::$recipients[] = $rv['abook_xchan'];
}
}
self::$private = false;
self::$recipients = $rcps;
}
else {
self::$private = false;
@ -452,11 +442,9 @@ class Notifier {
self::$recipients = array_diff(self::$recipients, [ $target_item['owner_xchan'] ]);
}
// don't send deletions onward for other people's stuff
// TODO verify this is needed - copied logic from same place in old code
if(intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) {
if (intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) {
logger('notifier: ignoring delete notification for non-wall item', LOGGER_NORMAL, LOG_NOTICE);
return;
}
@ -469,26 +457,26 @@ class Notifier {
logger('encoded item: ' . print_r(self::$encoded_item,true), LOGGER_DATA, LOG_DEBUG);
stringify_array_elms(self::$recipients);
if(! self::$recipients) {
if (! self::$recipients) {
logger('no recipients');
return;
}
// logger('recipients: ' . print_r(self::$recipients,true), LOGGER_NORMAL, LOG_DEBUG);
if(! count(self::$env_recips))
if (! count(self::$env_recips)) {
self::$env_recips = ((self::$private) ? [] : null);
}
$details = q("select xchan_hash, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")");
$recip_list = [];
$details = q("select xchan_hash, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan
where xchan_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")");
$recip_list = array();
if($details) {
foreach($details as $d) {
if ($details) {
foreach ($details as $d) {
$recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
if(self::$private) {
if (self::$private) {
self::$env_recips[] = $d['xchan_hash'];
}
}
@ -508,20 +496,18 @@ class Notifier {
'relay_to_owner' => $relay_to_owner,
'uplink' => $uplink,
'cmd' => $cmd,
'mail' => $mail,
'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
'single' => (($cmd === 'single_activity') ? true : false),
'request' => $request,
'normal_mode' => $normal_mode,
'packet_type' => self::$packet_type,
'queued' => []
];
call_hooks('notifier_process', $narr);
if($narr['queued']) {
foreach($narr['queued'] as $pq)
if ($narr['queued']) {
foreach ($narr['queued'] as $pq) {
self::$deliveries[] = $pq;
}
}
// notifier_process can alter the recipient list
@ -529,7 +515,7 @@ class Notifier {
self::$recipients = $narr['recipients'];
self::$env_recips = $narr['env_recips'];
if((self::$private) && (! self::$env_recips)) {
if ((self::$private) && (! self::$env_recips)) {
// shouldn't happen
logger('private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE);
return;
@ -537,22 +523,19 @@ class Notifier {
logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG);
// Now we have collected recipients (except for external mentions, FIXME)
// Now we have collected recipients (except for external mentions, @FIXME)
// Let's reduce this to a set of hubs; checking that the site is not dead.
$r = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")
$hubs = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url
where hubloc_hash in (" . protect_sprintf(implode(',',self::$recipients)) . ")
and hubloc_error = 0 and hubloc_deleted = 0 and ( site_dead = 0 OR site_dead is null ) "
);
if(! $r) {
if (! $hubs) {
logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
return;
}
$hubs = $r;
/**
* Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey,
* since it may have been a re-install which has not yet been detected and pruned.
@ -566,12 +549,12 @@ class Notifier {
$urls = []; // array of urls to check uniqueness of hubs from other networks
$hub_env = []; // per-hub envelope so we don't broadcast the entire envelope to all
foreach($hubs as $hub) {
foreach ($hubs as $hub) {
if(self::$env_recips) {
foreach(self::$env_recips as $er) {
if($hub['hubloc_hash'] === $er) {
if(! array_key_exists($hub['hubloc_site_id'], $hub_env)) {
if (self::$env_recips) {
foreach (self::$env_recips as $er) {
if ($hub['hubloc_hash'] === $er) {
if (! array_key_exists($hub['hubloc_site_id'], $hub_env)) {
$hub_env[$hub['hubloc_site_id']] = [];
}
$hub_env[$hub['hubloc_site_id']][] = $er;
@ -580,15 +563,15 @@ class Notifier {
}
if($hub['hubloc_network'] === 'zot6') {
if(! in_array($hub['hubloc_sitekey'],$keys)) {
if ($hub['hubloc_network'] === 'zot6') {
if (! in_array($hub['hubloc_sitekey'],$keys)) {
$hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
$dhubs[] = $hub;
$keys[] = $hub['hubloc_sitekey'];
}
}
else {
if(! in_array($hub['hubloc_url'],$urls)) {
if (! in_array($hub['hubloc_url'],$urls)) {
$hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
$dhubs[] = $hub;
$urls[] = $hub['hubloc_url'];
@ -598,11 +581,13 @@ class Notifier {
logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG);
foreach($dhubs as $hub) {
foreach ($dhubs as $hub) {
logger('notifier_hub: ' . $hub['hubloc_url'],LOGGER_DEBUG, LOG_DEBUG);
logger('notifier_hub: ' . $hub['hubloc_url'],LOGGER_DEBUG);
// deliver to any non-zot networks
if($hub['hubloc_network'] !== 'zot6') {
if ($hub['hubloc_network'] !== 'zot6') {
$narr = [
'channel' => self::$channel,
'upstream' => $upstream,
@ -617,15 +602,13 @@ class Notifier {
'relay_to_owner' => $relay_to_owner,
'uplink' => $uplink,
'cmd' => $cmd,
'mail' => $mail,
'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
'single' => (($cmd === 'single_activity') ? true : false),
'request' => $request,
'normal_mode' => $normal_mode,
'packet_type' => self::$packet_type,
'queued' => []
];
ActivityPub::notifier_process($narr);
call_hooks('notifier_hub',$narr);
@ -637,7 +620,7 @@ class Notifier {
}
// singleton deliveries by definition 'not got zot'.
// Single deliveries are other federated networks (plugins) and we're essentially
// Single deliveries are other federated networks and we're essentially
// delivering only to those that have this site url in their abook_instance
// and only from within a sync operation. This means if you post from a clone,
// and a connection is connected to one of your other clones; assuming that hub
@ -645,22 +628,21 @@ class Notifier {
// will invoke a delivery to those connections which are connected to just that
// hub instance.
// Note: Legacy Hubzilla and Osada code. In Zap this should never happen.
if($cmd === 'single_mail' || $cmd === 'single_activity') {
if ($cmd === 'single_activity') {
continue;
}
// default: zot protocol
$hash = new_uuid();
$hash = new_uuid();
$env = (($hub_env && $hub_env[$hub['hubloc_site_id']]) ? $hub_env[$hub['hubloc_site_id']] : '');
if((self::$private) && (! $env)) {
if ((self::$private) && (! $env)) {
continue;
}
$packet = Libzot::build_packet(self::$channel, self::$packet_type, $env, self::$encoded_item, self::$encoding, ((self::$private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto']);
$packet = Libzot::build_packet(self::$channel, self::$packet_type, $env, self::$encoded_item, self::$encoding,
((self::$private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto']);
Queue::insert(
[
@ -674,8 +656,9 @@ class Notifier {
);
// only create delivery reports for normal undeleted items
if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
if (is_array($target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_queue )
values ( '%s', '%s','%s','%s','%s','%s','%s','%s' ) ",
dbesc($target_item['mid']),
dbesc($hub['hubloc_host']),
dbesc($hub['hubloc_host']),
@ -690,17 +673,17 @@ class Notifier {
self::$deliveries[] = $hash;
}
if($normal_mode) {
if ($normal_mode) {
// This wastes a process if there are no delivery hooks configured, so check this before launching the new process
$x = q("select * from hook where hook = 'notifier_normal'");
if($x) {
if ($x) {
Master::Summon( [ 'Deliver_hooks', $target_item['id'] ] );
}
}
if(self::$deliveries)
if (self::$deliveries) {
do_delivery(self::$deliveries);
logger('notifier: basic loop complete.', LOGGER_DEBUG);
}
call_hooks('notifier_end',$target_item);

View file

@ -99,20 +99,26 @@ class Onepoll {
if(! $responded)
return;
if(defined('USE_OUTBOX')) {
// @fixme
// This needs to be converted from zotfeed to ActivityStreams (such as an ActivityPub outbox).
// The zotfeed has serious compatibility issues between Hubzilla and Zap.
if($contact['xchan_connurl']) {
$fetch_feed = true;
$x = null;
// They haven't given us permission to see their stream
$can_view_stream = their_perms_contains($importer_uid,$contact['abook_xchan'],'view_stream');
$can_view_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'their_perms','view_stream'));
if(! $can_view_stream)
$fetch_feed = false;
// we haven't given them permission to send us their stream
$can_send_stream = ((strpos(get_abconfig($importer_uid,$contact['abook_xchan'],'system','my_perms',EMPTY_STR),'send_stream') !== false) ? true : false);
$can_send_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'my_perms','send_stream'));
if(! $can_send_stream)
$fetch_feed = false;
@ -151,7 +157,7 @@ class Onepoll {
$j = json_decode($x['body'],true);
if($j['success'] && $j['messages']) {
foreach($j['messages'] as $message) {
$results = Libzot::process_delivery($contact['xchan_hash'], null, get_item_elements($message), [ $importer['xchan_hash'] ], false);
// process delivery here once we have parsed the AS
logger('onepoll: feed_update: process_delivery: ' . print_r($results,true), LOGGER_DATA);
$total ++;
}
@ -161,6 +167,8 @@ class Onepoll {
}
} // end USE_OUTBOX
// update the poco details for this connection
if($contact['xchan_connurl']) {

View file

@ -29,8 +29,8 @@ class Poller {
return;
}
// Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
file_put_contents($lockfile, $x);
// Create a lockfile.
file_put_contents($lockfile, EMPTY_STR);
logger('poller: start');
@ -47,7 +47,7 @@ class Poller {
$restart = true;
$generation = intval($argv[2]);
if(! $generation)
killme();
return;
}
if(($argc > 1) && intval($argv[1])) {

View file

@ -1,18 +0,0 @@
<?php
namespace Zotlabs\Identity\BasicId;
class BasicId {
private $name;
private $profile_photo;
private $profile_url;
private $address;
private $protocol;
}

View file

@ -2,27 +2,34 @@
namespace Zotlabs\Identity;
class OAuth2Server extends \OAuth2\Server {
use Zotlabs\Lib\System;
use OAuth2\Server;
use OAuth2\Storage\Memory;
use OAuth2\GrantType\ClientCredentials;
use OAuth2\OpenID\GrantType\AuthorizationCode;
class OAuth2Server extends Server {
public function __construct(OAuth2Storage $storage, $config = null) {
if(! is_array($config)) {
if (! is_array($config)) {
$config = [
'use_openid_connect' => true,
'issuer' => \Zotlabs\Lib\System::get_site_name()
'issuer' => System::get_site_name()
];
}
parent::__construct($storage, $config);
// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$this->addGrantType(new \OAuth2\GrantType\ClientCredentials($storage));
$this->addGrantType(new ClientCredentials($storage));
// Add the "Authorization Code" grant type (this is where the oauth magic happens)
// Need to use OpenID\GrantType to return id_token (see:https://github.com/bshaffer/oauth2-server-php/issues/443)
$this->addGrantType(new \OAuth2\OpenID\GrantType\AuthorizationCode($storage));
// Need to use OpenID\GrantType to return id_token
// (see:https://github.com/bshaffer/oauth2-server-php/issues/443)
$this->addGrantType(new AuthorizationCode($storage));
$keyStorage = new \OAuth2\Storage\Memory( [
$keyStorage = new Memory( [
'keys' => [
'public_key' => get_config('system', 'pubkey'),
'private_key' => get_config('system', 'prvkey')

View file

@ -51,7 +51,7 @@ class OAuth2Storage extends \OAuth2\Storage\Pdo {
{
$x = channelx_by_n($username);
if(! $x) {
if (! $x) {
return false;
}
@ -92,29 +92,30 @@ class OAuth2Storage extends \OAuth2\Storage\Pdo {
}
public function getUserClaims ($user_id, $claims) {
// Populate the CLAIMS requested (if any).
// @TODO: create a more reasonable/comprehensive list.
// @TODO: present claims on the AUTHORIZATION screen
// Populate the CLAIMS requested (if any).
// @TODO: create a more reasonable/comprehensive list.
// @TODO: present claims on the AUTHORIZATION screen
$userClaims = Array();
$userClaims = [];
$claims = explode (' ', trim($claims));
$validclaims = Array ("name","preferred_username","webfinger","portable_id","email","picture","firstName","lastName");
$claimsmap = Array (
"webfinger" => 'webfinger',
"portable_id" => 'portable_id',
"name" => 'name',
"email" => 'email',
"preferred_username" => 'username',
"picture" => 'picture',
"given_name" => 'firstName',
"family_name" => 'lastName'
);
$validclaims = [ "name", "preferred_username", "webfinger", "portable_id", "email", "picture", "firstName", "lastName" ];
$claimsmap = [
"webfinger" => 'webfinger',
"portable_id" => 'portable_id',
"name" => 'name',
"email" => 'email',
"preferred_username" => 'username',
"picture" => 'picture',
"given_name" => 'firstName',
"family_name" => 'lastName'
];
$userinfo = $this->getUser($user_id);
foreach ($validclaims as $validclaim) {
if (in_array($validclaim,$claims)) {
$claimkey = $claimsmap[$validclaim];
$userClaims[$validclaim] = $userinfo[$claimkey];
} else {
}
else {
$userClaims[$validclaim] = $validclaim;
}
}
@ -136,4 +137,35 @@ class OAuth2Storage extends \OAuth2\Storage\Pdo {
return true;
}
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null, $client_name = null)
{
// if it exists, update it.
if ($this->getClientDetails($client_id)) {
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_secret=:client_secret, redirect_uri=:redirect_uri, grant_types=:grant_types, scope=:scope, user_id=:user_id, client_name=:client_name where client_id=:client_id', $this->config['client_table']));
} else {
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (client_id, client_secret, redirect_uri, grant_types, scope, user_id, client_name) VALUES (:client_id, :client_secret, :redirect_uri, :grant_types, :scope, :user_id, :client_name)', $this->config['client_table']));
}
return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id', 'client_name'));
}
public function checkRestrictedGrantType($client_id, $grant_type)
{
$details = $this->getClientDetails($client_id);
if ($details['grant_types']) {
$grant_types = explode(' ', $details['grant_types']);
return in_array($grant_type, (array) $grant_types);
}
// if grant_types are not defined, then none are restricted
return true;
}
}

View file

@ -1,16 +0,0 @@
<?php
namespace Zotlabs\Identity\ProfilePhoto;
class ProfilePhoto {
private $photo_large_url;
private $photo_medium_url;
private $photo_small_url;
private $photo_mimetype;
private $photo_updated;
}

View file

@ -0,0 +1,81 @@
<?php
namespace Zotlabs\Lib;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
/**
* Class for dealing with ActivityStreams ordered collections.
* Construct with the object url and an optional channel to sign the request.
* Returns an array of collection members.
* If desired, call $collection->next to return additional pages (arrays of collection members).
* Returns an empty array when there is nothing more to return
*/
class ASCollection {
private $url = null;
private $channel = null;
private $nextpage = null;
private $data = null;
function __construct($url,$channel = null) {
$this->url = $url;
$this->channel = $channel;
$data = Activity::fetch($url,$channel);
if (! $data) {
return false;
}
$ptr = $data;
if ($data['type'] === 'OrderedCollection') {
if (array_key_exists('first',$data)) {
$ptr = $data['first'];
}
}
if ($ptr['type'] === 'OrderedCollectionPage' && $ptr['orderedItems']) {
$this->data = $ptr['orderedItems'];
}
$this->setnext($data);
return $this->data;
}
function next() {
if (! $this->nextpage) {
return [];
}
$data = Activity::fetch($this->nextpage,$channel);
if (! $data) {
return [];
}
if ($data['type'] === 'OrderedCollectionPage' && $data['orderedItems']) {
$this->data = $data['orderedItems'];
}
$this->setnext($data);
return $this->data;
}
function setnext($data) {
if (array_key_exists('next',$data)) {
$this->nextpage = $data['next'];
}
elseif (array_key_exists('last',$data)) {
$this->nextpage = $data['last'];
}
}
}

View file

@ -10,9 +10,9 @@ class AccessList {
static function add($uid,$name,$public = 0) {
$ret = false;
if(x($uid) && x($name)) {
if ($uid && $name) {
$r = self::byname($uid,$name); // check for dups
if($r !== false) {
if ($r !== false) {
// This could be a problem.
// Let's assume we've just created a list which we once deleted
@ -30,15 +30,7 @@ class AccessList {
return true;
}
do {
$dups = false;
$hash = random_string(32) . str_replace(['<','>'],['.','.'], $name);
$r = q("SELECT id FROM pgrp WHERE hash = '%s' LIMIT 1", dbesc($hash));
if($r)
$dups = true;
} while($dups == true);
$hash = new_uuid();
$r = q("INSERT INTO pgrp ( hash, uid, visible, gname )
VALUES( '%s', %d, %d, '%s' ) ",
@ -214,15 +206,15 @@ class AccessList {
}
static function members($gid) {
static function members($uid, $gid) {
$ret = array();
if(intval($gid)) {
$r = q("SELECT * FROM pgrp_member
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC ",
intval($gid),
intval(local_channel()),
intval(local_channel())
intval($uid),
intval($uid)
);
if($r)
$ret = $r;
@ -230,12 +222,12 @@ class AccessList {
return $ret;
}
static function members_xchan($gid) {
static function members_xchan($uid,$gid) {
$ret = [];
if(intval($gid)) {
$r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d",
intval($gid),
intval(local_channel())
intval($uid)
);
if($r) {
foreach($r as $rr) {
@ -293,7 +285,7 @@ class AccessList {
static function widget($every="connections",$each="group",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
static function widget($every="connections",$each="lists",$edit = false, $group_id = 0, $cid = '',$mode = 1) {
$o = '';
@ -312,7 +304,7 @@ class AccessList {
$selected = (($group_id == $rr['id']) ? ' group-selected' : '');
if ($edit) {
$groupedit = [ 'href' => "alist/".$rr['id'], 'title' => t('edit') ];
$groupedit = [ 'href' => "lists/".$rr['id'], 'title' => t('edit') ];
}
else {
$groupedit = null;
@ -334,7 +326,7 @@ class AccessList {
$tpl = get_markup_template("group_side.tpl");
$o = replace_macros($tpl, array(
'$title' => t('Access Lists'),
'$title' => t('Lists'),
'$edittext' => t('Edit list'),
'$createtext' => t('Create new list'),
'$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''),

File diff suppressed because it is too large Load diff

View file

@ -6,14 +6,15 @@ use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Queue;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\IConfig;
class ActivityPub {
static public function notifier_process(&$arr) {
if($arr['hub']['hubloc_network'] !== 'activitypub')
if ($arr['hub']['hubloc_network'] !== 'activitypub') {
return;
}
logger('upstream: ' . intval($arr['upstream']));
@ -22,17 +23,13 @@ class ActivityPub {
$signed_msg = null;
if(array_key_exists('target_item',$arr) && is_array($arr['target_item'])) {
if (array_key_exists('target_item',$arr) && is_array($arr['target_item'])) {
if(intval($arr['target_item']['item_obscured'])) {
if (intval($arr['target_item']['item_obscured'])) {
logger('Cannot send raw data as an activitypub activity.');
return;
}
if(strpos($arr['target_item']['postopts'],'nopub') !== false) {
return;
}
$signed_msg = get_iconfig($arr['target_item'],'activitypub','rawmsg');
// If we have an activity already stored with an LD-signature
@ -42,7 +39,7 @@ class ActivityPub {
// It is unclear if Mastodon supports the federation delivery model. Initial tests were
// inconclusive and the behaviour varied.
if(($arr['channel']['channel_hash'] !== $arr['target_item']['author_xchan']) && (! $signed_msg)) {
if (($arr['channel']['channel_hash'] !== $arr['target_item']['author_xchan']) && (! $signed_msg)) {
logger('relayed post with no signed message');
return;
}
@ -51,19 +48,34 @@ class ActivityPub {
$target_item = $arr['target_item'];
if(! $target_item['mid'])
if (! $target_item['mid']) {
return;
}
$prv_recips = $arr['env_recips'];
if($signed_msg) {
if ($signed_msg) {
$jmsg = $signed_msg;
}
else {
$ti = Activity::encode_activity($target_item, true);
if(! $ti)
if (! $ti) {
return;
}
if ($target_item['mid'] !== $target_item['parent_mid']) {
$token = IConfig::get($target_item['id'],'ocap','relay');
if ($token) {
if (defined('USE_BEARCAPS')) {
$ti['id'] = 'bear:?u=' . $ti['id'] . '&t=' . $token;
}
else {
$ti['id'] = $ti['id'] . '?token=' . $token;
}
}
}
$msg = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
@ -74,40 +86,42 @@ class ActivityPub {
$msg['signature'] = LDSignatures::sign($msg,$arr['channel']);
logger('ActivityPub_encoded: ' . json_encode($msg,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT));
$jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES);
}
if($prv_recips) {
$hashes = array();
if ($prv_recips) {
$hashes = [];
// re-explode the recipients, but only for this hub/pod
foreach($prv_recips as $recip)
foreach ($prv_recips as $recip) {
$hashes[] = "'" . $recip . "'";
}
$r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url = '%s'
and xchan_hash in (" . implode(',', $hashes) . ") and xchan_network = 'activitypub' ",
dbesc($arr['hub']['hubloc_url'])
);
if(! $r) {
if (! $r) {
logger('activitypub_process_outbound: no recipients');
return;
}
foreach($r as $contact) {
foreach ($r as $contact) {
// is $contact connected with this channel - and if the channel is cloned, also on this hub?
// 2018-10-19 this probably doesn't apply to activitypub anymore, just send the thing.
// They'll reject it if they don't like it.
// $single = deliverable_singleton($arr['channel']['channel_id'],$contact);
if(! $arr['normal_mode'])
if (! $arr['normal_mode']) {
continue;
}
$qi = self::queue_message($jmsg,$arr['channel'],$contact,$target_item['mid']);
if($qi) {
if ($qi) {
$arr['queued'][] = $qi;
}
continue;
@ -121,11 +135,11 @@ class ActivityPub {
// See if we can deliver all of them at once
$x = get_xconfig($arr['hub']['hubloc_hash'],'activitypub','collections');
if($x && $x['sharedInbox']) {
if ($x && $x['sharedInbox']) {
logger('using publicInbox delivery for ' . $arr['hub']['hubloc_url'], LOGGER_DEBUG);
$contact['hubloc_callback'] = $x['sharedInbox'];
$qi = self::queue_message($jmsg,$arr['channel'],$contact,$target_item['mid']);
if($qi) {
if ($qi) {
$arr['queued'][] = $qi;
}
}
@ -135,19 +149,18 @@ class ActivityPub {
dbesc($arr['hub']['hubloc_url'])
);
if(! $r) {
if (! $r) {
logger('activitypub_process_outbound: no recipients');
return;
}
foreach($r as $contact) {
foreach ($r as $contact) {
// $single = deliverable_singleton($arr['channel']['channel_id'],$contact);
$qi = self::queue_message($jmsg,$arr['channel'],$contact,$target_item['mid']);
if($qi) {
if ($qi) {
$arr['queued'][] = $qi;
}
}
@ -161,13 +174,12 @@ class ActivityPub {
static function queue_message($msg,$sender,$recip,$message_id = '') {
$dest_url = $recip['hubloc_callback'];
logger('URL: ' . $dest_url, LOGGER_DEBUG);
logger('DATA: ' . jindent($msg), LOGGER_DATA);
if(intval(get_config('system','activitypub_test')) || intval(get_pconfig($sender['channel_id'],'system','activitypub_test'))) {
if (intval(get_config('system','activitypub_test')) || intval(get_pconfig($sender['channel_id'],'system','activitypub_test'))) {
logger('test mode - delivery disabled');
return false;
}
@ -175,7 +187,7 @@ class ActivityPub {
$hash = random_string();
logger('queue: ' . $hash . ' ' . $dest_url, LOGGER_DEBUG);
Queue::insert(array(
Queue::insert([
'hash' => $hash,
'account_id' => $sender['channel_account_id'],
'channel_id' => $sender['channel_id'],
@ -183,9 +195,9 @@ class ActivityPub {
'posturl' => $dest_url,
'notify' => '',
'msg' => $msg
));
]);
if($message_id && (! get_config('system','disable_dreport'))) {
if ($message_id && (! get_config('system','disable_dreport'))) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ",
dbesc($message_id),
dbesc($dest_url),
@ -198,7 +210,6 @@ class ActivityPub {
}
return $hash;
}
@ -207,13 +218,14 @@ class ActivityPub {
// send a follow activity to the followee's inbox
if($x['recipient']['xchan_network'] !== 'activitypub') {
if ($x['recipient']['xchan_network'] !== 'activitypub') {
return;
}
$p = Activity::encode_person($x['sender'],true,true);
if(! $p)
$p = Activity::encode_person($x['sender'],false);
if (! $p) {
return;
}
$msg = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
@ -237,14 +249,14 @@ class ActivityPub {
dbesc($x['recipient']['xchan_hash'])
);
if($h) {
if ($h) {
$qi = self::queue_message($jmsg,$x['sender'],$h[0]);
if($qi)
if ($qi) {
$x['deliveries'] = $qi;
}
}
$x['success'] = true;
}
@ -252,19 +264,21 @@ class ActivityPub {
// send an accept activity to the followee's inbox
if($x['recipient']['xchan_network'] !== 'activitypub') {
if ($x['recipient']['xchan_network'] !== 'activitypub') {
return;
}
// we currently are not handling send of reject follow activities; this is permitted by protocol
$accept = get_abconfig($x['recipient']['abook_channel'],$x['recipient']['xchan_hash'],'activitypub','their_follow_id');
if(! $accept)
if (! $accept) {
return;
}
$p = Activity::encode_person($x['sender'],true,true);
if(! $p)
$p = Activity::encode_person($x['sender'],false);
if (! $p) {
return;
}
$msg = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
@ -292,10 +306,11 @@ class ActivityPub {
dbesc($x['recipient']['xchan_hash'])
);
if($h) {
if ($h) {
$qi = self::queue_message($jmsg,$x['sender'],$h[0]);
if($qi)
if ($qi) {
$x['deliveries'] = $qi;
}
}
$x['success'] = true;
@ -308,23 +323,24 @@ class ActivityPub {
intval($abook['abook_id'])
);
if((! $recip) || $recip[0]['xchan_network'] !== 'activitypub')
if ((! $recip) || $recip[0]['xchan_network'] !== 'activitypub')
return;
$channel = channelx_by_n($recip[0]['abook_channel']);
if(! $channel)
if (! $channel) {
return;
}
$p = Activity::encode_person($channel,true,true);
if(! $p)
if (! $p) {
return;
}
// send an unfollow activity to the followee's inbox
$orig_activity = get_abconfig($recip[0]['abook_channel'],$recip[0]['xchan_hash'],'activitypub','follow_id');
if($orig_activity && $recip[0]['abook_pending']) {
if ($orig_activity && $recip[0]['abook_pending']) {
// was never approved
@ -379,9 +395,9 @@ class ActivityPub {
dbesc($recip[0]['xchan_hash'])
);
if($h) {
if ($h) {
$qi = self::queue_message($jmsg,$channel,$h[0]);
if($qi) {
if ($qi) {
Master::Summon([ 'Deliver' , $qi ]);
}
}
@ -391,18 +407,18 @@ class ActivityPub {
$person_obj = null;
$ap = Activity::fetch($apurl);
if($ap) {
if ($ap) {
$AS = new ActivityStreams($ap);
if($AS->is_valid()) {
if(ActivityStreams::is_an_actor($AS->type)) {
if ($AS->is_valid()) {
if (ActivityStreams::is_an_actor($AS->type)) {
$person_obj = $AS->data;
}
elseif($AS->obj && ActivityStreams::is_an_actor($AS->obj['type'])) {
elseif ($AS->obj && ActivityStreams::is_an_actor($AS->obj['type'])) {
$person_obj = $AS->obj;
}
}
}
if($person_obj) {
if ($person_obj) {
Activity::actor_store($person_obj['id'],$person_obj);
return $person_obj['id'];
}

View file

@ -24,6 +24,7 @@ class ActivityStreams {
public $actor = null;
public $obj = null;
public $tgt = null;
public $replyto = null;
public $origin = null;
public $owner = null;
public $signer = null;
@ -35,46 +36,55 @@ class ActivityStreams {
/**
* @brief Constructor for ActivityStreams.
*
* Takes a JSON string as parameter, decodes it and sets up this object.
* Takes a JSON string or previously decode activity array as parameter,
* decodes it and sets up this object/activity, fetching any required attributes
* which were only referenced by @id/URI.
*
* @param string $string
*/
function __construct($string,$hub = null) {
function __construct($string,$hub = null,$client = null) {
$this->raw = $string;
$this->hub = $hub;
if(is_array($string)) {
if (is_array($string)) {
$this->data = $string;
$this->raw = json_encode($string,JSON_UNESCAPED_SLASHES);
}
else {
$this->data = json_decode($string, true);
}
if($this->data) {
if ($this->data) {
// verify and unpack JSalmon signature if present
// This will only be the case for Zot6 packets
if(is_array($this->data) && array_key_exists('signed',$this->data)) {
if (is_array($this->data) && array_key_exists('signed',$this->data)) {
$ret = JSalmon::verify($this->data);
$tmp = JSalmon::unpack($this->data['data']);
if($ret && $ret['success']) {
if($ret['signer']) {
if ($ret && $ret['success']) {
if ($ret['signer']) {
logger('Unpacked: ' . json_encode($tmp,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT),LOGGER_DATA,LOG_DEBUG);
$saved = json_encode($this->data,JSON_UNESCAPED_SLASHES);
$this->data = $tmp;
$this->data['signer'] = $ret['signer'];
$this->data['signed_data'] = $saved;
if($ret['hubloc']) {
if ($ret['hubloc']) {
$this->data['hubloc'] = $ret['hubloc'];
}
}
}
}
// This indicates only that we have sucessfully decoded JSON.
$this->valid = true;
if(array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) {
if($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
// Special handling for Mastodon "delete actor" activities which will often fail to verify
// because the key cannot be fetched. We will catch this condition elsewhere.
if (array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) {
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
$this->deleted = $this->data['actor'];
$this->valid = false;
}
@ -82,42 +92,54 @@ class ActivityStreams {
}
if($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
$this->actor = $this->get_actor('actor','','');
$this->obj = $this->get_compound_property('object');
$this->tgt = $this->get_compound_property('target');
$this->origin = $this->get_compound_property('origin');
$this->recips = $this->collect_recips();
// Attempt to assemble an Activity from what we were given.
if ($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
$this->actor = $this->get_actor('actor','','');
$this->obj = $this->get_compound_property('object');
$this->tgt = $this->get_compound_property('target');
$this->origin = $this->get_compound_property('origin');
$this->recips = $this->collect_recips();
$this->replyto = $this->get_compound_property('replyTo');
$this->ldsig = $this->get_compound_property('signature');
if($this->ldsig) {
if ($this->ldsig) {
$this->signer = $this->get_compound_property('creator',$this->ldsig);
if($this->signer && is_array($this->signer) && array_key_exists('publicKey',$this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
if ($this->signer && is_array($this->signer) && array_key_exists('publicKey',$this->signer)
&& is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
$this->sigok = LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
}
}
if(! $this->obj) {
// Implied create activity required by C2S specification if no object is present
if ($client && ! $this->obj) {
$this->obj = $this->data;
$this->type = 'Create';
if(! $this->actor) {
if (! $this->actor) {
$this->actor = $this->get_actor('attributedTo',$this->obj);
}
}
if($this->obj && is_array($this->obj) && $this->obj['actor'])
$this->obj['actor'] = $this->get_actor('actor',$this->obj);
if($this->tgt && is_array($this->tgt) && $this->tgt['actor'])
$this->tgt['actor'] = $this->get_actor('actor',$this->tgt);
// Enumerate and store actors in referenced objects
if ($this->obj && is_array($this->obj) && $this->obj['actor']) {
$this->obj['actor'] = $this->get_actor('actor',$this->obj);
}
if ($this->tgt && is_array($this->tgt) && $this->tgt['actor']) {
$this->tgt['actor'] = $this->get_actor('actor',$this->tgt);
}
// Determine if this is a followup or response activity
$this->parent_id = $this->get_property_obj('inReplyTo');
if((! $this->parent_id) && is_array($this->obj)) {
if ((! $this->parent_id) && is_array($this->obj)) {
$this->parent_id = $this->obj['inReplyTo'];
}
if((! $this->parent_id) && is_array($this->obj)) {
if ((! $this->parent_id) && is_array($this->obj)) {
$this->parent_id = $this->obj['id'];
}
}
@ -146,19 +168,21 @@ class ActivityStreams {
function collect_recips($base = '', $namespace = '') {
$x = [];
$fields = [ 'to', 'cc', 'bto', 'bcc', 'audience'];
foreach($fields as $f) {
foreach ($fields as $f) {
$y = $this->get_compound_property($f, $base, $namespace);
if($y) {
if(! is_array($y)) {
if ($y) {
if (! is_array($y)) {
$y = [ $y ];
}
$x = array_merge($x, $y);
if(! is_array($this->raw_recips))
if (! is_array($this->raw_recips)) {
$this->raw_recips = [];
}
$this->raw_recips[$f] = $x;
}
}
// not yet ready for prime time
// $x = $this->expand($x,$base,$namespace);
return $x;
@ -169,15 +193,15 @@ class ActivityStreams {
// right now use a hardwired recursion depth of 5
for($z = 0; $z < 5; $z ++) {
if(is_array($arr) && $arr) {
foreach($arr as $a) {
if(is_array($a)) {
for ($z = 0; $z < 5; $z ++) {
if (is_array($arr) && $arr) {
foreach ($arr as $a) {
if (is_array($a)) {
$ret[] = $a;
}
else {
$x = $this->get_compound_property($a,$base,$namespace);
if($x) {
if ($x) {
$ret = array_merge($ret,$x);
}
}
@ -197,35 +221,39 @@ class ActivityStreams {
* @param string $namespace if not set return empty string
* @return string|NULL
*/
function get_namespace($base, $namespace) {
if(! $namespace)
return '';
if (! $namespace) {
return EMPTY_STR;
}
$key = null;
foreach( [ $this->data, $base ] as $b ) {
if(! $b)
foreach ( [ $this->data, $base ] as $b ) {
if (! $b) {
continue;
}
if(array_key_exists('@context', $b)) {
if(is_array($b['@context'])) {
foreach($b['@context'] as $ns) {
if(is_array($ns)) {
foreach($ns as $k => $v) {
if($namespace === $v)
if (array_key_exists('@context', $b)) {
if (is_array($b['@context'])) {
foreach ($b['@context'] as $ns) {
if (is_array($ns)) {
foreach ($ns as $k => $v) {
if ($namespace === $v) {
$key = $k;
}
}
}
else {
if($namespace === $ns) {
if ($namespace === $ns) {
$key = '';
}
}
}
}
else {
if($namespace === $b['@context']) {
if ($namespace === $b['@context']) {
$key = '';
}
}
@ -243,15 +271,17 @@ class ActivityStreams {
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_property_obj($property, $base = '', $namespace = '') {
$prefix = $this->get_namespace($base, $namespace);
if($prefix === null)
if ($prefix === null) {
return null;
}
$base = (($base) ? $base : $this->data);
$propname = (($prefix) ? $prefix . ':' : '') . $property;
if(! is_array($base)) {
if (! is_array($base)) {
btlogger('not an array: ' . print_r($base,true));
return null;
}
@ -290,7 +320,7 @@ class ActivityStreams {
function get_actor($property,$base='',$namespace = '') {
$x = $this->get_property_obj($property, $base, $namespace);
if($this->is_url($x)) {
if ($this->is_url($x)) {
// SECURITY: If we have already stored the actor profile, re-generate it
// from cached data - don't refetch it from the network
@ -298,7 +328,8 @@ class ActivityStreams {
$r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
dbesc($x)
);
if($r) {
if ($r) {
// indicate that this is a cached record
$y = Activity::encode_person($r[0]);
$y['cached'] = true;
$y['updated'] = datetime_convert('UTC','UTC',$r[0]['hubloc_updated'],ATOM_TIME);
@ -306,8 +337,8 @@ class ActivityStreams {
}
}
$actor = $this->get_compound_property($property,$base,$namespace,true);
if(is_array($actor) && self::is_an_actor($actor['type'])) {
if(array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) {
if (is_array($actor) && self::is_an_actor($actor['type'])) {
if (array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) {
$actor = $this->fetch_property($actor['id']);
}
return $actor;
@ -325,9 +356,10 @@ class ActivityStreams {
* @param boolean $first (optional) default false, if true and result is a sequential array return only the first element
* @return NULL|mixed
*/
function get_compound_property($property, $base = '', $namespace = '', $first = false) {
$x = $this->get_property_obj($property, $base, $namespace);
if($this->is_url($x)) {
if ($this->is_url($x)) {
$y = $this->fetch_property($x);
if (is_array($y)) {
$x = $y;
@ -335,23 +367,25 @@ class ActivityStreams {
}
// verify and unpack JSalmon signature if present
if(is_array($x) && array_key_exists('signed',$x)) {
// This may be present in Zot6 packets
if (is_array($x) && array_key_exists('signed',$x)) {
$ret = JSalmon::verify($x);
$tmp = JSalmon::unpack($x['data']);
if($ret && $ret['success']) {
if($ret['signer']) {
if ($ret && $ret['success']) {
if ($ret['signer']) {
logger('Unpacked: ' . json_encode($tmp,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT),LOGGER_DATA,LOG_DEBUG);
$saved = json_encode($x,JSON_UNESCAPED_SLASHES);
$x = $tmp;
$x['signer'] = $ret['signer'];
$x['signed_data'] = $saved;
if($ret['hubloc']) {
if ($ret['hubloc']) {
$x['hubloc'] = $ret['hubloc'];
}
}
}
}
if($first && is_array($x) && array_key_exists(0,$x)) {
if ($first && is_array($x) && array_key_exists(0,$x)) {
return $x[0];
}
@ -364,8 +398,9 @@ class ActivityStreams {
* @param string $url
* @return boolean
*/
function is_url($url) {
if(($url) && (! is_array($url)) && ((strpos($url, 'http') === 0) || (strpos($url,'x-zot') === 0))) {
if (($url) && (! is_array($url)) && ((strpos($url, 'http') === 0) || (strpos($url,'x-zot') === 0) || (strpos($url,'bear') === 0))) {
return true;
}
@ -379,14 +414,15 @@ class ActivityStreams {
* @param string $namespace (optional) default empty
* @return NULL|mixed
*/
function get_primary_type($base = '', $namespace = '') {
if(! $base)
if (! $base) {
$base = $this->data;
}
$x = $this->get_property_obj('type', $base, $namespace);
if(is_array($x)) {
foreach($x as $y) {
if(strpos($y, ':') === false) {
if (is_array($x)) {
foreach ($x as $y) {
if (strpos($y, ':') === false) {
return $y;
}
}
@ -410,8 +446,5 @@ class ActivityStreams {
]);
return(($x) ? true : false);
}
}

View file

@ -74,7 +74,7 @@ class Apps {
'Events',
'Search',
'Profile Photo',
'Access Lists'
'Lists'
]);
call_hooks('get_base_apps',$x);
return $x;
@ -313,7 +313,7 @@ class Apps {
static public function translate_system_apps(&$arr) {
$apps = array(
'Apps' => t('Apps'),
'Affinity Tool' => t('Affinity Tool'),
'Friend Zoom' => t('Friend Zoom'),
'Articles' => t('Articles'),
'Cards' => t('Cards'),
'Calendar' => t('Calendar'),
@ -331,6 +331,7 @@ class Apps {
'Suggest Channels' => t('Suggest Channels'),
'Login' => t('Login'),
'Channel Manager' => t('Channel Manager'),
'Notes' => t('Notes'),
'Network' => t('Stream'),
'Settings' => t('Settings'),
'Files' => t('Files'),
@ -339,7 +340,10 @@ class Apps {
'Channel Home' => t('Channel Home'),
'View Profile' => t('View Profile'),
'Photos' => t('Photos'),
'Photomap' => t('Photomap'),
'Events' => t('Events'),
'Tasks' => t('Tasks'),
'No Comment' => t('No Comment'),
'Directory' => t('Directory'),
'Help' => t('Help'),
'Mail' => t('Mail'),
@ -359,7 +363,7 @@ class Apps {
'Profile Photo' => t('Profile Photo'),
'Profile' => t('Profile'),
'Profiles' => t('Profiles'),
'Access Lists' => t('Access Lists'),
'Lists' => t('Lists'),
'Notifications' => t('Notifications'),
'Order Apps' => t('Order Apps'),
'CalDAV' => t('CalDAV'),
@ -579,7 +583,8 @@ class Apps {
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
'$navapps' => (($mode === 'nav') ? true : false),
'$order' => (($mode === 'nav-order') ? true : false),
'$order' => (($mode === 'nav-order' || $mode === 'nav-order-pinned') ? true : false),
'$mode' => $mode,
'$add' => t('Add to app-tray'),
'$remove' => t('Remove from app-tray'),
'$add_nav' => t('Pin to navbar'),
@ -921,8 +926,6 @@ class Apps {
if ($list) {
foreach ($list as $li) {
$papp = self::app_encode($li);
if ($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false)
continue;
$syslist[] = $papp;
}
}
@ -970,9 +973,6 @@ class Apps {
if ($list) {
foreach ($list as $li) {
$papp = self::app_encode($li);
if ($menu !== 'nav_pinned_app' && strpos($papp['categories'],'nav_pinned_app') !== false) {
continue;
}
$syslist[] = $papp;
}
}

View file

@ -2,6 +2,7 @@
namespace Zotlabs\Lib;
use App;
use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Master;
@ -24,25 +25,29 @@ class Connect {
$uid = $channel['channel_id'];
if (strpos($url,'@') === false && strpos($url,'/') === false) {
$url = $url . '@' . App::get_hostname();
}
$result = [ 'success' => false, 'message' => '' ];
$my_perms = false;
$protocol = '';
if(substr($url,0,1) === '[') {
if (substr($url,0,1) === '[') {
$x = strpos($url,']');
if($x) {
if ($x) {
$protocol = substr($url,1,$x-1);
$url = substr($url,$x+1);
}
}
if(! allowed_url($url)) {
if (! check_siteallowed($url)) {
$result['message'] = t('Channel is blocked on this site.');
return $result;
}
if(! $url) {
if (! $url) {
$result['message'] = t('Channel location missing.');
return $result;
}
@ -52,46 +57,53 @@ class Connect {
$r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ",
intval($uid)
);
if($r) {
if ($r) {
$total_channels = $r[0]['total'];
}
if(! service_class_allows($uid,'total_channels',$total_channels)) {
if (! service_class_allows($uid,'total_channels',$total_channels)) {
$result['message'] = upgrade_message();
return $result;
}
$xchan_hash = '';
$sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : '');
$r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' $sql_options ",
dbesc($url),
dbesc($url),
dbesc($url)
);
if($r) {
if ($r) {
// reset results to the best record or the first if we don't have the best
// note: this is a single record and not an array of results
$r = Libzot::zot_record_preferred($r,'xchan_network');
// Some Hubzilla records were originally stored as activitypub. If we find one, force rediscovery
// since Zap cannot connect with them.
if ($r['xchan_network'] === 'activitypub' && ! get_config('system','activitypub')) {
$r = null;
}
}
$singleton = false;
$d = false;
if(! $r) {
if (! $r) {
// not in cache - try discovery
$wf = discover_by_webbie($url,$protocol);
if(! $wf) {
if (! $wf) {
$feeds = get_config('system','feed_contacts');
if(($feeds) && (in_array($protocol, [ '', 'feed', 'rss' ]))) {
if (($feeds) && (in_array($protocol, [ '', 'feed', 'rss' ]))) {
$d = discover_feed($url);
}
else {
@ -101,8 +113,7 @@ class Connect {
}
}
if($wf || $d) {
if ($wf || $d) {
// something was discovered - find the record which was just created.
@ -114,14 +125,14 @@ class Connect {
// convert to a single record (once again preferring a zot solution in the case of multiples)
if($r) {
if ($r) {
$r = Libzot::zot_record_preferred($r,'xchan_network');
}
}
// if discovery was a success or the channel was already cached we should have an xchan record in $r
if($r) {
if ($r) {
$xchan = $r;
$xchan_hash = $r['xchan_hash'];
$their_perms = EMPTY_STR;
@ -129,41 +140,52 @@ class Connect {
// failure case
if(! $xchan_hash) {
if (! $xchan_hash) {
$result['message'] = t('Channel discovery failed.');
logger('follow: ' . $result['message']);
return $result;
}
// Now start processing the new connection
if($r['xchan_network'] === 'activitypub') {
// ActivityPub is not nomadic
$result['message'] = t('Protocol not supported');
if (! check_channelallowed($xchan_hash)) {
$result['message'] = t('Channel is blocked on this site.');
logger('follow: ' . $result['message']);
return $result;
}
$ap_allowed = get_config('system','activitypub',false) && get_pconfig($uid,'system','activitypub',true);
if ($r['xchan_network'] === 'activitypub') {
if (! $ap_allowed) {
$result['message'] = t('Protocol not supported');
return $result;
}
$singleton = true;
}
// Now start processing the new connection
$aid = $channel['channel_account_id'];
$hash = $channel['channel_hash'];
$default_group = $channel['channel_default_group'];
if($hash === $xchan_hash) {
if ($hash === $xchan_hash) {
$result['message'] = t('Cannot connect to yourself.');
return $result;
}
if($xchan['xchan_network'] === 'rss') {
if ($xchan['xchan_network'] === 'rss') {
// check service class feed limits
$t = q("select count(*) as total from abook where abook_account = %d and abook_feed = 1 ",
intval($aid)
);
if($t) {
if ($t) {
$total_feeds = $t[0]['total'];
}
if(! service_class_allows($uid,'total_feeds',$total_feeds)) {
if (! service_class_allows($uid,'total_feeds',$total_feeds)) {
$result['message'] = upgrade_message();
return $result;
}
@ -172,8 +194,9 @@ class Connect {
// to negotiate a suitable permission response
$p = get_abconfig($uid,$xchan_hash,'system','their_perms',EMPTY_STR);
if($p)
if ($p) {
$p .= ',';
}
$p .= 'view_stream,republish';
set_abconfig($uid,$xchan_hash,'system','their_perms',$p);
@ -206,14 +229,14 @@ class Connect {
intval($uid)
);
if($r) {
if ($r) {
$abook_instance = $r[0]['abook_instance'];
// If they are on a non-nomadic network, add them to this location
if(($singleton) && strpos($abook_instance,z_root()) === false) {
if($abook_instance) {
if (($singleton) && strpos($abook_instance,z_root()) === false) {
if ($abook_instance) {
$abook_instance .= ',';
}
$abook_instance .= z_root();
@ -226,7 +249,7 @@ class Connect {
// if they have a pending connection, we just followed them so approve the connection request
if(intval($r[0]['abook_pending'])) {
if (intval($r[0]['abook_pending'])) {
$x = q("update abook set abook_pending = 0 where abook_id = %d",
intval($r[0]['abook_id'])
);
@ -253,7 +276,7 @@ class Connect {
);
}
if(! $r) {
if (! $r) {
logger('abook creation failed');
$result['message'] = t('error saving data');
return $result;
@ -261,7 +284,7 @@ class Connect {
// Set suitable permissions to the connection
if($my_perms) {
if ($my_perms) {
set_abconfig($uid,$xchan_hash,'system','my_perms',$my_perms);
}
@ -273,7 +296,7 @@ class Connect {
intval($uid)
);
if($r) {
if ($r) {
$result['abook'] = $r[0];
Master::Summon([ 'Notifier', 'permissions_create', $result['abook']['abook_id'] ]);
}
@ -284,9 +307,9 @@ class Connect {
/** If there is a default group for this channel, add this connection to it */
if($default_group) {
if ($default_group) {
$g = AccessList::rec_byhash($uid,$default_group);
if($g) {
if ($g) {
AccessList::member_add($uid,'',$xchan_hash,$g['id']);
}
}

View file

@ -1,41 +0,0 @@
<?php
namespace Zotlabs\Lib;
class Discover {
private $resource = null;
private $resource_type = null;
private $webfinger = null;
private $zotinfo = null;
function run($resource) {
$this->resource = $resource;
$this->webfinger = webfinger_rfc7033($this->resource);
if(is_array($this->webfinger) && array_key_exists('links',$this->webfinger)) {
foreach($this->webfinger['links'] as $link) {
if(array_key_exists('rel',$link) && $link['rel'] === PROTOCOL_ZOT6) {
if(array_key_exists('href',$link) && $link['href'] !== EMPTY_STR) {
$headers = 'Accept: application/x-zot+json';
$redirects = 0;
$this->zotinfo = z_fetch_url($link['href'],true,$redirects,
[ 'headers' => [ $headers ]]
);
}
}
}
}
return [
'resource' => $this->resource,
'resource_type' => $this->resource_type,
'webfinger' => $this->webfinger,
'zotinfo' => $this->zotinfo
];
}
}

View file

@ -27,9 +27,9 @@ class LDSignatures {
static function sign($data,$channel) {
$options = [
'type' => 'RsaSignature2017',
'nonce' => random_string(64),
'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
'type' => 'RsaSignature2017',
'nonce' => random_string(64),
'creator' => channel_url($channel),
'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
];
@ -110,7 +110,7 @@ class LDSignatures {
$data_type = 'application/activity+json';
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
$keyhash = base64url_encode(z_root() . '/channel/' . $channel['channel_address']);
$keyhash = base64url_encode(channel_url($channel));
$data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$data);
@ -121,12 +121,12 @@ class LDSignatures {
$signature = base64url_encode(Crypto::sign($data . $precomputed,$channel['channel_prvkey']));
return ([
'id' => $arr['id'],
'meData' => $data,
'meDataType' => $data_type,
'meEncoding' => $encoding,
'meAlgorithm' => $algorithm,
'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
'id' => $arr['id'],
'meData' => $data,
'meDataType' => $data_type,
'meEncoding' => $encoding,
'meAlgorithm' => $algorithm,
'meCreator' => channel_url($channel),
'meSignatureValue' => $signature
]);

View file

@ -61,11 +61,19 @@ class Libprofile {
if ($profile) {
$p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile
LEFT JOIN channel ON profile.uid = channel.channel_id
WHERE channel.channel_address = '%s' AND profile.profile_guid = '%s' LIMIT 1",
dbesc($nickname),
dbesc($profile)
LEFT JOIN channel ON profile.uid = channel.channel_id
WHERE channel.channel_address = '%s' AND profile.profile_guid = '%s' LIMIT 1",
dbesc($nickname),
dbesc($profile)
);
if (! $p) {
$p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile
LEFT JOIN channel ON profile.uid = channel.channel_id
WHERE channel.channel_address = '%s' AND profile.id = %d LIMIT 1",
dbesc($nickname),
intval($profile)
);
}
}
if (! $p) {

View file

@ -399,6 +399,9 @@ class Libsync {
}
$columns = db_columns('channel');
$disallowed = [
'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey',
'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted',
@ -409,17 +412,15 @@ class Libsync {
'channel_a_delegate', 'channel_moved'
];
$clean = array();
foreach($arr['channel'] as $k => $v) {
if(in_array($k,$disallowed))
if (in_array($k,$disallowed)) {
continue;
$clean[$k] = $v;
}
if(count($clean)) {
foreach($clean as $k => $v) {
$r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v)
. "' where channel_id = " . intval($channel['channel_id']) );
}
if (! in_array($k,$columns)) {
continue;
}
$r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v)
. "' where channel_id = " . intval($channel['channel_id']) );
}
}
@ -853,11 +854,6 @@ class Libsync {
continue;
}
// Catch some malformed entries from the past which still exist
if(strpos($location['address'],'/') !== false)
$location['address'] = substr($location['address'],0,strpos($location['address'],'/'));
// match as many fields as possible in case anything at all changed.
$r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_id_url = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_site_id = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ",

View file

@ -11,6 +11,7 @@ use App;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\PermissionRoles;
use Zotlabs\Daemon\Master;
@ -322,13 +323,13 @@ class Libzot {
return false;
}
logger('zot-info: ' . print_r($record,true), LOGGER_DATA, LOG_DEBUG);
$x = self::import_xchan($record['data'], (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
if (! $x['success'])
if (! $x['success']) {
return false;
}
if ($channel && $record['data']['permissions']) {
$old_read_stream_perm = their_perms_contains($channel['channel_id'],$x['hash'],'view_stream');
@ -381,6 +382,19 @@ class Libzot {
}
else {
// limit the ability to do connection spamming, this limit is per channel
$lim = intval(get_config('system','max_connections_per_day',50));
if ($lim) {
$n = q("select count(abook_id) as total from abook where abook_channel = %d and abook_created > '%s'",
intval($channel['channel_id']),
dbesc(datetime_convert('UTC','UTC','now - 24 hours'))
);
if ($n && intval($n['total']) > $lim) {
logger('channel: ' . $channel['channel_id'] . ' too many new connections per day. This one from ' . $hsig['signer'], LOGGER_NORMAL, LOG_WARNING);
return false;
}
}
$p = Permissions::connect_perms($channel['channel_id']);
$my_perms = Permissions::serialise($p['perms']);
@ -1169,6 +1183,14 @@ class Libzot {
if ($env['encoding'] === 'activitystreams') {
$AS = new ActivityStreams($data);
if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj)
&& array_key_exists('object',$AS->obj) && array_key_exists('actor',$AS->obj)) {
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
// Reparse the encapsulated Activity and use that instead
logger('relayed activity',LOGGER_DEBUG);
$AS = new ActivityStreams($AS->obj);
}
if (! $AS->is_valid()) {
logger('Activity rejected: ' . print_r($data,true));
return;
@ -1289,8 +1311,8 @@ class Libzot {
$arr['owner_xchan'] = $env['sender'];
}
if ($private) {
$arr['item_private'] = true;
if ($private && (! intval($arr['item_private']))) {
$arr['item_private'] = 1;
}
if ($arr['mid'] === $arr['parent_mid']) {
if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) {
@ -1523,7 +1545,8 @@ class Libzot {
* @brief
*
* @param array $sender
* @param array $arr
* @param ActivityStreams object $act
* @param array $msg_arr
* @param array $deliveries
* @param boolean $relay
* @param boolean $public (optional) default false
@ -1535,6 +1558,8 @@ class Libzot {
$result = [];
//logger('msg_arr: ' . print_r($msg_arr,true),LOGGER_ALL);
// If an upstream hop used ActivityPub, set the identities to zot6 nomadic identities where applicable
// else things could easily get confused
@ -1681,24 +1706,23 @@ class Libzot {
// Conversation fetches (e.g. $request == true) take place for
// a) new comments on expired posts
// b) hyperdrive (friend-of-friend) conversations
// c) Repeats of posts by others
// over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations
// (if hyperdrive is enabled) and repeated posts by a friend.
// (if hyperdrive is enabled).
// If $allowed is already true, this is probably the conversation of a direct friend or a
// conversation fetch for a new comment on an expired post
// Comments of all these activities are allowed and will only be rejected (later) if the parent
// doesn't exist.
// if ($perm === 'send_stream') {
// if (get_pconfig($channel['channel_id'],'system','hyperdrive',true) || $arr['verb'] === 'Announce') {
// $allowed = true;
// }
// }
// else {
if ($perm === 'send_stream') {
if (get_pconfig($channel['channel_id'],'system','hyperdrive',false)) {
$allowed = true;
}
}
else {
$allowed = true;
// }
}
$friendofriend = true;
}
@ -1818,7 +1842,7 @@ class Libzot {
// remove_community_tag is a no-op if this isn't a community tag activity
self::remove_community_tag($sender,$arr,$channel['channel_id']);
// set these just in case we need to store a fresh copy of the deleted post.
// This could happen if the delete got here before the original post did.
@ -1876,8 +1900,9 @@ class Libzot {
// We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit),
// and at the same time not relay any other relayable posts more than once, because to do so is very wasteful.
if (! intval($r[0]['item_origin']))
if (! intval($r[0]['item_origin'])) {
continue;
}
}
}
else {
@ -1967,9 +1992,6 @@ class Libzot {
if (get_pconfig($channel['channel_id'],'system','hyperdrive',true)) {
return true;
}
if ($item['verb'] === 'Announce' && get_pconfig($channel['channel_id'],'system','hyperdrive_announce',true)) {
return true;
}
return false;
}
@ -2006,6 +2028,14 @@ class Libzot {
foreach ($a['data']['orderedItems'] as $activity) {
$AS = new ActivityStreams($activity);
if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj)
&& array_key_exists('object',$AS->obj) && array_key_exists('actor',$AS->obj)) {
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
// Reparse the encapsulated Activity and use that instead
logger('relayed activity',LOGGER_DEBUG);
$AS = new ActivityStreams($AS->obj);
}
if (! $AS->is_valid()) {
logger('FOF Activity rejected: ' . print_r($activity,true));
continue;
@ -2236,7 +2266,7 @@ class Libzot {
$item_found = false;
$post_id = 0;
$r = q("select id, author_xchan, owner_xchan, source_xchan, item_deleted from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
$r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' )
and mid = '%s' and uid = %d limit 1",
dbesc($sender),
dbesc($sender),
@ -2246,11 +2276,12 @@ class Libzot {
);
if ($r) {
if ($r[0]['author_xchan'] === $sender || $r[0]['owner_xchan'] === $sender || $r[0]['source_xchan'] === $sender) {
$stored = $r[0];
if ($stored['author_xchan'] === $sender || $stored['owner_xchan'] === $sender || $stored['source_xchan'] === $sender) {
$ownership_valid = true;
}
$post_id = $r[0]['id'];
$post_id = $stored['id'];
$item_found = true;
}
else {
@ -2274,8 +2305,26 @@ class Libzot {
return false;
}
if ($stored['resource_type'] === 'event') {
$i = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($stored['resource_id']),
intval($uid)
);
if ($i) {
if ($i[0]['event_xchan'] === $sender) {
q("delete from event where event_hash = '%s' and uid = %d",
dbesc($stored['resource_id']),
intval($uid)
);
}
else {
logger('delete linked event: not owner');
return;
}
}
}
if ($item_found) {
if (intval($r[0]['item_deleted'])) {
if (intval($stored['item_deleted'])) {
logger('delete_imported_item: item was already deleted');
if (! $relay) {
return false;
@ -2288,10 +2337,10 @@ class Libzot {
// back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing
// this information from the metadata should have no other discernible impact.
if (($r[0]['id'] != $r[0]['parent']) && intval($r[0]['item_origin'])) {
if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) {
q("update item set item_origin = 0 where id = %d and uid = %d",
intval($r[0]['id']),
intval($r[0]['uid'])
intval($stored['id']),
intval($stored['uid'])
);
}
}
@ -2307,90 +2356,6 @@ class Libzot {
return $post_id;
}
static function process_mail_delivery($sender, $arr, $deliveries) {
$result = array();
if ($sender != $arr['from_xchan']) {
logger('process_mail_delivery: sender is not mail author');
return;
}
foreach ($deliveries as $d) {
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
$r = q("select * from channel where channel_hash = '%s' limit 1",
dbesc($d['hash'])
);
if (! $r) {
$DR->update('recipient not found');
$result[] = $DR->get();
continue;
}
$channel = $r[0];
$DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
if (! perm_is_allowed($channel['channel_id'],$sender,'post_mail')) {
/*
* Always allow somebody to reply if you initiated the conversation. It's anti-social
* and a bit rude to send a private message to somebody and block their ability to respond.
* If you are being harrassed and want to put an end to it, delete the conversation.
*/
$return = false;
if ($arr['parent_mid']) {
$return = q("select * from mail where mid = '%s' and channel_id = %d limit 1",
dbesc($arr['parent_mid']),
intval($channel['channel_id'])
);
}
if (! $return) {
logger("permission denied for mail delivery {$channel['channel_id']}");
$DR->update('permission denied');
$result[] = $DR->get();
continue;
}
}
$r = q("select id from mail where mid = '%s' and channel_id = %d limit 1",
dbesc($arr['mid']),
intval($channel['channel_id'])
);
if ($r) {
if (intval($arr['mail_recalled'])) {
$x = q("delete from mail where id = %d and channel_id = %d",
intval($r[0]['id']),
intval($channel['channel_id'])
);
$DR->update('mail recalled');
$result[] = $DR->get();
logger('mail_recalled');
}
else {
$DR->update('duplicate mail received');
$result[] = $DR->get();
logger('duplicate mail received');
}
continue;
}
else {
$arr['account_id'] = $channel['channel_account_id'];
$arr['channel_id'] = $channel['channel_id'];
$item_id = mail_store($arr);
$DR->update('mail delivered');
$result[] = $DR->get();
}
}
return $result;
}
/**
* @brief Processes delivery of profile.
@ -2935,15 +2900,10 @@ class Libzot {
// now all forums (public, restricted, and private) set the public_forum flag. So it really means "is a group"
// and has nothing to do with accessibility.
$channel_type = 'normal';
$role = get_pconfig($e['channel_id'],'system','permissions_role');
if (in_array($role, ['forum','forum_restricted','repository'])) {
$channel_type = 'group';
}
if (in_array($role, ['collection','collection_restricted'])) {
$channel_type = 'collection';
}
$rolesettings = PermissionRoles::role_perms($role);
$channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal';
// This is for birthdays and keywords, but must check access permissions
$p = q("select * from profile where uid = %d and is_default = 1",

View file

@ -108,7 +108,7 @@ class Libzotdir {
if($ret === false) {
$ret = get_config('directory', $setting);
if($ret === false) {
$default = (in_array($setting,['globaldir','safemode']) ? 1 : 0);
$ret = (in_array($setting,['globaldir','safemode']) ? 1 : 0);
}
}
@ -132,16 +132,18 @@ class Libzotdir {
$pubforums = self::get_directory_setting($observer, 'chantype');
$hide_local = intval(get_config('system','localdir_hide'));
if($hide_local)
if ($hide_local) {
$globaldir = 1;
}
// Build urls without order and pubforums so it's easy to tack on the changed value
// Probably there's an easier way to do this
$directory_sort_order = get_config('system','directory_sort_order');
if(! $directory_sort_order)
if (! $directory_sort_order) {
$directory_sort_order = 'date';
}
$current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order);
$suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : '');
@ -156,7 +158,8 @@ class Libzotdir {
unset($tmp['safe']);
unset($tmp['req']);
unset($tmp['f']);
$forumsurl = $url . http_build_query($tmp) . $suggest;
$q = http_build_query($tmp);
$forumsurl = $url . (($q) ? '&' . $q : '') . $suggest;
$o = replace_macros(get_markup_template('dir_sort_links.tpl'), [
'$header' => t('Directory Options'),

View file

@ -236,7 +236,7 @@ class Queue {
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$ret = $outq['outq_msg'];
logger('ActivityPub send: ' . $ret, LOGGER_DATA);
logger('ActivityPub send: ' . jindent($ret), LOGGER_DATA);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = 'post ' . get_request_string($outq['outq_posturl']);

View file

@ -95,7 +95,7 @@ class Share {
$is_photo = (($this->item['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
if($is_photo) {
$object = json_decode($this->item['obj'],true);
$photo_bb = $object['body'];
$photo_bb = (($object['source']) ? $object['source']['content'] : $object['body']);
}
if (strpos($this->item['body'], "[/share]") !== false) {
@ -107,7 +107,7 @@ class Share {
"' portable_id='" . $this->item['author']['xchan_hash'] .
"' avatar='" . $this->item['author']['xchan_photo_s'] .
"' link='" . $this->item['plink'] .
"' auth='" . (($this->item['author']['network'] === 'zot') ? 'true' : 'false') .
"' auth='" . (($this->item['author']['network'] === 'zot6') ? 'true' : 'false') .
"' posted='" . $this->item['created'] .
"' message_id='" . $this->item['mid'] .
"']";

View file

@ -1,127 +0,0 @@
<?php
namespace Zotlabs\Lib;
/**
* @brief wrapper for z_fetch_url() which can be instantiated with several built-in parameters and
* these can be modified and re-used. Useful for CalDAV and other processes which need to authenticate
* and set lots of CURL options (many of which stay the same from one call to the next).
*/
class SuperCurl {
private $auth;
private $url;
private $curlopt = array();
private $headers = null;
public $filepos = 0;
public $filehandle = 0;
public $request_data = '';
private $request_method = 'GET';
private $upload = false;
private $cookies = false;
private function set_data($s) {
$this->request_data = $s;
$this->filepos = 0;
}
public function curl_read($ch,$fh,$size) {
if($this->filepos < 0) {
unset($fh);
return '';
}
$s = substr($this->request_data,$this->filepos,$size);
if(strlen($s) < $size)
$this->filepos = (-1);
else
$this->filepos = $this->filepos + $size;
return $s;
}
public function __construct($opts = array()) {
$this->set($opts);
}
private function set($opts = array()) {
if($opts) {
foreach($opts as $k => $v) {
switch($k) {
case 'http_auth':
$this->auth = $v;
break;
case 'magicauth':
// currently experimental
$this->magicauth = $v;
\Zotlabs\Daemon\Master::Summon([ 'CurlAuth', $v ]);
break;
case 'custom':
$this->request_method = $v;
break;
case 'url':
$this->url = $v;
break;
case 'data':
$this->set_data($v);
if($v) {
$this->upload = true;
}
else {
$this->upload = false;
}
break;
case 'headers':
$this->headers = $v;
break;
default:
$this->curlopts[$k] = $v;
break;
}
}
}
}
function exec() {
$opts = $this->curlopts;
$url = $this->url;
if($this->auth)
$opts['http_auth'] = $this->auth;
if($this->magicauth) {
$opts['cookiejar'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookiefile'] = 'store/[data]/cookie_' . $this->magicauth;
$opts['cookie'] = 'PHPSESSID=' . trim(file_get_contents('store/[data]/cookien_' . $this->magicauth));
$c = channelx_by_n($this->magicauth);
if($c)
$url = zid($this->url,channel_reddress($c));
}
if($this->custom)
$opts['custom'] = $this->custom;
if($this->headers)
$opts['headers'] = $this->headers;
if($this->upload) {
$opts['upload'] = true;
$opts['infile'] = $this->filehandle;
$opts['infilesize'] = strlen($this->request_data);
$opts['readfunc'] = [ $this, 'curl_read' ] ;
}
$recurse = 0;
return z_fetch_url($this->url,true,$recurse,(($opts) ? $opts : null));
}
}

View file

@ -31,7 +31,7 @@ class System {
if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('icon',App::$config['system'])) {
return App::$config['system']['icon'];
}
return z_root() . '/images/z-64.png';
return z_root() . '/images/z2-64.png';
}
@ -68,7 +68,7 @@ class System {
static public function get_project_link() {
if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['project_link'])
return App::$config['system']['project_link'];
return 'https://framagit.org/zot/zap';
return 'https://zotlabs.com/zap';
}
static public function get_project_srclink() {

View file

@ -2,6 +2,8 @@
namespace Zotlabs\Lib;
use App;
require_once('include/text.php');
/**
@ -36,9 +38,9 @@ class ThreadItem {
$this->data = $data;
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
$this->threaded = get_config('system','thread_allow',((defined('NOMADIC')) ? false : true));
$this->threaded = get_config('system','thread_allow',true);
$observer = \App::get_observer();
$observer = App::get_observer();
// Prepare the children
if($data['children']) {
@ -48,7 +50,7 @@ class ThreadItem {
* Only add those that will be displayed
*/
if((! visible_activity($item)) || array_key_exists('blocked',$item)) {
if(! visible_activity($item)) {
continue;
}
@ -116,7 +118,7 @@ class ThreadItem {
// logger('parent: ' . $item['thr_parent']);
}
$lock = ((($item['item_private'] == 1) || (($item['uid'] == local_channel()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
$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);
@ -132,7 +134,7 @@ class ThreadItem {
$privacy_warning = true;
}
if(($item['item_private'] == 1) && ($item['owner']['xchan_network'] === 'activitypub')) {
if(intval($item['item_private']) && ($item['owner']['xchan_network'] === 'activitypub')) {
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
@ -193,7 +195,6 @@ class ThreadItem {
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
}
// FIXME
if($observer_is_pageowner) {
$multidrop = array(
'select' => t('Select'),
@ -215,9 +216,8 @@ class ThreadItem {
$canvote = false;
// process action responses - e.g. like/dislike/attend/agree/whatever
$response_verbs = array('like');
// if(feature_enabled($conv->get_profile_owner(),'dislike'))
$response_verbs[] = 'dislike';
$response_verbs = [ 'like', 'dislike' ];
if($item['obj_type'] === ACTIVITY_OBJ_EVENT) {
$response_verbs[] = 'attendyes';
$response_verbs[] = 'attendno';
@ -239,9 +239,6 @@ class ThreadItem {
}
}
// if(! feature_enabled($conv->get_profile_owner(),'dislike'))
// unset($conv_responses['dislike']);
$responses = get_responses($conv_responses,$response_verbs,$this,$item);
$my_responses = [];
@ -257,19 +254,29 @@ class ThreadItem {
} else {
$like_list_part = '';
}
$like_button_label = tt('Like','Likes',$like_count,'noun');
if(get_config('system','show_like_counts',true)) {
$like_button_label = tt('Like','Likes',$like_count,'noun');
}
else {
$like_button_label = t('Likes','noun');
}
$dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
$dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : '');
if(get_config('system','show_like_counts',true)) {
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
}
else {
$dislike_button_label = t('Dislikes','noun');
}
if (($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$dislike_list_part = '';
}
// if (feature_enabled($conv->get_profile_owner(),'dislike')) {
$dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
$dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : '');
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
if (($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
$dislike_list_part = '';
}
// }
$showlike = ((x($conv_responses['like'],$item['mid'])) ? format_like($conv_responses['like'][$item['mid']],$conv_responses['like'][$item['mid'] . '-l'],'like',$item['mid']) : '');
$showdislike = ((x($conv_responses['dislike'],$item['mid']))
@ -284,7 +291,6 @@ class ThreadItem {
$this->check_wall_to_wall();
if($this->is_toplevel()) {
// FIXME check this permission
if(($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid',$item))) {
$star = array(
@ -304,8 +310,6 @@ class ThreadItem {
$unverified = '' ; // (($this->is_wall_to_wall() && (! intval($item['item_verified']))) ? t('Message cannot be verified') : '');
// FIXME - check this permission
if($conv->get_profile_owner() == local_channel()) {
$tagger = array(
'tagit' => t("Add Tag"),
@ -443,7 +447,9 @@ class ThreadItem {
'event' => $body['event'],
'has_tags' => $has_tags,
'reactions' => $this->reactions,
// Item toolbar buttons
// Item toolbar buttons
'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer) ? '1' : ''),
'like' => $like,
'dislike' => $dislike,
@ -456,11 +462,12 @@ class ThreadItem {
'tagger' => ((feature_enabled($conv->get_profile_owner(),'commtag')) ? $tagger : ''),
'filer' => ((feature_enabled($conv->get_profile_owner(),'filing')) ? $filer : ''),
'bookmark' => (($conv->get_profile_owner() == local_channel() && local_channel() && $has_bookmarks) ? t('Save Bookmarks') : ''),
'addtocal' => (($has_event) ? t('Add to Calendar') : ''),
'addtocal' => (($has_event && ! $item['resource_id']) ? t('Add to Calendar') : ''),
'drop' => $drop,
'multidrop' => ((feature_enabled($conv->get_profile_owner(),'multi_delete')) ? $multidrop : ''),
'dropdown_extras' => $dropdown_extras,
// end toolbar buttons
'dropdown_extras' => $dropdown_extras,
// end toolbar buttons
'unseen_comments' => $unseen_comments,
'comment_count' => $total_children,
@ -476,7 +483,7 @@ class ThreadItem {
'like_modal_title' => t('Likes','noun'),
'dislike_modal_title' => t('Dislikes','noun'),
'dislike_count' => $dislike_count,
'dislike_list' => $dislkie_list,
'dislike_list' => $dislike_list,
'dislike_list_part' => $dislike_list_part,
'dislike_button_label' => $dislike_button_label,
'modal_dismiss' => t('Close'),
@ -487,7 +494,8 @@ class ThreadItem {
'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
'thread_level' => $thread_level
'thread_level' => $thread_level,
'thread_max' => intval(get_config('system','thread_maxlevel',2)) + 1
);
$arr = array('item' => $item, 'output' => $tmp_item);
@ -495,22 +503,49 @@ class ThreadItem {
$result = $arr['output'];
$censored = false;
if(strpos($body['html'],"<button id=\"nsfw-wrap-") !== false && $collapse_all === false) {
$censored = true;
}
$censored = ((strpos($body['html'],"<button id=\"nsfw-wrap-") !== false && $collapse_all === false) ? true : false);
$result['children'] = [];
// place to store all the author addresses (links if not available) in the thread so we can auto-mention them in JS.
$result['authors'] = [];
$add_top_author = true;
if($observer && ($profile_addr === $observer['xchan_hash'] || $profile_addr === $observer['xchan_addr'])) {
$add_top_author = false;
}
if($add_top_author && (! defined('NOMADIC'))) {
$result['authors'][] = $profile_addr;
if (get_config('system','activitypub') && local_channel() && get_pconfig(local_channel(),'system','activitypub',true)) {
// place to store all the author addresses (links if not available) in the thread so we can auto-mention them in JS.
$result['authors'] = [];
// fix to add in sub-replies if replying to a comment on your own post from the top level.
if ($observer && ($profile_addr === $observer['xchan_hash'] || $profile_addr === $observer['xchan_addr'])) {
// ignore it
}
else {
$result['authors'][] = $profile_addr;
}
if ($children) {
foreach ($children as $child) {
$cdata = $child->get_data();
if ($cdata['author']['xchan_addr']) {
if (! in_array($cdata['author']['xchan_addr'],$result['authors'])) {
$result['authors'][] = $cdata['author']['xchan_addr'];
}
}
}
}
// Add any mentions from the immediate parent, unless they are mentions of the current viewer or duplicates
if ($item['term']) {
foreach ($item['term'] as $t) {
if ($t['ttype'] == TERM_MENTION) {
if (strpos($t['term'],'@') !== false) {
if ($observer && $t['term'] !== $observer['xchan_addr'] && ! in_array($t['term'],$result['authors'])) {
$result['authors'][] = $t['term'];
}
}
else {
$url = ((($position = strpos($t['url'],'url=')) !== false) ? urldecode(substr($t['url'],$position + 4)) : $t['url']);
if ($observer && $url !== $observer['xchan_url'] && ! in_array($url,$result['authors'])) {
$result['authors'][] = $url;
}
}
}
}
}
}
$nb_children = count($children);
@ -528,15 +563,6 @@ class ThreadItem {
if(strpos($xz['body'],"<button id=\"nsfw-wrap-") !== false && $collapse_all === false) {
$censored = true;
}
$author = $child->get_author();
if($author && ! in_array($author,$result['authors'])) {
if($observer && ($author === $observer['xchan_hash'] || $author === $observer['xchan_addr'])) {
// do nothing
}
elseif(! defined('NOMADIC')) {
$result['authors'][] = $author;
}
}
$result['children'][] = $xz;
}
// Collapse
@ -553,14 +579,6 @@ class ThreadItem {
}
}
if(count($result['authors']) > 6) {
$slice = array_slice($result['authors'],0,3);
$slice2 = array_slice($result['authors'],-3,3);
$result['authors'] = array_merge($slice,$slice2);
}
//logger('authors: ' . print_r($result['authors'],true));
$result['private'] = $item['item_private'];
$result['toplevel'] = ($this->is_toplevel() ? 'toplevel_item' : '');
@ -637,6 +655,7 @@ class ThreadItem {
logger('[WARN] Item::add_child : Item already exists ('. $item->get_id() .').', LOGGER_DEBUG);
return false;
}
/*
* Only add what will be displayed
*/
@ -653,6 +672,7 @@ class ThreadItem {
/**
* Get a child by its ID
*/
public function get_child($id) {
foreach($this->get_children() as $child) {
if($child->get_id() == $id)
@ -664,6 +684,7 @@ class ThreadItem {
/**
* Get all our children
*/
public function get_children() {
return $this->children;
}
@ -683,6 +704,7 @@ class ThreadItem {
/**
* Remove our parent
*/
protected function remove_parent() {
$this->parent = null;
$this->conversation = null;
@ -691,6 +713,7 @@ class ThreadItem {
/**
* Remove a child
*/
public function remove_child($item) {
$id = $item->get_id();
foreach($this->get_children() as $key => $child) {
@ -803,7 +826,7 @@ class ThreadItem {
$total = count($children);
if($total > 0) {
foreach($children as $child) {
if((! visible_activity($child->data)) || array_key_exists('blocked',$child->data)) {
if(! visible_activity($child->data)) {
continue;
}
if(! array_key_exists('sequence',$this->data)) {
@ -822,7 +845,7 @@ class ThreadItem {
if($total > 0) {
$total = 0;
foreach($children as $child) {
if((! visible_activity($child->data)) || array_key_exists('author_blocked',$child->data)) {
if(! visible_activity($child->data)) {
continue;
}
if(intval($child->data['item_unseen']))
@ -849,7 +872,7 @@ class ThreadItem {
*/
private function get_comment_box($indent) {
if(!$this->is_toplevel() && !get_config('system','thread_allow',((defined('NOMADIC')) ? false : true))) {
if(!$this->is_toplevel() && !get_config('system','thread_allow',true)) {
return '';
}
@ -885,7 +908,7 @@ class ThreadItem {
'$myphoto' => $observer['xchan_photo_s'],
'$comment' => t('Comment'),
'$submit' => t('Submit'),
'$edat' => ((defined('NOMADIC')) ? '' : t('Add Conversation Mentions')),
'$edat' => EMPTY_STR,
'$edbold' => t('Bold'),
'$editalic' => t('Italic'),
'$eduline' => t('Underline'),
@ -895,13 +918,13 @@ class ThreadItem {
'$edatt' => t('Attach/Upload file'),
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
'$preview' => t('Preview'),
'$indent' => $indent,
'$can_upload' => (perm_is_allowed($conv->get_profile_owner(),get_observer_hash(),'write_storage') && $conv->is_uploadable()),
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
'$cipher' => $conv->get_cipher(),
'$sourceapp' => \App::$sourcename,
'$sourceapp' => App::$sourcename,
'$observer' => get_observer_hash(),
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
'$anonname' => [ 'anonname', t('Your full name (required)') ],
@ -936,8 +959,46 @@ class ThreadItem {
$this->owner_name = $this->data['owner']['xchan_name'];
$this->wall_to_wall = true;
}
// present friend-of-friend conversations from hyperdrive as relayed posts from the first friend
// we find among the respondents.
if ($this->is_toplevel() && (! $this->data['owner']['abook_id'])) {
if ($this->data['children']) {
$friend = $this->find_a_friend($this->data['children']);
if ($friend) {
$this->owner_url = $friend['url'];
$this->owner_photo = $friend['photo'];
$this->owner_name = $friend['name'];
$this->wall_to_wall = true;
}
}
}
}
private function find_a_friend($items) {
$ret = null;
if ($items) {
foreach ($items as $child) {
if ($child['author']['abook_id'] && (! intval($child['author']['abook_self']))) {
return [
'url' => chanlink_hash($child['author']['xchan_hash']),
'photo' => $child['author']['xchan_photo_m'],
'name' => $child['author']['xchan_name']
];
if ($child['children']) {
$ret = $this->find_a_friend($child['children']);
if ($ret) {
break;
}
}
}
}
}
return $ret;
}
private function is_wall_to_wall() {
return $this->wall_to_wall;
}

View file

@ -85,7 +85,9 @@ class Acl extends \Zotlabs\Web\Controller {
if($search) {
$sql_extra = " AND pgrp.gname LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ";
$sql_extra2 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") ";
// This horrible mess is needed because position also returns 0 if nothing is found.
// Would be MUCH easier if it instead returned a very large value
// Otherwise we could just
@ -96,11 +98,14 @@ class Acl extends \Zotlabs\Web\Controller {
. " then POSITION('" . protect_sprintf(dbesc($search))
. "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, ";
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) ";
$sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR ( xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR abook_alias like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " )) ";
$sql_extra4 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . " OR abook_alias LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'") . ") ";
}
else {
$sql_extra = $sql_extra2 = $sql_extra3 = "";
$sql_extra = $sql_extra2 = $sql_extra3 = $sql_extra4 = "";
}
@ -145,14 +150,14 @@ class Acl extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $g){
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan($g['id']));
// logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(),$g['id']));
$groups[] = array(
"type" => "g",
"photo" => "images/twopeople.png",
"name" => $g['gname'],
"id" => $g['id'],
"xid" => $g['hash'],
"uids" => AccessList::members_xchan($g['id']),
"uids" => AccessList::members_xchan(local_channel(),$g['id']),
"link" => ''
);
}
@ -214,13 +219,14 @@ class Acl extends \Zotlabs\Web\Controller {
}
// add connections
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, xchan_type, abook_flags, abook_self
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra4 order by xchan_name asc" ,
intval(local_channel())
);
if($r2)
if($r && $r2)
$r = array_merge($r2,$r);
}
@ -318,7 +324,7 @@ class Acl extends \Zotlabs\Web\Controller {
$contacts[] = array(
"photo" => $g['photo'],
"name" => $g['name'],
"nick" => $g['address']
"nick" => $g['address'],
);
}
}
@ -418,7 +424,9 @@ class Acl extends \Zotlabs\Web\Controller {
if(strpos($search,'@') !== false) {
$address = true;
}
$remote_dir = false;
if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) {
$url = z_root() . '/dirsearch';
}
@ -426,6 +434,7 @@ class Acl extends \Zotlabs\Web\Controller {
if(! $url) {
$directory = Libzotdir::find_upstream_directory($dirmode);
$url = $directory['url'] . '/dirsearch';
$remote_dir = true;
}
$token = get_config('system','realm_token');
@ -440,11 +449,41 @@ class Acl extends \Zotlabs\Web\Controller {
$t = 0;
$j = json_decode($x['body'],true);
if($j && $j['results']) {
return $j['results'];
$results = $j['results'];
}
}
}
return array();
if($remote_dir) {
$query = z_root() . '/dirsearch' . '?f=&navsearch=1' . (($token) ? '&t=' . urlencode($token) : '');
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
$x = z_fetch_url($query);
if($x['success']) {
$t = 0;
$j = json_decode($x['body'],true);
if($j && $j['results']) {
$results2 = $j['results'];
}
}
}
if($results2 && $results) {
foreach($results2 as $x) {
$found = false;
foreach($results as $y) {
if($y['url'] === $x['url']) {
$found = true;
}
}
if (! $found) {
$x['local'] = true;
$results[] = $x;
}
}
}
return $results;
}
}

View file

@ -1,28 +1,59 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity as ZActivity;
use Zotlabs\Lib\Activity as ZlibActivity;
class Activity extends \Zotlabs\Web\Controller {
class Activity extends Controller {
function init() {
if(ActivityStreams::is_as_request()) {
if (ActivityStreams::is_as_request()) {
$item_id = argv(1);
if(! $item_id)
if (! $item_id) {
return;
}
$ob_authorise = false;
$item_uid = 0;
$bear = ZlibActivity::token_from_request();
if ($bear) {
logger('bear: ' . $bear, LOGGER_DEBUG);
$t = q("select item.uid, iconfig.v from iconfig left join item on iid = item.id where cat = 'ocap' and item.uuid = '%s'",
dbesc($item_id)
);
if ($t) {
foreach ($t as $token) {
if ($token['v'] === $bear) {
$ob_authorize = true;
$item_uid = $token['uid'];
break;
}
}
}
}
$item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0
and item.item_delayed = 0 and item.item_blocked = 0 ";
$sql_extra = item_permissions_sql(0);
$r = q("select * from item where uuid = '%s' $item_normal $sql_extra limit 1",
// if passed an owner_id of 0 to item_permissions_sql(), we force "guest access" or observer checking
// Give ocap tokens priority
if ($ob_authorize) {
$sql_extra = " and item.uid = " . intval($token['uid']) . " ";
}
else {
$sql_extra = item_permissions_sql(0);
}
$r = q("select * from item where uuid = '%s' $item_normal $sql_extra and item_deleted = 0 limit 1",
dbesc($item_id)
);
if(! $r) {
if (! $r) {
$r = q("select * from item where uuid = '%s' $item_normal limit 1",
dbesc($item_id)
);
@ -38,12 +69,11 @@ class Activity extends \Zotlabs\Web\Controller {
$channel = channelx_by_n($items[0]['uid']);
$x = array_merge(['@context' => [
$x = array_merge( ['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], ZActivity::encode_activity($items[0]));
]], ZlibActivity::encode_activity($items[0]));
$headers = [];
@ -59,7 +89,7 @@ class Activity extends \Zotlabs\Web\Controller {
killme();
}
goaway(z_root() . '/item/' . argv(1));
}
}

View file

@ -2,7 +2,7 @@
namespace Zotlabs\Module\Admin;
use App;
class Accounts {
@ -23,19 +23,20 @@ class Accounts {
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
// change to switch structure?
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
for ($i = 0; $i < count($users); $i++) {
// if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag
$op = ($blocked[$i]) ? '& ~' : '| ';
q("UPDATE account SET account_flags = (account_flags $op%d) WHERE account_id = %d",
q("UPDATE account SET account_flags = (account_flags $op %d) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($users[$i])
);
}
notice( sprintf( tt("%s account blocked/unblocked", "%s account blocked/unblocked", count($users)), count($users)) );
}
// account delete button was submitted
if (x($_POST, 'page_accounts_delete')) {
foreach ($users as $uid){
@ -43,12 +44,14 @@ class Accounts {
}
notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) );
}
// registration approved button was submitted
if (x($_POST, 'page_accounts_approve')) {
foreach ($pending as $hash) {
account_allow($hash);
}
}
// registration deny button was submitted
if (x($_POST, 'page_accounts_deny')) {
foreach ($pending as $hash) {
@ -83,7 +86,7 @@ class Accounts {
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't');
switch (argv(2)){
switch (argv(2)) {
case 'delete':
// delete user
account_remove($uid,true,false);
@ -99,9 +102,9 @@ class Accounts {
notice( sprintf( t("Account '%s' blocked") , $account[0]['account_email']) . EOL);
break;
case 'unblock':
q("UPDATE account SET account_flags = ( account_flags & ~%d ) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($uid)
q("UPDATE account SET account_flags = ( account_flags & ~ %d ) WHERE account_id = %d",
intval(ACCOUNT_BLOCKED),
intval($uid)
);
notice( sprintf( t("Account '%s' unblocked"), $account[0]['account_email']) . EOL);
@ -112,7 +115,7 @@ class Accounts {
}
/* get pending */
$pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d )>0 ",
$pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) != 0 ",
intval(ACCOUNT_PENDING)
);
@ -120,17 +123,18 @@ class Accounts {
$total = q("SELECT count(*) as total FROM account");
if (count($total)) {
\App::set_pager_total($total[0]['total']);
\App::set_pager_itemspage(100);
App::set_pager_total($total[0]['total']);
App::set_pager_itemspage(100);
}
$serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : '');
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id');
$dir = 'asc';
if(array_key_exists('dir',$_REQUEST))
if (array_key_exists('dir',$_REQUEST)) {
$dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');
}
$base = z_root() . '/admin/accounts?f=';
$odir = (($dir === 'asc') ? '0' : '1');
@ -140,29 +144,25 @@ class Accounts {
intval(ACCOUNT_BLOCKED),
db_concat('ch.channel_address', ' '),
intval(ACCOUNT_BLOCKED | ACCOUNT_PENDING),
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
// function _setup_users($e){
// $accounts = Array(
// t('Normal Account'),
// t('Soapbox Account'),
// t('Community/Celebrity Account'),
// t('Automatic Friend Account')
// );
// $e['page_flags'] = $accounts[$e['page-flags']];
// $e['register_date'] = relative_date($e['register_date']);
// $e['login_date'] = relative_date($e['login_date']);
// $e['lastitem_date'] = relative_date($e['lastitem_date']);
// return $e;
// }
// $users = array_map("_setup_users", $users);
$t = get_markup_template('admin_accounts.tpl');
$o = replace_macros($t, array(
// strings //
if ($users) {
for($x = 0; $x < count($users); $x ++) {
$channel_arr = explode(' ',$users[$x]['channels']);
if ($channel_arr) {
$linked = [];
foreach ( $channel_arr as $c) {
$linked[] = '<a href="' . z_root() . '/channel/' . $c . '">' . $c . '</a>';
}
$users[$x]['channels'] = implode(' ',$linked);
}
}
}
$t =
$o = replace_macros(get_markup_template('admin_accounts.tpl'), [
'$title' => t('Administration'),
'$page' => t('Accounts'),
'$submit' => t('Submit'),
@ -178,30 +178,25 @@ class Accounts {
'$odir' => $odir,
'$base' => $base,
'$h_users' => t('Accounts'),
'$th_users' => array(
'$th_users' => [
[ t('ID'), 'account_id' ],
[ t('Email'), 'account_email' ],
[ t('All Channels'), 'channels' ],
[ t('Register date'), 'account_created' ],
[ t('Last login'), 'account_lastlog' ],
[ t('Expires'), 'account_expires' ],
[ t('Service Class'), 'account_service_class'] ),
[ t('Service Class'), 'account_service_class']
],
'$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
'$form_security_token' => get_form_security_token("admin_accounts"),
// values //
'$baseurl' => z_root(),
'$pending' => $pending,
'$users' => $users,
));
]);
$o .= paginate($a);
return $o;
}
}

View file

@ -2,6 +2,8 @@
namespace Zotlabs\Module\Admin;
use Zotlabs\Daemon\Master;
/**
* @brief Admin Module for Channels.
*
@ -26,7 +28,7 @@ class Channels {
intval(PAGE_CENSORED),
intval( $uid )
);
\Zotlabs\Daemon\Master::Summon(array('Directory', $uid, 'nopush'));
Master::Summon( [ 'Directory', $uid, 'nopush' ] );
}
notice( sprintf( tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels)) );
}
@ -82,7 +84,7 @@ class Channels {
intval($pflags),
intval( $uid )
);
\Zotlabs\Daemon\Master::Summon(array('Directory',$uid,'nopush'));
Master::Summon( [ 'Directory', $uid, 'nopush' ]);
notice( sprintf( (($pflags & PAGE_CENSORED) ? t("Channel '%s' censored"): t("Channel '%s' uncensored")) , $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')' ) . EOL);
}; break;

View file

@ -29,7 +29,7 @@ class Site {
$admininfo = ((x($_POST,'admininfo')) ? trim($_POST['admininfo']) : false);
$siteinfo = ((x($_POST,'siteinfo')) ? trim($_POST['siteinfo']) : '');
$language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : '');
$language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : 'en');
$theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : '');
// $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
// $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
@ -53,7 +53,6 @@ class Site {
}
$mirror_frontpage = ((x($_POST,'mirror_frontpage')) ? intval(trim($_POST['mirror_frontpage'])) : 0);
$directory_server = ((x($_POST,'directory_server')) ? trim($_POST['directory_server']) : '');
$allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : '');
$force_publish = ((x($_POST,'publish_all')) ? True : False);
$disable_discover_tab = ((x($_POST,'disable_discover_tab')) ? False : True);
$site_firehose = ((x($_POST,'site_firehose')) ? True : False);
@ -73,11 +72,13 @@ class Site {
$proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : '');
$proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : '');
$timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['timeout'])) : 60);
$show_like_counts = ((x($_POST,'show_like_counts')) ? intval(trim($_POST['show_like_counts'])) : 0);
$delivery_interval = ((x($_POST,'delivery_interval'))? intval(trim($_POST['delivery_interval'])) : 0);
$delivery_batch_count = ((x($_POST,'delivery_batch_count') && $_POST['delivery_batch_count'] > 0)? intval(trim($_POST['delivery_batch_count'])) : 3);
$poll_interval = ((x($_POST,'poll_interval')) ? intval(trim($_POST['poll_interval'])) : 0);
$maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50);
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$ap_contacts = ((x($_POST,'ap_contacts')) ? intval($_POST['ap_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
@ -88,6 +89,7 @@ class Site {
$permissions_role = escape_tags(trim($_POST['permissions_role']));
set_config('system', 'feed_contacts', $feed_contacts);
set_config('system', 'activitypub', $ap_contacts);
set_config('system', 'delivery_interval', $delivery_interval);
set_config('system', 'delivery_batch_count', $delivery_batch_count);
set_config('system', 'poll_interval', $poll_interval);
@ -109,6 +111,7 @@ class Site {
set_config('system', 'imagick_convert_path' , $imagick_path);
set_config('system', 'thumbnail_security' , $thumbnail_security);
set_config('system', 'default_permissions_role', $permissions_role);
set_config('system', 'show_like_counts', $show_like_counts);
set_config('system', 'pubstream_incl',$pub_incl);
set_config('system', 'pubstream_excl',$pub_excl);
@ -144,7 +147,6 @@ class Site {
set_config('system','access_policy', $access_policy);
set_config('system','account_abandon_days', $abandon_days);
set_config('system','register_text', $register_text);
set_config('system','allowed_sites', $allowed_sites);
set_config('system','publish_all', $force_publish);
set_config('system','disable_discover_tab', $disable_discover_tab);
set_config('system','site_firehose', $site_firehose);
@ -177,10 +179,10 @@ class Site {
/* Installed langs */
$lang_choices = array();
$langs = glob('view/*/hstrings.php');
$langs = glob('view/*/strings.php');
if (is_array($langs) && count($langs)) {
if (! in_array('view/en/hstrings.php',$langs))
if (! in_array('view/en/strings.php',$langs))
$langs[] = 'view/en/';
asort($langs);
foreach ($langs as $l) {
@ -302,11 +304,12 @@ class Site {
'$banner' => [ 'banner', t("Banner/Logo"), $banner, t('Unfiltered HTML/CSS/JS is allowed') ],
'$admininfo' => [ 'admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode may be used here.") ],
'$siteinfo' => [ 'siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode may be used here.") ],
'$language' => [ 'language', t("System language"), get_config('system','language'), "", $lang_choices ],
'$language' => [ 'language', t("System language"), get_config('system','language','en'), "", $lang_choices ],
'$theme' => [ 'theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices ],
// '$theme_mobile' => [ 'theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile ],
// '$site_channel' => [ 'site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel") ],
'$feed_contacts' => [ 'feed_contacts', t('Allow Feeds as Connections'),get_config('system','feed_contacts'),t('(Heavy system resource usage)') ],
'$ap_contacts' => [ 'ap_contacts', t('Allow ActivityPub Connections'),get_config('system','activitypub'),t('Experimental and unsupported. ActivityPub does not fully support privacy and account mobility.') ],
'$maximagesize' => [ 'maximagesize', t("Maximum image size"), intval(get_config('system','maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.") ],
'$register_policy' => [ 'register_policy', t("Does this site allow new member registration?"), get_config('system','register_policy'), "", $register_choices ],
'$invite_only' => [ 'invite_only', t("Invitation only"), get_config('system','invitation_only'), t("Only allow new member registrations with an invitation code. New member registration must be allowed for this to work.") ],
@ -317,12 +320,12 @@ class Site {
'$frontpage' => [ 'frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.") ],
'$mirror_frontpage' => [ 'mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting') ],
'$abandon_days' => [ 'abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.') ],
'$allowed_sites' => [ 'allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains") ],
'$verify_email' => [ 'verify_email', t("Verify Email Addresses"), get_config('system','verify_email'), t("Check to verify email addresses used in account registration (recommended).") ],
'$force_publish' => [ 'publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.") ],
'$disable_discover_tab' => [ 'disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.') ],
'$site_firehose' => [ 'site_firehose', t('Site only Public Streams'), get_config('system','site_firehose'), t('Allow access to public content originating only from this site if Imported Public Streams are disabled.') ],
'$open_pubstream' => [ 'open_pubstream', t('Allow anybody on the internet to access the Public streams'), get_config('system','open_pubstream',0), t('Default is to only allow viewing by site members. Warning: this content is unmoderated.') ],
'$show_like_counts' => [ 'show_like_counts', t('Show numbers of likes and dislikes in conversations'), get_config('system','show_like_counts',1), t('If disabled, the presence of likes and dislikes will be shown, but without totals.') ],
'$incl' => [ 'pub_incl',t('Only import Public stream posts with this text'), get_config('system','pubstream_incl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts') ],
'$excl' => [ 'pub_excl',t('Do not import Public stream posts with this text'), get_config('system','pubstream_excl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts') ],
'$login_on_homepage' => [ 'login_on_homepage', t("Login on Homepage"),((intval($homelogin) || $homelogin === false) ? 1 : '') , t("Present a login box to visitors on the home page if no other content has been configured.") ],
@ -341,7 +344,7 @@ class Site {
'$imagick_path' => [ 'imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert") ],
'$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ],
'$maxloadavg' => [ 'maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.") ],
'$default_expire_days' => [ 'default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content') ],
'$default_expire_days' => [ 'default_expire_days', t('Expiration period in days for imported streams'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content') ],
'$active_expire_days' => [ 'active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), '' ],
'$sellpage' => [ 'site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system','sellpage',''), sprintf( t('Create this page first. Default is %s/register'),z_root()) ],
'$first_page' => [ 'first_page', t('Page to display after creating a new channel'), get_config('system','workflow_channel_next','profiles'), t('Default: profiles') ],

View file

@ -9,7 +9,7 @@ class Affinity extends \Zotlabs\Web\Controller {
function post() {
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Affinity Tool'))) {
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Friend Zoom'))) {
return;
}
@ -23,7 +23,7 @@ class Affinity extends \Zotlabs\Web\Controller {
set_pconfig(local_channel(),'affinity','cmin',0);
set_pconfig(local_channel(),'affinity','cmax',$cmax);
info( t('Affinity Tool settings updated.') . EOL);
info( t('Friend Zoom settings updated.') . EOL);
}
@ -34,11 +34,11 @@ class Affinity extends \Zotlabs\Web\Controller {
function get() {
$desc = t('This app (when installed) presents a slider control in your connection editor and also on your network page. The slider represents your degree of friendship or <em>affinity</em> with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream.');
$desc = t('This app (when installed) presents a slider control in your connection editor and also on your network page. The slider represents your degree of friendship with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream.');
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Affinity Tool'))) {
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Friend Zoom'))) {
return $text;
}
@ -52,7 +52,7 @@ class Affinity extends \Zotlabs\Web\Controller {
// '$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, t('0-99 default 99'))
// ));
if(Apps::system_app_installed(local_channel(),'Affinity Tool')) {
if(Apps::system_app_installed(local_channel(),'Friend Zoom')) {
$labels = array(
0 => t('Me'),
@ -80,7 +80,7 @@ class Affinity extends \Zotlabs\Web\Controller {
}
$s .= replace_macros(get_markup_template('generic_app_settings.tpl'), array(
'$addon' => array('affinity', '' . t('Affinity Tool Settings'), '', t('Submit')),
'$addon' => array('affinity', '' . t('Friend Zoom Settings'), '', t('Submit')),
'$content' => $setting_fields
));

View file

@ -1,279 +0,0 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\AccessList;
class Alist extends \Zotlabs\Web\Controller {
function init() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
\App::$profile_uid = local_channel();
nav_set_selected('Access Lists');
}
function post() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
if((argc() == 2) && (argv(1) === 'new')) {
check_form_security_token_redirectOnErr('/alist/new', 'group_edit');
$name = notags(trim($_POST['groupname']));
$public = intval($_POST['public']);
$r = AccessList::add(local_channel(),$name,$public);
if($r) {
info( t('Access list created.') . EOL );
}
else {
notice( t('Could not create access list.') . EOL );
}
goaway(z_root() . '/alist');
}
if((argc() == 2) && (intval(argv(1)))) {
check_form_security_token_redirectOnErr('/alist', 'group_edit');
$r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1",
intval(argv(1)),
intval(local_channel())
);
if(! $r) {
notice( t('Access list not found.') . EOL );
goaway(z_root() . '/connections');
}
$group = $r[0];
$groupname = notags(trim($_POST['groupname']));
$public = intval($_POST['public']);
if((strlen($groupname)) && (($groupname != $group['gname']) || ($public != $group['visible']))) {
$r = q("UPDATE pgrp SET gname = '%s', visible = %d WHERE uid = %d AND id = %d",
dbesc($groupname),
intval($public),
intval(local_channel()),
intval($group['id'])
);
if($r)
info( t('Access list updated.') . EOL );
Libsync::build_sync_packet(local_channel(),null,true);
}
goaway(z_root() . '/alist/' . argv(1) . '/' . argv(2));
}
return;
}
function get() {
$change = false;
logger('mod_alist: ' . \App::$cmd,LOGGER_DEBUG);
if(! local_channel()) {
notice( t('Permission denied') . EOL);
return;
}
// Switch to text mode interface if we have more than 'n' contacts or group members
$switchtotext = get_pconfig(local_channel(),'system','groupedit_image_limit');
if($switchtotext === false)
$switchtotext = get_config('system','groupedit_image_limit');
if($switchtotext === false)
$switchtotext = 400;
if((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) {
$new = (((argc() == 2) && (argv(1) === 'new')) ? true : false);
$groups = q("SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
$i = 0;
foreach($groups as $group) {
$entries[$i]['name'] = $group['gname'];
$entries[$i]['id'] = $group['id'];
$entries[$i]['count'] = count(AccessList::members($group['id']));
$i++;
}
$tpl = get_markup_template('privacy_groups.tpl');
$o = replace_macros($tpl, [
'$title' => t('Access Lists'),
'$add_new_label' => t('Create access list'),
'$new' => $new,
// new group form
'$gname' => array('groupname',t('Access list name')),
'$public' => array('public',t('Members are visible to other channels'), false),
'$form_security_token' => get_form_security_token("group_edit"),
'$submit' => t('Submit'),
// groups list
'$title' => t('Access Lists'),
'$name_label' => t('Name'),
'$count_label' => t('Members'),
'$entries' => $entries
]);
return $o;
}
$context = array('$submit' => t('Submit'));
$tpl = get_markup_template('group_edit.tpl');
if((argc() == 3) && (argv(1) === 'drop')) {
check_form_security_token_redirectOnErr('/alist', 'group_drop', 't');
if(intval(argv(2))) {
$r = q("SELECT gname FROM pgrp WHERE id = %d AND uid = %d LIMIT 1",
intval(argv(2)),
intval(local_channel())
);
if($r)
$result = AccessList::remove(local_channel(),$r[0]['gname']);
if($result)
info( t('Access list removed.') . EOL);
else
notice( t('Unable to remove access list.') . EOL);
}
goaway(z_root() . '/alist');
// NOTREACHED
}
if((argc() > 2) && intval(argv(1)) && argv(2)) {
check_form_security_token_ForbiddenOnErr('group_member_change', 't');
$r = q("SELECT abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 limit 1",
dbesc(base64url_decode(argv(2))),
intval(local_channel())
);
if(count($r))
$change = base64url_decode(argv(2));
}
if((argc() > 1) && (intval(argv(1)))) {
require_once('include/acl_selectors.php');
$r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1",
intval(argv(1)),
intval(local_channel())
);
if(! $r) {
notice( t('Access list not found.') . EOL );
goaway(z_root() . '/connections');
}
$group = $r[0];
$members = AccessList::members($group['id']);
$preselected = array();
if(count($members)) {
foreach($members as $member)
if(! in_array($member['xchan_hash'],$preselected))
$preselected[] = $member['xchan_hash'];
}
if($change) {
if(in_array($change,$preselected)) {
AccessList::member_remove(local_channel(),$group['gname'],$change);
}
else {
AccessList::member_add(local_channel(),$group['gname'],$change);
}
$members = AccessList::members($group['id']);
$preselected = array();
if(count($members)) {
foreach($members as $member)
$preselected[] = $member['xchan_hash'];
}
}
$context = $context + array(
'$title' => sprintf(t('Access List: %s'), $group['gname']),
'$details_label' => t('Edit'),
'$gname' => array('groupname',t('Access list name: '),$group['gname'], ''),
'$gid' => $group['id'],
'$drop' => $drop_txt,
'$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''),
'$form_security_token_edit' => get_form_security_token('group_edit'),
'$delete' => t('Delete access list'),
'$form_security_token_drop' => get_form_security_token("group_drop"),
);
}
if(! isset($group))
return;
$groupeditor = array(
'label_members' => t('List members'),
'members' => array(),
'label_contacts' => t('Not in this list'),
'contacts' => array(),
);
$sec_token = addslashes(get_form_security_token('group_member_change'));
$textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : 'card');
foreach($members as $member) {
if($member['xchan_url']) {
$member['archived'] = (intval($member['abook_archived']) ? true : false);
$member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;';
$groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode);
}
else
AccessList::member_remove(local_channel(),$group['gname'],$member['xchan_hash']);
}
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_self = 0 and abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc",
intval(local_channel())
);
if(count($r)) {
$textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : 'card');
foreach($r as $member) {
if(! in_array($member['xchan_hash'],$preselected)) {
$member['archived'] = (intval($member['abook_archived']) ? true : false);
$member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;';
$groupeditor['contacts'][] = micropro($member,true,'mpall', $textmode);
}
}
}
$context['$groupeditor'] = $groupeditor;
$context['$desc'] = t('Click a channel to toggle membership');
if($change) {
$tpl = get_markup_template('groupeditor.tpl');
echo replace_macros($tpl, $context);
killme();
}
return replace_macros($tpl, $context);
}
}

View file

@ -1,116 +1,113 @@
<?php /** @file */
<?php
namespace Zotlabs\Module;
//require_once('include/apps.php');
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
use \Zotlabs\Lib as Zlib;
class Appman extends \Zotlabs\Web\Controller {
class Appman extends Controller {
function post() {
if(! local_channel())
if (! local_channel()) {
return;
}
if($_POST['url']) {
$arr = array(
'uid' => intval($_REQUEST['uid']),
'url' => escape_tags($_REQUEST['url']),
'guid' => escape_tags($_REQUEST['guid']),
'author' => escape_tags($_REQUEST['author']),
'addr' => escape_tags($_REQUEST['addr']),
'name' => escape_tags($_REQUEST['name']),
'desc' => escape_tags($_REQUEST['desc']),
'photo' => escape_tags($_REQUEST['photo']),
'version' => escape_tags($_REQUEST['version']),
'price' => escape_tags($_REQUEST['price']),
'page' => escape_tags($_REQUEST['page']),
'requires' => escape_tags($_REQUEST['requires']),
'system' => intval($_REQUEST['system']),
'plugin' => escape_tags($_REQUEST['plugin']),
'sig' => escape_tags($_REQUEST['sig']),
if ($_POST['url']) {
$arr = [
'uid' => intval($_REQUEST['uid']),
'url' => escape_tags($_REQUEST['url']),
'guid' => escape_tags($_REQUEST['guid']),
'author' => escape_tags($_REQUEST['author']),
'addr' => escape_tags($_REQUEST['addr']),
'name' => escape_tags($_REQUEST['name']),
'desc' => escape_tags($_REQUEST['desc']),
'photo' => escape_tags($_REQUEST['photo']),
'version' => escape_tags($_REQUEST['version']),
'price' => escape_tags($_REQUEST['price']),
'page' => escape_tags($_REQUEST['sellpage']), // do not use 'page' as a request variable here as it conflicts with pagination
'requires' => escape_tags($_REQUEST['requires']),
'system' => intval($_REQUEST['system']),
'plugin' => escape_tags($_REQUEST['plugin']),
'sig' => escape_tags($_REQUEST['sig']),
'categories' => escape_tags($_REQUEST['categories'])
);
];
$_REQUEST['appid'] = Zlib\Apps::app_install(local_channel(),$arr);
$_REQUEST['appid'] = Apps::app_install(local_channel(),$arr);
if(Zlib\Apps::app_installed(local_channel(),$arr))
if (Apps::app_installed(local_channel(),$arr)) {
info( t('App installed.') . EOL);
}
goaway(z_root() . '/apps');
return; //not reached
}
$papp = Zlib\Apps::app_decode($_POST['papp']);
$papp = Apps::app_decode($_POST['papp']);
if(! is_array($papp)) {
if (! is_array($papp)) {
notice( t('Malformed app.') . EOL);
return;
}
if($_POST['install']) {
Zlib\Apps::app_install(local_channel(),$papp);
if(Zlib\Apps::app_installed(local_channel(),$papp))
if ($_POST['install']) {
Apps::app_install(local_channel(),$papp);
if (Apps::app_installed(local_channel(),$papp))
info( t('App installed.') . EOL);
}
if($_POST['delete']) {
Zlib\Apps::app_destroy(local_channel(),$papp);
if ($_POST['delete']) {
Apps::app_destroy(local_channel(),$papp);
}
if($_POST['edit']) {
if ($_POST['edit']) {
return;
}
if($_POST['feature']) {
Zlib\Apps::app_feature(local_channel(), $papp, $_POST['feature']);
if ($_POST['feature']) {
Apps::app_feature(local_channel(), $papp, $_POST['feature']);
}
if($_POST['pin']) {
Zlib\Apps::app_feature(local_channel(), $papp, $_POST['pin']);
if ($_POST['pin']) {
Apps::app_feature(local_channel(), $papp, $_POST['pin']);
}
if($_SESSION['return_url'])
if ($_SESSION['return_url']) {
goaway(z_root() . '/' . $_SESSION['return_url']);
}
goaway(z_root() . '/apps');
}
function get() {
if(! local_channel()) {
if (! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
if(argc() > 3) {
if (argc() > 3) {
if(argv(2) === 'moveup') {
Zlib\Apps::moveup(local_channel(),argv(1),argv(3));
Apps::moveup(local_channel(),argv(1),argv(3));
}
if(argv(2) === 'movedown') {
Zlib\Apps::movedown(local_channel(),argv(1),argv(3));
Apps::movedown(local_channel(),argv(1),argv(3));
}
goaway(z_root() . '/apporder');
}
$app = null;
$embed = null;
if($_REQUEST['appid']) {
if ($_REQUEST['appid']) {
$r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($_REQUEST['appid']),
dbesc(local_channel())
);
if($r) {
if ($r) {
$app = $r[0];
$term = q("select * from term where otype = %d and oid = %d and uid = %d",
@ -118,41 +115,34 @@ class Appman extends \Zotlabs\Web\Controller {
intval($r[0]['id']),
intval(local_channel())
);
if($term) {
$app['categories'] = '';
foreach($term as $t) {
if($app['categories'])
$app['categories'] .= ',';
$app['categories'] .= $t['term'];
}
if ($term) {
$app['categories'] = array_elm_to_str($term,'term');
}
}
$embed = array('embed', t('Embed code'), Zlib\Apps::app_encode($app,true),'', 'onclick="this.select();"');
$embed = [ 'embed', t('Embed code'), Apps::app_encode($app,true), EMPTY_STR, 'onclick="this.select();"' ];
}
return replace_macros(get_markup_template('app_create.tpl'), array(
'$banner' => (($app) ? t('Edit App') : t('Create App')),
'$app' => $app,
'$guid' => (($app) ? $app['app_id'] : ''),
'$author' => (($app) ? $app['app_author'] : $channel['channel_hash']),
'$addr' => (($app) ? $app['app_addr'] : $channel['xchan_addr']),
'$name' => array('name', t('Name of app'),(($app) ? $app['app_name'] : ''), t('Required')),
'$url' => array('url', t('Location (URL) of app'),(($app) ? $app['app_url'] : ''), t('Required')),
'$desc' => array('desc', t('Description'),(($app) ? $app['app_desc'] : ''), ''),
'$photo' => array('photo', t('Photo icon URL'),(($app) ? $app['app_photo'] : ''), t('80 x 80 pixels - optional')),
'$categories' => array('categories',t('Categories (optional, comma separated list)'),(($app) ? $app['categories'] : ''),''),
'$version' => array('version', t('Version ID'),(($app) ? $app['app_version'] : ''), ''),
'$price' => array('price', t('Price of app'),(($app) ? $app['app_price'] : ''), ''),
'$page' => array('page', t('Location (URL) to purchase app'),(($app) ? $app['app_page'] : ''), ''),
'$system' => (($app) ? intval($app['app_system']) : 0),
'$plugin' => (($app) ? $app['app_plugin'] : ''),
'$requires' => (($app) ? $app['app_requires'] : ''),
'$embed' => $embed,
'$submit' => t('Submit')
));
return replace_macros(get_markup_template('app_create.tpl'), [
'$banner' => (($app) ? t('Edit App') : t('Create App')),
'$app' => $app,
'$guid' => (($app) ? $app['app_id'] : EMPTY_STR),
'$author' => (($app) ? $app['app_author'] : $channel['channel_hash']),
'$addr' => (($app) ? $app['app_addr'] : $channel['xchan_addr']),
'$name' => [ 'name', t('Name of app'),(($app) ? $app['app_name'] : EMPTY_STR), t('Required') ],
'$url' => [ 'url', t('Location (URL) of app'),(($app) ? $app['app_url'] : EMPTY_STR), t('Required') ],
'$desc' => [ 'desc', t('Description'),(($app) ? $app['app_desc'] : EMPTY_STR), EMPTY_STR],
'$photo' => [ 'photo', t('Photo icon URL'),(($app) ? $app['app_photo'] : EMPTY_STR), t('80 x 80 pixels - optional') ],
'$categories' => [ 'categories',t('Categories (optional, comma separated list)'),(($app) ? $app['categories'] : EMPTY_STR), EMPTY_STR ],
'$version' => [ 'version', t('Version ID'),(($app) ? $app['app_version'] : EMPTY_STR), EMPTY_STR ],
'$price' => [ 'price', t('Price of app'),(($app) ? $app['app_price'] : EMPTY_STR), EMPTY_STR ],
'$page' => [ 'sellpage', t('Location (URL) to purchase app'),(($app) ? $app['app_page'] : EMPTY_STR), EMPTY_STR ],
'$system' => (($app) ? intval($app['app_system']) : 0),
'$plugin' => (($app) ? $app['app_plugin'] : EMPTY_STR),
'$requires' => (($app) ? $app['app_requires'] : EMPTY_STR),
'$embed' => $embed,
'$submit' => t('Submit')
]);
}

View file

@ -2,53 +2,51 @@
namespace Zotlabs\Module;
use \Zotlabs\Lib as Zlib;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
class Apporder extends \Zotlabs\Web\Controller {
function post() {
}
function get() {
if(! local_channel())
if (! local_channel()) {
return;
}
nav_set_selected('Order Apps');
foreach( [ 'nav_featured_app', 'nav_pinned_app' ] as $l ) {
foreach ( [ 'nav_featured_app', 'nav_pinned_app' ] as $l ) {
$syslist = [];
$list = Zlib\Apps::app_list(local_channel(), false, [ $l ]);
if($list) {
foreach($list as $li) {
$syslist[] = Zlib\Apps::app_encode($li);
$list = Apps::app_list(local_channel(), false, [ $l ]);
if ($list) {
foreach ($list as $li) {
$syslist[] = Apps::app_encode($li);
}
}
Zlib\Apps::translate_system_apps($syslist);
Apps::translate_system_apps($syslist);
usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
$syslist = Zlib\Apps::app_order(local_channel(),$syslist, $l);
$syslist = Apps::app_order(local_channel(),$syslist, $l);
foreach($syslist as $app) {
if($l === 'nav_pinned_app') {
$navbar_apps[] = Zlib\Apps::app_render($app,'nav-order');
foreach ($syslist as $app) {
if ($l === 'nav_pinned_app') {
$navbar_apps[] = Apps::app_render($app,'nav-order-pinned');
}
elseif(strpos($app['categories'],'nav_pinned_app') === false) {
$nav_apps[] = Zlib\Apps::app_render($app,'nav-order');
else {
$nav_apps[] = Apps::app_render($app,'nav-order');
}
}
}
return replace_macros(get_markup_template('apporder.tpl'),
[
'$header' => [t('Change Order of Pinned Navbar Apps'), t('Change Order of App Tray Apps')],
'$desc' => [t('Use arrows to move the corresponding app left (top) or right (bottom) in the navbar'), t('Use arrows to move the corresponding app up or down in the app tray')],
'$nav_apps' => $nav_apps,
return replace_macros(get_markup_template('apporder.tpl'), [
'$header' => [ t('Change Order of Pinned Navbar Apps'), t('Change Order of App Tray Apps') ],
'$desc' => [ t('Use arrows to move the corresponding app left (top) or right (bottom) in the navbar'),
t('Use arrows to move the corresponding app up or down in the app tray') ],
'$nav_apps' => $nav_apps,
'$navbar_apps' => $navbar_apps
]
);
]);
}
}

View file

@ -17,12 +17,17 @@ class Apschema extends \Zotlabs\Web\Controller {
'ostatus' => 'http://ostatus.org#',
'conversation' => 'ostatus:conversation',
'sensitive' => 'as:sensitive',
'movedTo' => 'as:movedTo',
'copiedTo' => 'as:copiedTo',
'alsoKnownAs' => 'as:alsoKnownAs',
'inheritPrivacy' => 'as:inheritPrivacy',
'commentPolicy' => 'zot:commentPolicy',
'topicalCollection' => 'zot:topicalCollection',
'eventRepeat' => 'zot:eventRepeat',
'emojiReaction' => 'zot:emojiReaction',
'expires' => 'zot:expires',
'directMessage' => 'zot:directMessage',
'replyTo' => 'zot:replyTo'
]
];

View file

@ -50,13 +50,21 @@ class Authorize extends \Zotlabs\Web\Controller {
// TODO: The automatic client registration protocol below should adhere more
// closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined
// at https://tools.ietf.org/html/rfc7591
// If no client_id was provided, generate a new one.
if (x($_POST, 'client_name')) {
$client_name = $_POST['client_name'];
} else {
$client_name = $_POST['client_name'] = EMPTY_STR;
}
// If no client_id was provided, generate a new one.
if (x($_POST, 'client_id')) {
$client_id = $_POST['client_id'];
} else {
$client_id = $_POST['client_id'] = random_string(16);
}
// If no redirect_uri was provided, generate a fake one.
if (x($_POST, 'redirect_uri')) {
$redirect_uri = $_POST['redirect_uri'];
@ -76,7 +84,7 @@ class Authorize extends \Zotlabs\Web\Controller {
// Until "Dynamic Client Registration" is pursued - allow new clients to assign their own secret in the REQUEST
$client_secret = (isset($_REQUEST['client_secret'])) ? $_REQUEST['client_secret'] : random_string(16);
// Client apps are registered per channel
$storage->setClientDetails($client_id, $client_secret, $redirect_uri, 'authorization_code', $_REQUEST['scope'], $user_id);
$storage->setClientDetails($client_id, $client_secret, $redirect_uri, $_REQUEST['grant_types'], $_REQUEST['scope'], $user_id, $client_name);
}
if (!$client = $storage->getClientDetails($client_id)) {
// There was an error registering the client.

View file

@ -81,9 +81,8 @@ class Cal extends Controller {
nav_set_selected('Calendar');
$sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event');
$first_day = get_pconfig(local_channel(),'system','cal_first_day');
$first_day = (($first_day) ? $first_day : 0);
$first_day = intval(get_pconfig($channel['channel_id'],'system','cal_first_day',0));
$htpl = get_markup_template('event_head.tpl');
\App::$page['htmlhead'] .= replace_macros($htpl,array(

View file

@ -429,12 +429,12 @@ class Calendar extends Controller {
'end' => $end,
'drop' => $drop,
'allDay' => $allDay,
'title' => htmlentities($rr['summary'], ENT_COMPAT, 'UTF-8'),
'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
'editable' => $edit ? true : false,
'item' => $rr,
'plink' => [ $rr['plink'], t('Link to source') ],
'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8'),
'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8'),
'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8',false),
'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8',false),
'allow_cid' => expand_acl($rr['allow_cid']),
'allow_gid' => expand_acl($rr['allow_gid']),
'deny_cid' => expand_acl($rr['deny_cid']),
@ -443,7 +443,7 @@ class Calendar extends Controller {
];
}
}
if ($export) {
header('Content-type: text/calendar');
header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );

View file

@ -76,6 +76,7 @@ class Channel extends Controller {
'href' => z_root() . '/feed/' . $which . '?f=&top=1'
]);
// handle zot6 channel discovery
if(Libzot::is_zot_request()) {
@ -113,7 +114,7 @@ class Channel extends Controller {
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_person($channel,true,((defined('NOMADIC')) ? false : true)));
]], Activity::encode_person($channel,true,true));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
@ -135,6 +136,16 @@ class Channel extends Controller {
Libprofile::load($which,$profile);
App::$meta->set('og:title', $channel['channel_name']);
App::$meta->set('og:image', $channel['xchan_photo_l']);
App::$meta->set('og:type','webpage');
App::$meta->set('og:url', channel_url($channel));
if(App::$profile['about'] && perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_profile')) {
App::$meta->set('og:description', App::$profile['about']);
}
else {
App::$meta->set('og:description', sprintf( t('This is the home page of %s.'), $channel['channel_name']));
}
}
function get($update = 0, $load = false) {
@ -440,6 +451,7 @@ class Channel extends Controller {
'$nouveau' => '0',
'$wall' => '1',
'$fh' => '0',
'$dm' => '0',
'$static' => $static,
'$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1),
'$search' => $search,

View file

@ -37,18 +37,11 @@ class Cloud extends Controller {
if (argc() > 1)
$which = argv(1);
if (argc() < 2 && intval(get_config('system','cloud_disable_siteroot'))) {
notice( t('Permission denied.') . EOL);
construct_page();
killme();
}
$profile = 0;
if ($which)
if ($which) {
Libprofile::load( $which, $profile);
}
$auth = new \Zotlabs\Storage\BasicAuth();

View file

@ -1,20 +1,24 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/socgraph.php');
class Connections extends \Zotlabs\Web\Controller {
class Connections extends Controller {
function init() {
if(! local_channel())
if (! local_channel()) {
return;
}
$channel = \App::get_channel();
if($channel)
$channel = App::get_channel();
if ($channel) {
head_set_icon($channel['xchan_photo_s']);
}
}
@ -24,7 +28,7 @@ class Connections extends \Zotlabs\Web\Controller {
$o = '';
if(! local_channel()) {
if (! local_channel()) {
notice( t('Permission denied.') . EOL);
return login();
}
@ -41,14 +45,15 @@ class Connections extends \Zotlabs\Web\Controller {
$unconnected = false;
$all = false;
if(! $_REQUEST['aj'])
$_SESSION['return_url'] = \App::$query_string;
if (! $_REQUEST['aj']) {
$_SESSION['return_url'] = App::$query_string;
}
$search_flags = "";
$head = '';
if(argc() == 2) {
switch(argv(1)) {
if (argc() == 2) {
switch (argv(1)) {
case 'active':
$search_flags = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 AND abook_not_here = 0 ";
$head = t('Active');
@ -80,21 +85,25 @@ class Connections extends \Zotlabs\Web\Controller {
$pending = true;
break;
case 'ifpending':
case intval(argv(1)):
$r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ",
intval(local_channel())
);
if($r && $r[0]['total']) {
if ($r && $r[0]['total']) {
$search_flags = " and abook_pending = 1 ";
if(intval(argv(1))) {
$search_flags .= " and abook_id = " . intval(argv(1)) . " ";
}
$head = t('New');
$pending = true;
\App::$argv[1] = 'pending';
App::$argv[1] = 'pending';
}
else {
$head = t('All');
$search_flags = '';
$all = true;
\App::$argc = 1;
unset(\App::$argv[1]);
App::$argc = 1;
unset(App::$argv[1]);
}
break;
@ -109,9 +118,9 @@ class Connections extends \Zotlabs\Web\Controller {
}
$sql_extra = $search_flags;
if(argv(1) === 'pending')
if (argv(1) === 'pending') {
$sql_extra .= " and abook_ignored = 0 ";
}
}
else {
$sql_extra = " and abook_blocked = 0 ";
@ -179,7 +188,7 @@ class Connections extends \Zotlabs\Web\Controller {
$search_txt = dbesc(protect_sprintf(preg_quote($search)));
$searching = true;
}
$sql_extra .= (($searching) ? protect_sprintf(" AND xchan_name like '%$search_txt%' ") : "");
$sql_extra .= (($searching) ? protect_sprintf(" AND ( xchan_name like '%$search_txt%' OR abook_alias like '%$search_txt%' ) ") : "");
if($_REQUEST['gid']) {
$sql_extra .= " and xchan_hash in ( select xchan from pgrp_member where gid = " . intval($_REQUEST['gid']) . " and uid = " . intval(local_channel()) . " ) ";
@ -190,15 +199,15 @@ class Connections extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if($r) {
\App::set_pager_total($r[0]['total']);
App::set_pager_total($r[0]['total']);
$total = $r[0]['total'];
}
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash
WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ORDER BY xchan_name LIMIT %d OFFSET %d ",
intval(local_channel()),
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
intval(App::$pager['itemspage']),
intval(App::$pager['start'])
);
$contacts = array();
@ -247,7 +256,7 @@ class Connections extends \Zotlabs\Web\Controller {
'delete_hover' => t('Delete connection'),
'id' => $rr['abook_id'],
'thumb' => $rr['xchan_photo_m'],
'name' => $rr['xchan_name'],
'name' => $rr['xchan_name'] . (($rr['abook_alias']) ? ' &lt;' . $rr['abook_alias'] . '&gt;' : ''),
'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''),
'link' => z_root() . '/connedit/' . $rr['abook_id'],
'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop',
@ -303,7 +312,7 @@ class Connections extends \Zotlabs\Web\Controller {
'$finding' => (($searching) ? t('Connections search') . ": '" . $search . "'" : ""),
'$submit' => t('Find'),
'$edit' => t('Edit'),
'$cmd' => \App::$cmd,
'$cmd' => App::$cmd,
'$contacts' => $contacts,
'$paginate' => paginate($a),

View file

@ -74,15 +74,6 @@ class Connedit extends Controller {
$channel = App::get_channel();
// TODO if configured for hassle-free permissions, we'll post the form with ajax as soon as the
// connection enable is toggled to a special autopost url and set permissions immediately, leaving
// the other form elements alone pending a manual submit of the form. The downside is that there
// will be a window of opportunity when the permissions have been set but before you've had a chance
// to review and possibly restrict them. The upside is we won't have to warn you that your connection
// can't do anything until you save the bloody form.
$autopost = (((argc() > 2) && (argv(2) === 'auto')) ? true : false);
$orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1",
intval($contact_id),
intval(local_channel())
@ -127,6 +118,7 @@ class Connedit extends Controller {
$abook_incl = ((array_key_exists('abook_incl',$_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record[0]['abook_incl']);
$abook_excl = ((array_key_exists('abook_excl',$_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record[0]['abook_excl']);
$abook_alias = ((array_key_exists('abook_alias',$_POST)) ? escape_tags(trim($_POST['abook_alias'])) : $orig_record[0]['abook_alias']);
$hidden = intval($_POST['hidden']);
@ -184,13 +176,14 @@ class Connedit extends Controller {
$abook_pending = (($new_friend) ? 0 : $orig_record[0]['abook_pending']);
$r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d,
abook_incl = '%s', abook_excl = '%s'
abook_incl = '%s', abook_excl = '%s', abook_alias = '%s'
where abook_id = %d AND abook_channel = %d",
dbesc($profile_id),
intval($closeness),
intval($abook_pending),
dbesc($abook_incl),
dbesc($abook_excl),
dbesc($abook_alias),
intval($contact_id),
intval(local_channel())
);
@ -247,8 +240,7 @@ class Connedit extends Controller {
post_activity_item($xarr);
}
// pull in a bit of content if there is any to pull in
Master::Summon( [ 'Onepoll', $contact_id ]);
@ -287,33 +279,33 @@ class Connedit extends Controller {
function connedit_clone(&$a) {
if(! App::$poi)
return;
if (! App::$poi) {
return;
}
$channel = App::get_channel();
$channel = App::get_channel();
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_id = %d LIMIT 1",
intval(local_channel()),
intval(App::$poi['abook_id'])
);
if ($r) {
App::$poi = array_shift($r);
}
$r = q("SELECT abook.*, xchan.*
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel = %d and abook_id = %d LIMIT 1",
intval(local_channel()),
intval(App::$poi['abook_id'])
);
if($r) {
App::$poi = array_shift($r);
}
$clone = App::$poi;
$clone = App::$poi;
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if($abconfig)
$clone['abconfig'] = $abconfig;
Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if ($abconfig) {
$clone['abconfig'] = $abconfig;
}
Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ] ] );
}
/* @brief Generate content of connection edit page
@ -431,7 +423,7 @@ class Connedit extends Controller {
notice(t('Unable to set address book parameters.') . EOL);
goaway(z_root() . '/connedit/' . $contact_id);
}
if($cmd === 'ignore') {
if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_IGNORED)) {
$this->connedit_clone($a);
@ -441,6 +433,15 @@ class Connedit extends Controller {
goaway(z_root() . '/connedit/' . $contact_id);
}
if($cmd === 'censor') {
if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_CENSORED)) {
$this->connedit_clone($a);
}
else
notice(t('Unable to set address book parameters.') . EOL);
goaway(z_root() . '/connedit/' . $contact_id);
}
if($cmd === 'archive') {
if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_ARCHIVED)) {
$this->connedit_clone($a);
@ -574,7 +575,15 @@ class Connedit extends Controller {
'title' => t('Ignore (or Unignore) all inbound communications from this connection'),
'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''),
),
'censor' => array(
'label' => (intval($contact['abook_censor']) ? t('Uncensor') : t('Censor')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor',
'sel' => (intval($contact['abook_censor']) ? 'active' : ''),
'title' => t('Censor (or Uncensor) images from this connection'),
'info' => (intval($contact['abook_censor']) ? t('This connection is censored!') : ''),
),
'archive' => array(
'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive',
@ -637,13 +646,13 @@ class Connedit extends Controller {
$tpl = get_markup_template("abook_edit.tpl");
if(Apps::system_app_installed(local_channel(),'Affinity Tool')) {
if(Apps::system_app_installed(local_channel(),'Friend Zoom')) {
$sections['affinity'] = [
'label' => t('Affinity'),
'label' => t('Friend Zoom'),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=&section=affinity',
'sel' => '',
'title' => t('Open Set Affinity section by default'),
'title' => t('Open Friend Zoom section by default'),
];
$labels = [
@ -714,13 +723,13 @@ class Connedit extends Controller {
$multiprofs = ((feature_enabled(local_channel(),'multi_profiles')) ? true : false);
if($slide && !$multiprofs)
$affinity = t('Set Affinity');
$affinity = t('Set Friend Zoom');
if(!$slide && $multiprofs)
$affinity = t('Set Profile');
if($slide && $multiprofs)
$affinity = t('Set Affinity & Profile');
$affinity = t('Set Friend Zoom & Profile');
$theirs = get_abconfig(local_channel(),$contact['abook_xchan'],'system','their_perms',EMPTY_STR);
@ -776,7 +785,7 @@ class Connedit extends Controller {
$not_here = t('This connection is unreachable from this location. Location independence is not supported by their network.');
$o .= replace_macros($tpl, [
'$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name'])),
'$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name']) . (($contact['abook_alias']) ? ' &lt;' . $contact['abook_alias'] . '&gt;' : '')),
'$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no),
'$permcat' => [ 'permcat', t('Permission role'), '', '<span class="loading invisible">' . t('Loading') . '<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span></span>',$permcats ],
'$permcat_new' => t('Add permission role'),
@ -803,6 +812,7 @@ class Connedit extends Controller {
'$connfilter_label' => t('Custom Filter'),
'$incl' => array('abook_incl',t('Only import posts with this text'), $contact['abook_incl'],t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')),
'$excl' => array('abook_excl',t('Do not import posts with this text'), $contact['abook_excl'],t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')),
'$alias' => array('abook_alias',t('Nickname'), $contact['abook_alias'],t('optional - allows you to search by a name that you have chosen')),
'$rating_text' => array('rating_text', t('Optionally explain your rating'),$rating_text,''),
'$rating_info' => t('This information is public!'),
'$rating' => $rating,

View file

@ -38,7 +38,7 @@ class Contactgroup extends Controller {
killme();
}
$members = AccessList::members($group['id']);
$members = AccessList::members(local_channel(),$group['id']);
$preselected = ids_to_array($members,'xchan_hash');
if ($change) {

View file

@ -1,6 +1,7 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Activity;
use Zotlabs\Lib\Libprofile;
use Zotlabs\Access\AccessControl;
@ -12,6 +13,7 @@ use Zotlabs\Web\Controller;
*/
require_once('include/attach.php');
require_once('include/photo_factory.php');
require_once('include/photos.php');
@ -25,14 +27,14 @@ require_once('include/photos.php');
*/
class Cover_photo extends \Zotlabs\Web\Controller {
class Cover_photo extends Controller {
function init() {
if(! local_channel()) {
if (! local_channel()) {
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
Libprofile::load($channel['channel_address']);
}
@ -45,26 +47,26 @@ class Cover_photo extends \Zotlabs\Web\Controller {
function post() {
if(! local_channel()) {
if (! local_channel()) {
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo');
if((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) {
if ((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) {
// phase 2 - we have finished cropping
if(argc() != 2) {
if (argc() != 2) {
notice( t('Image uploaded but image cropping failed.') . EOL );
return;
}
$image_id = argv(1);
if(substr($image_id,-2,1) == '-') {
if (substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
}
@ -79,8 +81,8 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$r = q("select gender from profile where uid = %d and is_default = 1 limit 1",
intval(local_channel())
);
if($r) {
$profile = $r[0];
if ($r) {
$profile = array_shift($r);
}
$r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1",
@ -88,26 +90,26 @@ class Cover_photo extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if($r) {
if ($r) {
$max_thumb = intval(get_config('system','max_thumbnail',1600));
$iscaled = false;
if(intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) {
if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) {
$imagick_path = get_config('system','imagick_convert_path');
if($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) {
if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) {
$fname = dbunescbin($r[0]['content']);
$tmp_name = $fname . '-001';
$newsize = photo_calculate_scale(array_merge(getimagesize($fname),['max' => $max_thumb]));
$cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name);
// logger('imagick thumbnail command: ' . $cmd);
for($x = 0; $x < 4; $x ++) {
for ($x = 0; $x < 4; $x ++) {
exec($cmd);
if(file_exists($tmp_name)) {
if (file_exists($tmp_name)) {
break;
}
}
if(file_exists($tmp_name)) {
if (file_exists($tmp_name)) {
$base_image = $r[0];
$gis = getimagesize($tmp_name);
logger('gis: ' . print_r($gis,true));
@ -119,13 +121,13 @@ logger('gis: ' . print_r($gis,true));
}
}
}
if(! $iscaled) {
if (! $iscaled) {
$base_image = $r[0];
$base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
$base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
}
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
if ($im->is_valid()) {
// We are scaling and cropping the relative pixel locations to the original photo instead of the
// scaled photo we operated on.
@ -142,7 +144,7 @@ logger('gis: ' . print_r($gis,true));
$scaled_width = $g[0]['width'];
$scaled_height = $g[0]['height'];
if((! $scaled_width) || (! $scaled_height)) {
if ((! $scaled_width) || (! $scaled_height)) {
logger('potential divide by zero scaling cover photo');
return;
}
@ -179,20 +181,19 @@ logger('gis: ' . print_r($gis,true));
$p['imgscale'] = 7;
$p['photo_usage'] = PHOTO_COVER;
$r1 = $im->save($p);
$r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200);
$im->doScaleImage(850,310);
$p['imgscale'] = 8;
$r2 = $im->save($p);
$r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850);
$im->doScaleImage(425,160);
$p['imgscale'] = 9;
$r3 = $im->save($p);
$r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425);
if($r1 === false || $r2 === false || $r3 === false) {
if ($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ",
@ -202,7 +203,7 @@ logger('gis: ' . print_r($gis,true));
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
$this->send_cover_photo_activity($channel,$base_image,$profile);
@ -218,24 +219,22 @@ logger('gis: ' . print_r($gis,true));
$hash = photo_new_resource();
$smallest = 0;
require_once('include/attach.php');
$matches = [];
$partial = false;
if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
$pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
if($pm) {
if ($pm) {
logger('Content-Range: ' . print_r($matches,true));
$partial = true;
}
}
if($partial) {
if ($partial) {
$x = save_chunk($channel,$matches[1],$matches[2],$matches[3]);
if($x['partial']) {
if ($x['partial']) {
header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
json_return_and_die($result);
}
@ -252,7 +251,7 @@ logger('gis: ' . print_r($gis,true));
}
}
else {
if(! array_key_exists('userfile',$_FILES)) {
if (! array_key_exists('userfile',$_FILES)) {
$_FILES['userfile'] = [
'name' => $_FILES['files']['name'],
'type' => $_FILES['files']['type'],
@ -263,9 +262,9 @@ logger('gis: ' . print_r($gis,true));
}
}
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash));
$res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash));
logger('attach_store: ' . print_r($res,true));
logger('attach_store: ' . print_r($res,true),LOGGER_DEBUG);
json_return_and_die([ 'message' => $hash ]);
@ -273,7 +272,7 @@ logger('gis: ' . print_r($gis,true));
function send_cover_photo_activity($channel,$photo,$profile) {
$arr = array();
$arr = [];
$arr['item_thread_top'] = 1;
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
@ -282,12 +281,15 @@ logger('gis: ' . print_r($gis,true));
$arr['obj_type'] = ACTIVITY_OBJ_NOTE;
$arr['verb'] = ACTIVITY_CREATE;
if($profile && stripos($profile['gender'],t('female')) !== false)
if ($profile && stripos($profile['gender'],t('female')) !== false) {
$t = t('%1$s updated her %2$s');
elseif($profile && stripos($profile['gender'],t('male')) !== false)
}
elseif ($profile && stripos($profile['gender'],t('male')) !== false) {
$t = t('%1$s updated his %2$s');
else
}
else {
$t = t('%1$s updated their %2$s');
}
$ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]';
@ -336,19 +338,19 @@ logger('gis: ' . print_r($gis,true));
function get() {
if(! local_channel()) {
if (! local_channel()) {
notice( t('Permission denied.') . EOL );
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
$newuser = false;
if(argc() == 2 && argv(1) === 'new')
if (argc() == 2 && argv(1) === 'new')
$newuser = true;
if(argv(1) === 'use') {
if (argv(1) === 'use') {
if (argc() < 3) {
notice( t('Permission denied.') . EOL );
return;
@ -362,14 +364,15 @@ logger('gis: ' . print_r($gis,true));
intval(local_channel()),
dbesc($resource_id)
);
if(! $r) {
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
$havescale = false;
foreach($r as $rr) {
if($rr['imgscale'] == 7)
foreach ($r as $rr) {
if ($rr['imgscale'] == 7) {
$havescale = true;
}
}
$r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
@ -377,75 +380,74 @@ logger('gis: ' . print_r($gis,true));
intval(local_channel())
);
if(! $r) {
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
if(intval($r[0]['os_storage']))
if (intval($r[0]['os_storage'])) {
$data = @file_get_contents(dbunescbin($r[0]['content']));
else
$data = dbunescbin($r[0]['content']);
}
else {
$data = dbunescbin($r[0]['content']);
}
$ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if($ph->is_valid()) {
if ($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
$i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0",
dbesc($r[0]['resource_id']),
intval(local_channel())
);
if($i) {
if ($i) {
$hash = $i[0]['resource_id'];
foreach($i as $ii) {
foreach ($i as $ii) {
$smallest = intval($ii['imgscale']);
}
}
}
$this->cover_photo_crop_ui_head($a, $ph, $hash, $smallest);
$this->cover_photo_crop_ui_head($ph, $hash, $smallest);
}
if(! x(\App::$data,'imagecrop')) {
if(! array_key_exists('imagecrop',App::$data)) {
$tpl = get_markup_template('cover_photo.tpl');
$o .= replace_macros($tpl,array(
'$user' => \App::$channel['channel_address'],
'$info' => t('Your cover photo may be visible to anybody on the internet'),
'$existing' => get_cover_photo(local_channel(),'array',PHOTO_RES_COVER_850),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => t('Change Cover Photo'),
'$submit' => t('Upload'),
'$profiles' => $profiles,
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
$o .= replace_macros(get_markup_template('cover_photo.tpl'), [
'$user' => App::$channel['channel_address'],
'$info' => t('Your cover photo may be visible to anybody on the internet'),
'$existing' => get_cover_photo(local_channel(),'array',PHOTO_RES_COVER_850),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => t('Change Cover Photo'),
'$submit' => t('Upload'),
'$profiles' => $profiles,
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("cover_photo"),
/// @FIXME - yuk
'$select' => t('Select existing photo'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("cover_photo"),
'$select' => t('Select previously uploaded photo'),
));
]);
call_hooks('cover_photo_content_end', $o);
return $o;
}
else {
$filename = \App::$data['imagecrop'] . '-3';
$filename = App::$data['imagecrop'] . '-3';
$resolution = 3;
$tpl = get_markup_template("cropcover.tpl");
$o .= replace_macros($tpl,array(
$o .= replace_macros(get_markup_template('cropcover.tpl'), [
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => \App::$data['imagecrop'] . '-3',
@ -454,11 +456,9 @@ logger('gis: ' . print_r($gis,true));
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
'$form_security_token' => get_form_security_token("cover_photo"),
'$done' => t('Done Editing')
));
]);
return $o;
}
return; // NOTREACHED
}
/* @brief Generate the UI for photo-cropping
@ -469,27 +469,29 @@ logger('gis: ' . print_r($gis,true));
*
*/
function cover_photo_crop_ui_head(&$a, $ph, $hash, $smallest){
function cover_photo_crop_ui_head($ph, $hash, $smallest){
$max_length = get_config('system','max_image_length');
if(! $max_length)
if (! $max_length) {
$max_length = MAX_IMAGE_LENGTH;
if($max_length > 0)
}
if ($max_length > 0) {
$ph->scaleImage($max_length);
}
$width = $ph->getWidth();
$height = $ph->getHeight();
if($width < 300 || $height < 300) {
if ($width < 300 || $height < 300) {
$ph->scaleImageUp(240);
$width = $ph->getWidth();
$height = $ph->getHeight();
}
\App::$data['imagecrop'] = $hash;
\App::$data['imagecrop_resolution'] = $smallest;
\App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array());
App::$data['imagecrop'] = $hash;
App::$data['imagecrop_resolution'] = $smallest;
App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []);
return;
}

View file

@ -96,6 +96,8 @@ class Dav extends Controller {
$auth = new \Zotlabs\Storage\BasicAuth();
$auth->observer = get_observer_hash();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV');
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);

View file

@ -42,10 +42,10 @@ class Dircensor extends Controller {
info( t('Entry censored') . EOL);
}
else {
info( t('Entry censored') . EOL);
info( t('Entry uncensored') . EOL);
}
return;
goaway(z_root() . '/directory');
}

View file

@ -18,14 +18,16 @@ class Directory extends Controller {
function init() {
App::set_pager_itemspage(DIRECTORY_PAGESIZE);
if(x($_GET,'ignore') && local_channel()) {
if (x($_GET,'ignore') && local_channel()) {
q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ",
intval(local_channel()),
dbesc($_GET['ignore'])
);
Libsync::build_sync_packet(local_channel(), [ 'xign' => [ [ 'uid' => local_channel(), 'xchan' => $_GET['ignore'] ]]] );
Libsync::build_sync_packet(local_channel(), [ 'xign' => [ [ 'uid' => local_channel(), 'xchan' => $_GET['ignore'] ]]] );
if ($_REQUEST['return']) {
goaway(z_root() . '/' . base64_decode($_REQUEST['return']));
}
goaway(z_root() . '/directory?f=&suggest=1');
}
@ -34,62 +36,63 @@ class Directory extends Controller {
$safe_changed = false;
$type_changed = false;
if(array_key_exists('global',$_REQUEST)) {
if (array_key_exists('global',$_REQUEST)) {
$globaldir = intval($_REQUEST['global']);
if(get_config('system','localdir_hide')) {
if (get_config('system','localdir_hide')) {
$globaldir = 1;
}
$global_changed = true;
}
if($global_changed) {
if ($global_changed) {
$_SESSION['globaldir'] = $globaldir;
if($observer)
if ($observer) {
set_xconfig($observer,'directory','globaldir',$globaldir);
}
}
if(array_key_exists('safe',$_REQUEST)) {
if (array_key_exists('safe',$_REQUEST)) {
$safemode = intval($_REQUEST['safe']);
$safe_changed = true;
}
if($safe_changed) {
if ($safe_changed) {
$_SESSION['safemode'] = $safemode;
if($observer)
if ($observer) {
set_xconfig($observer,'directory','safemode',$safemode);
}
}
if(array_key_exists('type',$_REQUEST)) {
if (array_key_exists('type',$_REQUEST)) {
$type = intval($_REQUEST['type']);
$type_changed = true;
}
if($type_changed) {
if ($type_changed) {
$_SESSION['chantype'] = $type;
if($observer)
if ($observer) {
set_xconfig($observer,'directory','chantype',$type);
}
}
}
function get() {
if(observer_prohibited()) {
if (observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
if(get_config('system','block_public_directory',false) && (! get_observer_hash())) {
$observer = get_observer_hash();
if (get_config('system','block_public_directory',false) && (! $observer)) {
notice( t('Public access denied.') . EOL);
return;
}
$observer = get_observer_hash();
$globaldir = Libzotdir::get_directory_setting($observer, 'globaldir');
// override your personal global search pref if we're doing a navbar search of the directory
if(intval($_REQUEST['navsearch']))
if (intval($_REQUEST['navsearch'])) {
$globaldir = 1;
}
$safe_mode = Libzotdir::get_directory_setting($observer, 'safemode');
@ -98,21 +101,23 @@ class Directory extends Controller {
$o = '';
nav_set_selected('Directory');
if(x($_POST,'search'))
if (x($_POST,'search')) {
$search = notags(trim($_POST['search']));
else
}
else {
$search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : '');
}
if(strpos($search,'=') && local_channel() && feature_enabled(local_channel(), 'advanced_dirsearch'))
if (strpos($search,'=')) {
$advanced = $search;
}
$keywords = (($_GET['keywords']) ? $_GET['keywords'] : '');
// Suggest channels if no search terms or keywords are given
$suggest = (local_channel() && x($_REQUEST,'suggest')) ? $_REQUEST['suggest'] : '';
if($suggest) {
if ($suggest) {
// the directory options have no effect in suggestion mode
@ -120,14 +125,13 @@ class Directory extends Controller {
$safe_mode = 1;
$type = 0;
// only return DIRECTORY_PAGESIZE suggestions as the suggestion sorting
// only works if the suggestion query and the directory query have the
// same number of results
$r = suggestion_query(local_channel(),get_observer_hash(),0,DIRECTORY_PAGESIZE);
if(! $r) {
if (! $r) {
notice( t('No default suggestions were found.') . EOL);
return;
}
@ -136,14 +140,14 @@ class Directory extends Controller {
$addresses = array();
$common = array();
$index = 0;
foreach($r as $rr) {
foreach ($r as $rr) {
$common[$rr['xchan_addr']] = ((intval($rr['total']) > 0) ? intval($rr['total']) - 1 : 0);
$addresses[$rr['xchan_addr']] = $index++;
}
// Build query to get info about suggested people
$advanced = '';
foreach(array_keys($addresses) as $address) {
foreach (array_keys($addresses) as $address) {
$advanced .= "address=\"$address\" ";
}
// Remove last space in the advanced query
@ -172,76 +176,85 @@ class Directory extends Controller {
}
$token = get_config('system','realm_token');
logger('mod_directory: URL = ' . $url, LOGGER_DEBUG);
$contacts = array();
if(local_channel()) {
if (local_channel()) {
$x = q("select abook_xchan from abook where abook_channel = %d",
intval(local_channel())
);
if($x) {
foreach($x as $xx)
if ($x) {
foreach ($x as $xx) {
$contacts[] = $xx['abook_xchan'];
}
}
}
if($url) {
if ($url) {
$numtags = get_config('system','directorytags');
$kw = ((intval($numtags) > 0) ? intval($numtags) : 50);
if(get_config('system','disable_directory_keywords'))
if (get_config('system','disable_directory_keywords')) {
$kw = 0;
}
$query = $url . '?f=&kw=' . $kw . (($safe_mode != 1) ? '&safe=' . $safe_mode : '');
if($token)
if ($token) {
$query .= '&t=' . $token;
if(! $globaldir)
}
if (! $globaldir) {
$query .= '&hub=' . App::get_hostname();
if($search)
}
if ($search) {
$query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search);
if(strpos($search,'@'))
}
if (strpos($search,'@')) {
$query .= '&address=' . urlencode($search);
if($keywords)
}
if ($keywords) {
$query .= '&keywords=' . urlencode($keywords);
if($advanced)
}
if ($advanced) {
$query .= '&query=' . urlencode($advanced);
if(! is_null($type))
}
if (! is_null($type)) {
$query .= '&type=' . intval($type);
}
$directory_sort_order = get_config('system','directory_sort_order');
if(! $directory_sort_order)
if (! $directory_sort_order) {
$directory_sort_order = 'date';
}
$sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : $directory_sort_order);
if($sort_order)
if ($sort_order) {
$query .= '&order=' . urlencode($sort_order);
}
if(App::$pager['page'] != 1)
if (App::$pager['page'] != 1) {
$query .= '&p=' . App::$pager['page'];
}
logger('mod_directory: query: ' . $query);
$x = z_fetch_url($query);
// logger('directory: return from upstream: ' . print_r($x,true), LOGGER_DATA);
if($x['success']) {
if ($x['success']) {
$t = 0;
$j = json_decode($x['body'],true);
if($j) {
if ($j) {
if($j['results']) {
if ($j['results']) {
$results = $j['results'];
if($suggest) {
if ($suggest) {
// change order to "number of common friends descending"
$results = self::reorder_results($results,$addresses);
}
@ -250,7 +263,7 @@ class Directory extends Controller {
$photo = 'thumb';
foreach($results as $rr) {
foreach ($results as $rr) {
$profile_link = chanlink_url($rr['url']);
@ -261,54 +274,52 @@ class Directory extends Controller {
//$online = remote_online_status($rr['address']);
$online = '';
if(in_array($rr['hash'],$contacts))
if (in_array($rr['hash'],$contacts)) {
$connect_link = '';
}
$location = '';
if(strlen($rr['locale']))
if (strlen($rr['locale'])) {
$location .= $rr['locale'];
if(strlen($rr['region'])) {
if(strlen($rr['locale']))
}
if (strlen($rr['region'])) {
if (strlen($rr['locale'])) {
$location .= ', ';
}
$location .= $rr['region'];
}
if(strlen($rr['country'])) {
if(strlen($location))
if (strlen($rr['country'])) {
if (strlen($location)) {
$location .= ', ';
}
$location .= $rr['country'];
}
$age = '';
if(strlen($rr['birthday'])) {
if(($years = age($rr['birthday'],'UTC','')) > 0)
if (strlen($rr['birthday'])) {
if (($years = age($rr['birthday'],'UTC','')) > 0) {
$age = $years;
}
}
$page_type = '';
$rating_enabled = get_config('system','rating_enabled');
if($rr['total_ratings'] && $rating_enabled)
if ($rr['total_ratings'] && $rating_enabled) {
$total_ratings = sprintf( tt("%d rating", "%d ratings", $rr['total_ratings']), $rr['total_ratings']);
else
}
else {
$total_ratings = '';
}
$profile = $rr;
if ((x($profile,'locale') == 1)
|| (x($profile,'region') == 1)
|| (x($profile,'postcode') == 1)
|| (x($profile,'country') == 1))
$gender = ((x($profile,'gender') == 1) ? t('Gender: ') . $profile['gender']: False);
$marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False);
$marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False);
$homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') : False);
$homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : '');
$homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : '');
$hometown = ((x($profile,'hometown') == 1) ? html2plain($profile['hometown']) : False);
$about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False);
if ($about && $safe_mode) {
$about = html2plain($about);
@ -316,81 +327,82 @@ class Directory extends Controller {
$keywords = ((x($profile,'keywords')) ? $profile['keywords'] : '');
$out = '';
if($keywords) {
if ($keywords) {
$keywords = str_replace(',',' ', $keywords);
$keywords = str_replace(' ',' ', $keywords);
$karr = explode(' ', $keywords);
if($karr) {
if(local_channel()) {
$r = q("select keywords from profile where uid = %d and is_default = 1 limit 1",
if ($karr) {
if (local_channel()) {
$pk = q("select keywords from profile where uid = %d and is_default = 1 limit 1",
intval(local_channel())
);
if($r) {
$keywords = str_replace(',',' ', $r[0]['keywords']);
if ($pk) {
$keywords = str_replace(',',' ', $pk[0]['keywords']);
$keywords = str_replace(' ',' ', $keywords);
$marr = explode(' ', $keywords);
}
}
foreach($karr as $k) {
if(strlen($out))
foreach ($karr as $k) {
if (strlen($out)) {
$out .= ', ';
if($marr && in_arrayi($k,$marr))
}
if ($marr && in_arrayi($k,$marr)) {
$out .= '<a href="' . z_root() . '/directory/f=&keywords=' . urlencode($k) .'"><strong>' . $k . '</strong></a>';
else
}
else {
$out .= '<a href="' . z_root() . '/directory/f=&keywords=' . urlencode($k) .'">' . $k . '</a>';
}
}
}
}
$entry = array(
'id' => ++$t,
'profile_link' => $profile_link,
'type' => $rr['type'],
'photo' => $rr['photo'],
'hash' => $rr['hash'],
'alttext' => $rr['name'] . ((local_channel() || remote_channel()) ? ' ' . $rr['address'] : ''),
'name' => $rr['name'],
'age' => $age,
'age_label' => t('Age:'),
'profile' => $profile,
'address' => $rr['address'],
'nickname' => substr($rr['address'],0,strpos($rr['address'],'@')),
'location' => $location,
'location_label' => t('Location:'),
'gender' => $gender,
'total_ratings' => $total_ratings,
'viewrate' => true,
'canrate' => (($rating_enabled && local_channel()) ? true : false),
'pdesc' => $pdesc,
'pdesc_label' => t('Description:'),
'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] : ''),
'censor_label' => (($rr['censored']) ? t('Uncensor') : t('Censor')),
'marital' => $marital,
'homepage' => $homepage,
'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)),
'hometown' => $hometown,
'hometown_label' => t('Hometown:'),
'about' => $about,
'about_label' => t('About:'),
'conn_label' => t('Connect'),
'forum_label' => t('Group'),
$entry = [
'id' => ++ $t,
'profile_link' => $profile_link,
'type' => $rr['type'],
'photo' => $rr['photo'],
'hash' => $rr['hash'],
'alttext' => $rr['name'] . ((local_channel() || remote_channel()) ? ' ' . $rr['address'] : ''),
'name' => $rr['name'],
'age' => $age,
'age_label' => t('Age:'),
'profile' => $profile,
'address' => $rr['address'],
'nickname' => substr($rr['address'],0,strpos($rr['address'],'@')),
'location' => $location,
'location_label' => t('Location:'),
'gender' => $gender,
'total_ratings' => $total_ratings,
'viewrate' => true,
'canrate' => (($rating_enabled && local_channel()) ? true : false),
'pdesc' => $pdesc,
'pdesc_label' => t('Description:'),
'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] : ''),
'censor_label' => (($rr['censored']) ? t('Uncensor') : t('Censor')),
'marital' => $marital,
'homepage' => $homepage,
'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)),
'hometown' => $hometown,
'hometown_label' => t('Hometown:'),
'about' => $about,
'about_label' => t('About:'),
'conn_label' => t('Connect'),
'forum_label' => t('Group'),
'collections_label' => t('Collection'),
'connect' => $connect_link,
'online' => $online,
'kw' => (($out) ? t('Keywords: ') : ''),
'keywords' => $out,
'ignlink' => $suggest ? z_root() . '/directory?ignore=' . $rr['hash'] : '',
'ignore_label' => t('Don\'t suggest'),
'common_friends' => (($common[$rr['address']]) ? intval($common[$rr['address']]) : ''),
'common_label' => t('Common connections (estimated):'),
'common_count' => intval($common[$rr['address']]),
'safe' => $safe_mode
);
'connect' => $connect_link,
'online' => $online,
'kw' => (($out) ? t('Keywords: ') : ''),
'keywords' => $out,
'ignlink' => $suggest ? z_root() . '/directory?ignore=' . $rr['hash'] : '',
'ignore_label' => t('Don\'t suggest'),
'common_friends' => (($common[$rr['address']]) ? intval($common[$rr['address']]) : ''),
'common_label' => t('Common connections (estimated):'),
'common_count' => intval($common[$rr['address']]),
'safe' => $safe_mode
];
$arr = array('contact' => $rr, 'entry' => $entry);
@ -399,14 +411,13 @@ class Directory extends Controller {
unset($profile);
unset($location);
if(! $arr['entry']) {
if (! $arr['entry']) {
continue;
}
if($sort_order == '' && $suggest) {
if ($sort_order == '' && $suggest) {
$entries[$addresses[$rr['address']]] = $arr['entry']; // Use the same indexes as originally to get the best suggestion first
}
else {
$entries[] = $arr['entry'];
}
@ -414,18 +425,16 @@ class Directory extends Controller {
ksort($entries); // Sort array by key so that foreach-constructs work as expected
if($j['keywords']) {
if ($j['keywords']) {
App::$data['directory_keywords'] = $j['keywords'];
}
// logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA);
if($_REQUEST['aj']) {
if($entries) {
$o = replace_macros(get_markup_template('directajax.tpl'),array(
'$entries' => $entries
));
if ($_REQUEST['aj']) {
if ($entries) {
$o = replace_macros(get_markup_template('directajax.tpl'), [ '$entries' => $entries ] );
}
else {
$o = '<div id="content-complete"></div>';
@ -439,35 +448,42 @@ class Directory extends Controller {
$dirtitle = (($globaldir) ? t('Global Directory') : t('Local Directory'));
$o .= "<script> var page_query = '" . escape_tags(urlencode($_GET['req'])) . "'; var extra_args = '" . extra_query_args() . "' ; divmore_height = " . intval($maxheight) . "; </script>";
$o .= replace_macros($tpl, array(
'$search' => $search,
'$desc' => t('Find'),
'$finddsc' => t('Finding:'),
'$safetxt' => htmlspecialchars($search,ENT_QUOTES,'UTF-8'),
'$entries' => $entries,
'$dirlbl' => $suggest ? t('Channel Suggestions') : $dirtitle,
'$submit' => t('Find'),
'$next' => alt_pager($j['records'], t('next page'), t('previous page')),
'$sort' => t('Sort options'),
'$normal' => t('Alphabetic'),
'$reverse' => t('Reverse Alphabetic'),
'$date' => t('Newest to Oldest'),
$o .= replace_macros($tpl, [
'$search' => $search,
'$desc' => t('Find'),
'$finddsc' => t('Finding:'),
'$safetxt' => htmlspecialchars($search,ENT_QUOTES,'UTF-8'),
'$entries' => $entries,
'$dirlbl' => $suggest ? t('Channel Suggestions') : $dirtitle,
'$submit' => t('Find'),
'$next' => alt_pager($j['records'], t('next page'), t('previous page')),
'$sort' => t('Sort options'),
'$normal' => t('Alphabetic'),
'$reverse' => t('Reverse Alphabetic'),
'$date' => t('Newest to Oldest'),
'$reversedate' => t('Oldest to Newest'),
'$suggest' => $suggest ? '&suggest=1' : ''
));
'$suggest' => $suggest ? '&suggest=1' : ''
]);
}
}
else {
if($_REQUEST['aj']) {
if ($_REQUEST['aj']) {
$o = '<div id="content-complete"></div>';
echo $o;
killme();
}
if(\App::$pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) {
goaway(z_root() . '/chanview/?f=&address=' . $search);
if (App::$pager['page'] == 1 && $j['records'] == 0) {
if (strpos($search,'@')) {
goaway(z_root() . '/chanview/?f=&address=' . $search);
}
else {
$r = q("select xchan_hash from xchan where xchan_name = '%s' limit 1",
dbesc($search)
);
if ($r) {
goaway(z_root() . '/chanview/?f=&hash=' . urlencode($r[0]['xchan_hash']));
}
}
}
info( t("No entries (some entries may be hidden).") . EOL);
}
@ -479,22 +495,19 @@ class Directory extends Controller {
static public function reorder_results($results,$suggests) {
// return $results;
if(! $suggests)
if (! $suggests) {
return $results;
}
$out = [];
foreach($suggests as $k => $v) {
foreach($results as $rv) {
if($k == $rv['address']) {
foreach ($suggests as $k => $v) {
foreach ($results as $rv) {
if ($k == $rv['address']) {
$out[intval($v)] = $rv;
break;
}
}
}
return $out;
}

View file

@ -27,11 +27,13 @@ class Dirsearch extends Controller {
$dirmode = intval(get_config('system','directory_mode'));
if ($dirmode == DIRECTORY_MODE_NORMAL) {
if ($dirmode == DIRECTORY_MODE_NORMAL && ! intval($_REQUEST['navsearch'])) {
$ret['message'] = t('This site is not a directory server');
json_return_and_die($ret);
}
$network = ((intval($_REQUEST['navsearch'])) ? EMPTY_STR : " AND xchan_network = 'zot6' ");
$access_token = $_REQUEST['t'];
@ -220,7 +222,7 @@ class Dirsearch extends Controller {
else {
$qlimit = " LIMIT " . intval($perpage) . " OFFSET " . intval($startrec);
if ($return_total) {
$r = q("SELECT COUNT(xchan_hash) AS total FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra and xchan_network = 'zot6' and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql ");
$r = q("SELECT COUNT(xchan_hash) AS total FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra $network and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql ");
if ($r) {
$ret['total_items'] = $r[0]['total'];
}
@ -299,7 +301,7 @@ class Dirsearch extends Controller {
// normal directory query
$r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash
where ( $logic $sql_extra ) $hub_query and xchan_network = 'zot6' and xchan_system = 0 and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0
where ( $logic $sql_extra ) $hub_query $network and xchan_system = 0 and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0
$safesql $order $qlimit "
);
@ -353,7 +355,7 @@ class Dirsearch extends Controller {
$ret['results'] = $entries;
if ($kw) {
$k = dir_tagadelic($kw, $hub, $type);
$k = dir_tagadelic($kw, $hub, $type,$safesql);
if ($k) {
$ret['keywords'] = array();
foreach ($k as $kv) {
@ -430,7 +432,7 @@ class Dirsearch extends Controller {
$quoted_string = false;
}
else
$curr['value'] .= ' ' . trim(q);
$curr['value'] .= ' ' . trim($q);
}
}
}

View file

@ -180,6 +180,12 @@ class Display extends Controller {
return '';
}
}
if ($target_item['item_type'] == ITEM_TYPE_CUSTOM) {
call_hooks('item_custom_display',$target_item);
notice( t('Page not found.') . EOL);
return '';
}
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
@ -224,6 +230,7 @@ class Display extends Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,

View file

@ -2,15 +2,13 @@
namespace Zotlabs\Module;
/**
* @brief
*
*/
class Embedphotos extends \Zotlabs\Web\Controller {
use App;
use Zotlabs\Web\Controller;
function get() {
require_once('include/attach.php');
require_once('include/photos.php');
}
class Embedphotos extends Controller {
/**
*
@ -21,28 +19,29 @@ class Embedphotos extends \Zotlabs\Web\Controller {
if (argc() > 1 && argv(1) === 'album') {
// API: /embedphotos/album
$name = (x($_POST,'name') ? $_POST['name'] : null );
if(!$name) {
if (! $name) {
json_return_and_die(array('errormsg' => 'Error retrieving album', 'status' => false));
}
$album = $this->embedphotos_widget_album(array('channel' => \App::get_channel(), 'album' => $name));
$album = $this->embedphotos_widget_album(array('channel_id' => local_channel(), 'album' => $name));
json_return_and_die(array('status' => true, 'content' => $album));
}
if(argc() > 1 && argv(1) === 'albumlist') {
if (argc() > 1 && argv(1) === 'albumlist') {
// API: /embedphotos/albumlist
$album_list = $this->embedphotos_album_list($a);
$album_list = $this->embedphotos_album_list();
json_return_and_die(array('status' => true, 'albumlist' => $album_list));
}
if(argc() > 1 && argv(1) === 'photolink') {
if (argc() > 1 && argv(1) === 'photolink') {
// API: /embedphotos/photolink
$href = (x($_POST,'href') ? $_POST['href'] : null );
if(!$href) {
if (! $href) {
json_return_and_die(array('errormsg' => 'Error retrieving link ' . $href, 'status' => false));
}
$resource_id = array_pop(explode("/", $href));
$x = self::photolink($resource_id);
if($x)
if ($x) {
json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id));
}
json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false));
}
@ -50,27 +49,32 @@ class Embedphotos extends \Zotlabs\Web\Controller {
protected static function photolink($resource) {
$channel = \App::get_channel();
$channel = App::get_channel();
$output = EMPTY_STR;
if($channel) {
$resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 2 : 3);
if ($channel) {
$resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 1 : 2);
$r = q("select mimetype, height, width from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1",
dbesc($resource),
intval($resolution),
intval($channel['channel_id'])
);
if(! $r)
if (! $r) {
return $output;
if($r[0]['mimetype'] === 'image/jpeg')
}
if ($r[0]['mimetype'] === 'image/jpeg') {
$ext = '.jpg';
elseif($r[0]['mimetype'] === 'image/png')
}
elseif ($r[0]['mimetype'] === 'image/png') {
$ext = '.png';
elseif($r[0]['mimetype'] === 'image/gif')
}
elseif ($r[0]['mimetype'] === 'image/gif') {
$ext = '.gif';
else
}
else {
$ext = EMPTY_STR;
}
$output = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $resource . ']' .
'[zmg=' . $r[0]['width'] . 'x' . $r[0]['height'] . ']' . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . '[/zmg][/zrl]';
@ -89,50 +93,56 @@ class Embedphotos extends \Zotlabs\Web\Controller {
* @param array $args
* @return string with HTML
*/
function embedphotos_widget_album($args) {
$channel_id = 0;
if(array_key_exists('channel', $args))
$channel = $args['channel'];
$channel_id = intval($channel['channel_id']);
if(! $channel_id)
$channel_id = \App::$profile_uid;
if(! $channel_id)
if (array_key_exists('channel_id', $args)) {
$channel_id = $args['channel_id'];
$channel = channelx_by_n($channel_id);
}
if (! $channel_id) {
return '';
}
$owner_uid = $channel_id;
require_once('include/security.php');
$sql_extra = permissions_sql($channel_id);
if(! perm_is_allowed($channel_id,get_observer_hash(),'view_storage'))
if (! perm_is_allowed($channel_id,get_observer_hash(),'view_storage'))
return '';
if($args['album'])
if ($args['album']) {
$album = (($args['album'] === '/') ? '' : $args['album']);
if($args['title'])
}
if ($args['title']) {
$title = $args['title'];
}
/**
* This may return incorrect permissions if you have multiple directories of the same name.
* It is a limitation of the photo table using a name for a photo album instead of a folder hash
*/
if($album) {
require_once('include/attach.php');
if ($album) {
$x = q("select hash from attach where filename = '%s' and uid = %d limit 1",
dbesc($album),
intval($owner_uid)
);
if($x) {
if ($x) {
$y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']);
if(! $y)
if (! $y) {
return '';
}
}
}
$order = 'DESC';
$r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN
(SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph
(SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4
AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph
ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)
ORDER BY created $order",
intval($owner_uid),
@ -141,60 +151,61 @@ class Embedphotos extends \Zotlabs\Web\Controller {
intval(PHOTO_PROFILE)
);
$photos = array();
if(count($r)) {
$photos = [];
if ($r) {
$twist = 'rotright';
foreach($r as $rr) {
if($twist == 'rotright')
foreach ($r as $rr) {
if ($twist == 'rotright') {
$twist = 'rotleft';
else
}
else {
$twist = 'rotright';
}
$ext = $phototypes[$rr['mimetype']];
$imgalt_e = $rr['filename'];
$desc_e = $rr['description'];
$imagelink = (z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id']
$imagelink = (z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $rr['resource_id']
. (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''));
$photos[] = array(
'id' => $rr['id'],
'twist' => ' ' . $twist . rand(2,4),
'link' => $imagelink,
'title' => t('View Photo'),
'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext,
'alt' => $imgalt_e,
'desc'=> $desc_e,
'ext' => $ext,
'hash'=> $rr['resource_id'],
'unknown' => t('Unknown')
);
$photos[] = [
'id' => $rr['id'],
'twist' => ' ' . $twist . rand(2,4),
'link' => $imagelink,
'title' => t('View Photo'),
'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext,
'alt' => $imgalt_e,
'desc' => $desc_e,
'ext' => $ext,
'hash' => $rr['resource_id'],
'unknown' => t('Unknown')
];
}
}
$tpl = get_markup_template('photo_album.tpl');
$o .= replace_macros($tpl, array(
'$photos' => $photos,
'$album' => (($title) ? $title : $album),
'$album_id' => rand(),
'$album_edit' => array(t('Edit Album'), $album_edit),
'$can_post' => false,
'$upload' => array(t('Upload'), z_root() . '/photos/' . \App::$profile['channel_address'] . '/upload/' . bin2hex($album)),
'$order' => false,
'$upload_form' => $upload_form,
$o .= replace_macros(get_markup_template('photo_album.tpl'), [
'$photos' => $photos,
'$album' => (($title) ? $title : $album),
'$album_id' => rand(),
'$album_edit' => array(t('Edit Album'), $album_edit),
'$can_post' => false,
'$upload' => [ t('Upload'), z_root() . '/photos/' . $channel['channel_address'] . '/upload/' . bin2hex($album) ],
'$order' => false,
'$upload_form' => $upload_form,
'$no_fullscreen_btn' => true
));
]);
return $o;
}
function embedphotos_album_list($a) {
require_once('include/photos.php');
$p = photos_albums_list(\App::get_channel(), \App::get_observer());
if($p['success']) {
function embedphotos_album_list() {
$p = photos_albums_list(App::get_channel(),App::get_observer());
if ($p['success']) {
return $p['albums'];
} else {
}
else {
return null;
}
}

View file

@ -22,7 +22,9 @@ class Events extends Controller {
if(! local_channel())
return;
$channel = App::get_channel();
if(($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size'])) {
$src = $_FILES['userfile']['tmp_name'];
if($src) {
@ -151,7 +153,6 @@ class Events extends Controller {
$share = 1;
$channel = App::get_channel();
$acl = new AccessControl(false);
@ -193,7 +194,7 @@ class Events extends Controller {
}
$post_tags = array();
$channel = App::get_channel();
$ac = $acl->get();
if(strlen($categories)) {
@ -295,6 +296,8 @@ class Events extends Controller {
return;
}
$channel = App::get_channel();
nav_set_selected('Events');
if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
@ -311,8 +314,7 @@ class Events extends Controller {
);
}
$first_day = get_pconfig(local_channel(),'system','cal_first_day');
$first_day = (($first_day) ? $first_day : 0);
$first_day = intval(get_pconfig(local_channel(),'system','cal_first_day',0));
$htpl = get_markup_template('event_head.tpl');
App::$page['htmlhead'] .= replace_macros($htpl,array(
@ -325,8 +327,6 @@ class Events extends Controller {
$o = '';
$channel = App::get_channel();
$mode = 'view';
$y = 0;
$m = 0;
@ -751,7 +751,7 @@ class Events extends Controller {
dbesc($event_id),
intval(local_channel())
);
$sync_event = $r[0];
if($r) {
@ -759,7 +759,63 @@ class Events extends Controller {
dbesc($event_id),
intval(local_channel())
);
if($r) {
if ($r) {
$i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d",
dbesc($event_id),
intval(local_channel())
);
if ($i) {
$can_delete = false;
$local_delete = true;
$ob_hash = get_observer_hash();
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
$can_delete = true;
}
// The site admin can delete any post/item on the site.
// If the item originated on this site+channel the deletion will propagate downstream.
// Otherwise just the local copy is removed.
if(is_site_admin()) {
$local_delete = true;
if(intval($i[0]['item_origin']))
$can_delete = true;
}
if($can_delete || $local_delete) {
// if this is a different page type or it's just a local delete
// but not by the item author or owner, do a simple deletion
$complex = false;
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
drop_item($i[0]['id']);
}
else {
// complex deletion that needs to propagate and be performed in phases
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
$complex = true;
}
$ii = q("select * from item where id = %d",
intval($i[0]['id'])
);
if($ii) {
xchan_query($ii);
$sync_item = fetch_post_tags($ii);
Libsync::build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
}
if($complex) {
tag_deliver($i[0]['uid'],$i[0]['id']);
}
}
}
$r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
dbesc($event_id),
intval(local_channel())

View file

@ -10,16 +10,15 @@ class Expire extends Controller {
function post() {
logger('expire: ' . print_r($_POST,true));
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Expire Posts'))) {
if (! ( local_channel() && Apps::system_app_installed(local_channel(),'Expire Posts'))) {
return;
}
if($_POST['expire-submit']) {
if ($_POST['expire-submit']) {
$expire = intval($_POST['selfexpiredays']);
if($expire < 0)
if ($expire < 0) {
$expire = 0;
}
set_pconfig(local_channel(),'system','selfexpiredays',$expire);
info( t('Expiration settings updated.') . EOL);
}
@ -35,30 +34,18 @@ logger('expire: ' . print_r($_POST,true));
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Expire Posts'))) {
if (! ( local_channel() && Apps::system_app_installed(local_channel(),'Expire Posts'))) {
return $text;
}
$setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array(
$setting_fields .= replace_macros(get_markup_template('field_input.tpl'), [
'$field' => array('selfexpiredays', t('Expire and delete all my posts after this many days'), intval(get_pconfig(local_channel(),'system','selfexpiredays',0)), t('Leave at 0 if you wish to manually control expiration of specific posts.'))
));
]);
$s .= replace_macros(get_markup_template('generic_app_settings.tpl'), array(
return replace_macros(get_markup_template('generic_app_settings.tpl'), [
'$addon' => array('expire', t('Automatic Expiration Settings'), '', t('Submit')),
'$content' => $setting_fields
));
return $s;
]);
}

View file

@ -1,9 +1,11 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
class Feed extends \Zotlabs\Web\Controller {
require_once('include/feedutils.php');
class Feed extends Controller {
function init() {
@ -20,21 +22,20 @@ class Feed extends \Zotlabs\Web\Controller {
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0);
if(! in_array($params['direction'],['asc','desc'])) {
if (! in_array($params['direction'],['asc','desc'])) {
$params['direction'] = 'desc';
}
if(argc() > 1) {
if (argc() > 1) {
if(observer_prohibited(true)) {
if (observer_prohibited(true)) {
killme();
}
$channel = channelx_by_nick(argv(1));
if(! $channel) {
if (! $channel) {
killme();
}
}
logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);

View file

@ -15,11 +15,8 @@ class Follow extends Controller {
function init() {
if(! local_channel()) {
return;
}
if(ActivityStreams::is_as_request() && argc() == 2) {
if (ActivityStreams::is_as_request() && argc() == 2) {
$abook_id = intval(argv(1));
if(! $abook_id)
return;
@ -27,18 +24,21 @@ class Follow extends Controller {
$r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d",
intval($abook_id)
);
if (! $r)
if (! $r) {
return;
}
$chan = channelx_by_n($r[0]['abook_channel']);
if(! $chan)
if (! $chan) {
http_status_exit(404, 'Not found');
}
$actor = Activity::encode_person($chan,true,true);
if(! $actor)
if (! $actor) {
http_status_exit(404, 'Not found');
}
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
@ -64,6 +64,13 @@ class Follow extends Controller {
}
if (! local_channel()) {
return;
}
$uid = local_channel();
$url = notags(trim(punify($_REQUEST['url'])));
$return_url = $_SESSION['return_url'];
@ -71,17 +78,13 @@ class Follow extends Controller {
$interactive = (($_REQUEST['interactive']) ? intval($_REQUEST['interactive']) : 1);
$channel = App::get_channel();
if(strpos($url,'@') === false && strpos($url,'/') === false) {
$url = $url . '@' . App::get_hostname();
}
$result = Connect::connect($channel,$url);
if($result['success'] == false) {
if($result['message'])
if ($result['success'] == false) {
if ($result['message']) {
notice($result['message']);
if($interactive) {
}
if ($interactive) {
goaway($return_url);
}
else {
@ -92,8 +95,8 @@ class Follow extends Controller {
info( t('Connection added.') . EOL);
$clone = array();
foreach($result['abook'] as $k => $v) {
if(strpos($k,'abook_') === 0) {
foreach ($result['abook'] as $k => $v) {
if (strpos($k,'abook_') === 0) {
$clone[$k] = $v;
}
}
@ -102,19 +105,20 @@ class Follow extends Controller {
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if($abconfig)
if ($abconfig) {
$clone['abconfig'] = $abconfig;
}
Libsync::build_sync_packet(0, [ 'abook' => [ $clone ] ], true);
$can_view_stream = their_perms_contains($channel['channel_id'],$clone['abook_xchan'],'view_stream');
// If we can view their stream, pull in some posts
if(($can_view_stream) || ($result['abook']['xchan_network'] === 'rss'))
if (($can_view_stream) || ($result['abook']['xchan_network'] === 'rss')) {
Master::Summon([ 'Onepoll', $result['abook']['abook_id'] ]);
}
if($interactive) {
if ($interactive) {
goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1');
}
else {
@ -124,7 +128,7 @@ class Follow extends Controller {
}
function get() {
if(! local_channel()) {
if (! local_channel()) {
return login();
}
}

View file

@ -0,0 +1,73 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libprofile;
class Followers extends Controller {
function init() {
if (observer_prohibited(true)) {
http_status_exit(403, 'Forbidden');
}
if (argc() < 2) {
http_status_exit(404, 'Not found');
}
$channel = channelx_by_nick(argv(1));
if (! $channel) {
http_status_exit(404, 'Not found');
}
Libprofile::load(argv(1));
$observer_hash = get_observer_hash();
if (((! (is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) {
http_status_exit(403, 'Forbidden');
}
if (! perm_is_allowed($channel['channel_id'],$observer_hash,'view_contacts')) {
http_status_exit(403, 'Forbidden');
}
$r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0",
intval($channel['channel_id']),
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
);
if (ActivityStreams::is_as_request()) {
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection'));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\LDSignatures;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libprofile;
class Following extends Controller {
function init() {
if (observer_prohibited(true)) {
http_status_exit(403, 'Forbidden');
}
if (argc() < 2) {
http_status_exit(404, 'Not found');
}
$channel = channelx_by_nick(argv(1));
if (! $channel) {
http_status_exit(404, 'Not found');
}
Libprofile::load(argv(1));
$observer_hash = get_observer_hash();
if (((! (is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) {
http_status_exit(403, 'Forbidden');
}
if (! perm_is_allowed($channel['channel_id'],$observer_hash,'view_contacts')) {
http_status_exit(403, 'Forbidden');
}
$r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0",
intval($channel['channel_id']),
intval($channel['channel_id']),
dbesc($channel['channel_hash'])
);
if (ActivityStreams::is_as_request()) {
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection'));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
}
}

View file

@ -1,6 +1,9 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
use Zotlabs\Web\HTTPSig;
/**
* module: getfile
*
@ -24,12 +27,15 @@ namespace Zotlabs\Module;
require_once('include/attach.php');
class Getfile extends \Zotlabs\Web\Controller {
class Getfile extends Controller {
function post() {
$header_verified = false;
logger('getfile_args: ' . print_r($_POST,true));
$hash = $_POST['hash'];
$resource = $_POST['resource'];
$revision = intval($_POST['revision']);
@ -37,12 +43,14 @@ class Getfile extends \Zotlabs\Web\Controller {
if(argc() > 1) {
$verify_hash = argv(1);
if($verify_hash !== $hash) {
if($verify_hash !== $resource) {
logger('resource mismatch');
killme();
}
}
if(! $hash) {
logger('no sender hash');
killme();
}
@ -53,7 +61,7 @@ class Getfile extends \Zotlabs\Web\Controller {
continue;
}
$verified = \Zotlabs\Web\HTTPSig::verify('');
$verified = HTTPSig::verify('');
if($verified && $verified['header_signed'] && $verified['header_valid']) {
$r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_addr = '%s' limit 1",
dbesc($verified['signer']),

View file

@ -1,19 +1,23 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription;
require_once("include/bbcode.php");
require_once('include/security.php');
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
class Hq extends \Zotlabs\Web\Controller {
class Hq extends Controller {
function init() {
if(! local_channel())
return;
\App::$profile_uid = local_channel();
App::$profile_uid = local_channel();
}
function post() {
@ -104,7 +108,7 @@ class Hq extends \Zotlabs\Web\Controller {
}
if(! $update) {
$channel = \App::get_channel();
$channel = App::get_channel();
$channel_acl = [
'allow_cid' => $channel['channel_allow_cid'],
@ -119,7 +123,7 @@ class Hq extends \Zotlabs\Web\Controller {
'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'],
'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'acl' => populate_acl($channel_acl,true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'permissions' => $channel_acl,
'bang' => '',
'visitor' => true,
@ -165,7 +169,7 @@ class Hq extends \Zotlabs\Web\Controller {
$o .= "<script> var profile_uid = " . local_channel()
. "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . ";</script>\r\n";
\App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),[
App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),[
'$baseurl' => z_root(),
'$pgtype' => 'hq',
'$uid' => local_channel(),
@ -178,6 +182,7 @@ class Hq extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,

View file

@ -90,7 +90,7 @@ class Id extends Controller {
xchan_query($r,true);
$items = fetch_post_tags($r,true);
$i = Activity::encode_item($items[0],( defined('NOMADIC') ? false : true));
$i = Activity::encode_item($items[0],( get_config('system','activitypub') ? true : false ));
if(! $i)
http_status_exit(404, 'Not found');

View file

@ -122,7 +122,7 @@ class Import extends Controller {
}
}
$codebase = ((defined('NOMADIC')) ? 'zap' : 'osada');
$codebase = 'zap';
if ((! array_path_exists('compatibility/codebase',$data)) || $data['compatibility']['codebase'] !== $codebase) {
notice('Data export format is not compatible with this software');
@ -142,7 +142,7 @@ class Import extends Controller {
$max_identities = account_service_class_fetch($account_id,'total_identities');
if ($max_identities !== false) {
$r = q("select channel_id from channel where channel_account_id = %d",
$r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 ",
intval($account_id)
);
if ($r && count($r) > $max_identities) {
@ -161,6 +161,9 @@ class Import extends Controller {
if ((! $x) || strlen($x) > 64) {
$x = strtolower(URLify::transliterate($newname));
}
else {
$x = $newname;
}
$newname = $x;
}

274
Zotlabs/Module/Inbox.php Normal file
View file

@ -0,0 +1,274 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Config;
class Inbox extends Controller {
function post() {
// This SHOULD be handled by the webserver, but in the RFC it is only indicated as
// a SHOULD and not a MUST, so some webservers fail to reject appropriately.
logger('accepting: ' . $_SERVER['HTTP_ACCEPT'],LOGGER_DEBUG);
if ((array_key_exists('HTTP_ACCEPT',$_SERVER)) && ($_SERVER['HTTP_ACCEPT'])
&& (strpos($_SERVER['HTTP_ACCEPT'],'*') === false) && (! ActivityStreams::is_as_request())) {
http_status_exit(406,'not acceptable');
}
$sys_disabled = ((Config::Get('system','disable_discover_tab') || Config::Get('system','disable_activitypub_discover_tab')) ? true : false);
logger('inbox_args: ' . print_r(App::$argv,true));
$is_public = false;
if (argc() == 1 || argv(1) === '[public]') {
$is_public = true;
}
else {
$channels = [ channelx_by_nick(argv(1)) ];
}
$data = file_get_contents('php://input');
if (! $data) {
return;
}
logger('inbox_activity: ' . jindent($data), LOGGER_DATA);
$hsig = HTTPSig::verify($data);
$AS = new ActivityStreams($data);
if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj)
&& array_key_exists('object',$AS->obj) && array_key_exists('actor',$AS->obj)) {
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
// Reparse the encapsulated Activity and use that instead
logger('relayed activity',LOGGER_DEBUG);
$AS = new ActivityStreams($AS->obj);
}
//logger('debug: ' . $AS->debug());
if (! $AS->is_valid()) {
if ($AS->deleted) {
// process mastodon user deletion activities, but only if we can validate the signature
if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) {
logger('removing deleted actor');
remove_all_xchan_resources($hsig['portable_id']);
}
else {
logger('ignoring deleted actor', LOGGER_DEBUG, LOG_INFO);
}
}
return;
}
// $observer_hash in this case is the sender
if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) {
$observer_hash = $hsig['portable_id'];
}
else {
$observer_hash = $AS->actor['id'];
}
if (! $observer_hash) {
return;
}
$m = parse_url($observer_hash);
if ($m && $m['scheme'] && $m['host']) {
if (! check_siteallowed($m['scheme'] . '://' . $m['host'])) {
http_status_exit(404,'Permission denied');
}
}
if (is_array($AS->actor) && array_key_exists('id',$AS->actor)) {
Activity::actor_store($AS->actor['id'],$AS->actor);
}
if (is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) {
Activity::actor_store($AS->obj['id'],$AS->obj);
}
if (is_array($AS->obj) && is_array($AS->obj['actor']) && array_key_exists('id',$AS->obj['actor']) && $AS->obj['actor']['id'] !== $AS->actor['id']) {
Activity::actor_store($AS->obj['actor']['id'],$AS->obj['actor']);
}
$test = q("update hubloc set hubloc_connected = '%s' where hubloc_hash = '%s' and hubloc_network = 'activitypub'",
dbesc(datetime_convert()),
dbesc($observer_hash)
);
// $test is ignored
if ($is_public) {
if ($AS->type === 'Follow' && $AS->obj && ActivityStreams::is_an_actor($AS->obj['type'])) {
$channels = q("SELECT * from channel where channel_address = '%s' and channel_removed = 0 ",
dbesc(basename($AS->obj['id']))
);
}
else {
// deliver to anybody following $AS->actor
$channels = q("SELECT * from channel where channel_id in ( SELECT abook_channel from abook left join xchan on abook_xchan = xchan_hash WHERE xchan_network = 'activitypub' and xchan_hash = '%s' ) and channel_removed = 0 ",
dbesc($observer_hash)
);
if (! $channels) {
$channels = [];
}
$parent = $AS->parent_id;
if ($parent) {
// this is a comment - deliver to everybody who owns the parent
$owners = q("SELECT * from channel where channel_id in ( SELECT uid from item where mid = '%s' ) ",
dbesc($parent)
);
if ($owners) {
$channels = array_merge($channels,$owners);
}
}
}
if ($channels === false) {
$channels = [];
}
if (in_array(ACTIVITY_PUBLIC_INBOX,$AS->recips)) {
// look for channels with send_stream = PERMS_PUBLIC
$r = q("select * from channel where channel_id in (select uid from pconfig where cat = 'perm_limits' and k = 'send_stream' and v = '1' ) and channel_removed = 0 ");
if ($r) {
$channels = array_merge($channels,$r);
}
if (! $sys_disabled) {
$channels[] = get_sys_channel();
}
}
}
if (! $channels) {
logger('no deliveries on this site');
return;
}
$saved_recips = [];
foreach ( [ 'to', 'cc', 'audience' ] as $x ) {
if (array_key_exists($x,$AS->data)) {
$saved_recips[$x] = $AS->data[$x];
}
}
$AS->set_recips($saved_recips);
foreach ($channels as $channel) {
if (! get_pconfig($channel['channel_id'],'system','activitypub',true)) {
continue;
}
logger('inbox_channel: ' . $channel['channel_address'],LOGGER_DEBUG);
switch ($AS->type) {
case 'Follow':
if ($AS->obj & ActivityStreams::is_an_actor($AS->obj['type'])) {
// do follow activity
Activity::follow($channel,$AS);
}
break;
case 'Accept':
if ($AS->obj & $AS->obj['type'] === 'Follow') {
// do follow activity
Activity::follow($channel,$AS);
}
break;
case 'Reject':
default:
break;
}
// These activities require permissions
$item = null;
switch ($AS->type) {
case 'Update':
if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) {
// pretend this is an old cache entry to force an update of all the actor details
$AS->obj['cached'] = true;
$AS->obj['updated'] = datetime_convert('UTC','UTC','1980-01-01', ATOM_TIME);
Activity::actor_store($AS->obj['id'],$AS->obj);
break;
}
case 'Create':
case 'Like':
case 'Dislike':
case 'Announce':
case 'Accept':
case 'Reject':
case 'TentativeAccept':
case 'TentativeReject':
case 'emojiReaction':
// These require a resolvable object structure
if (is_array($AS->obj)) {
$item = Activity::decode_note($AS);
// @wip replies must go to the replyTo endpoint if the top level post originated here.
//if ($item['mid'] !== $item['parent_mid'] && stripos(z_root(), $item['parent_mid']) === 0) {
// $item = null;
// break;
//}
}
else {
logger('unresolved object: ' . print_r($AS->obj,true));
}
break;
case 'Undo':
if ($AS->obj & $AS->obj['type'] === 'Follow') {
// do unfollow activity
Activity::unfollow($channel,$AS);
break;
}
case 'Delete':
Activity::drop($channel,$observer_hash,$AS);
break;
case 'Add':
case 'Remove':
default:
break;
}
if ($item) {
logger('parsed_item: ' . print_r($item,true),LOGGER_DATA);
Activity::store($channel,$observer_hash,$AS,$item);
}
}
http_status_exit(200,'OK');
}
function get() {
}
}

View file

@ -4,12 +4,14 @@ namespace Zotlabs\Module;
/**
*
* This is the POST destination for most all locally posted
* As a GET request, this module answers to activitypub and zot6 item fetches and
* acts as a permalink for local content.
*
* Otherwise this is the POST destination for most all locally posted
* text stuff. This function handles status, wall-to-wall status,
* local comments, and remote coments that are posted on this site
* (as opposed to being delivered in a feed).
* Also processed here are posts and comments coming through the
* statusnet/twitter API.
* Also processed here are posts and comments coming through the API.
* All of these become an "item" which is our basic unit of
* information.
* Posts that originate externally or do not fall into the above
@ -29,7 +31,10 @@ use Zotlabs\Lib\Config;
use Zotlabs\Lib\IConfig;
use Zotlabs\Lib\Enotify;
use Zotlabs\Lib\Apps;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\AccessControl;
use App;
use URLify;
require_once('include/attach.php');
require_once('include/bbcode.php');
@ -54,8 +59,9 @@ class Item extends Controller {
$i = null;
// do we have the item (at all)?
// add preferential bias to item owners (item_wall = 1)
$r = q("select * from item where mid = '%s' or uuid = '%s' $item_normal limit 1",
$r = q("select * from item where mid = '%s' or uuid = '%s' $item_normal order by item_wall desc limit 1",
dbesc(z_root() . '/item/' . $item_id),
dbesc($item_id)
);
@ -88,11 +94,12 @@ class Item extends Controller {
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0);
if (! $i) {
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra limit 1",
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
@ -114,7 +121,7 @@ class Item extends Controller {
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
http_status_exit(403, 'Forbidden');
$i = Activity::encode_item($items[0],((defined('NOMADIC')) ? false : true));
$i = Activity::encode_item($items[0],((get_config('system','activitypub')) ? true : false));
if(! $i)
http_status_exit(404, 'Not found');
@ -189,11 +196,12 @@ class Item extends Controller {
}
// if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access
// with a bias towards those items owned by channels on this site (item_wall = 1)
$sql_extra = item_permissions_sql(0);
if (! $i) {
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra limit 1",
$i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1",
dbesc($r[0]['parent_mid'])
);
}
@ -259,7 +267,7 @@ class Item extends Controller {
if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream'))
http_status_exit(403, 'Forbidden');
$i = Activity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',( defined('NOMADIC') ? false : true));
$i = Activity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',( get_config('system','activitypub') ? true : false));
if($portable_id) {
ThreadListener::store(z_root() . '/item/' . $item_id,$portable_id);
}
@ -286,12 +294,17 @@ class Item extends Controller {
}
if(argc() > 1 && argv(1) !== 'drop') {
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' ",
dbesc(z_root() . '/item/' . argv(1))
// if it isn't a drop command and isn't a post method and wasn't handled already,
// the default action is a browser request for a persistent uri and this should return
// the text/html page of the item.
if (argc() > 1 && argv(1) !== 'drop') {
$x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' ",
dbesc(z_root() . '/item/' . argv(1)),
dbesc(z_root() . '/activity/' . argv(1))
);
if($x) {
foreach($x as $xv) {
if ($x) {
foreach ($x as $xv) {
if (intval($xv['item_wall'])) {
$c = channelx_by_n($xv['uid']);
if ($c) {
@ -307,12 +320,20 @@ class Item extends Controller {
function post() {
// This will change. Figure out who the observer is and whether or not
// they have permission to post here. Else ignore the post.
if((! local_channel()) && (! remote_channel()) && (! x($_REQUEST,'anonname')))
return;
// drop an array of items.
if (x($_REQUEST,'dropitems')) {
$arr_drop = explode(',',$_REQUEST['dropitems']);
drop_items($arr_drop);
$json = array('success' => 1);
echo json_encode($json);
killme();
}
$uid = local_channel();
$channel = null;
$observer = null;
@ -323,34 +344,35 @@ class Item extends Controller {
* Is this a reply to something?
*/
$parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0);
$parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0);
$parent_mid = ((x($_REQUEST,'parent_mid')) ? trim($_REQUEST['parent_mid']) : '');
$remote_xchan = ((x($_REQUEST,'remote_xchan')) ? trim($_REQUEST['remote_xchan']) : false);
/**
* Who is viewing this page and posting this thing
*/
$remote_xchan = ((x($_REQUEST,'remote_xchan')) ? trim($_REQUEST['remote_xchan']) : false);
$remote_observer = xchan_match( ['xchan_hash' => $remote_xchan ] );
if(! $remote_observer) {
if (! $remote_observer) {
$remote_xchan = $remote_observer = false;
}
// This is the local channel representing who the posted item will belong to.
$profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
// *If* you are logged in as the site admin you are allowed to create items for the sys channel.
// This would typically be a webpage or webpage element.
$sys = get_sys_channel();
if($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) {
if ($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) {
$uid = intval($sys['channel_id']);
$channel = $sys;
$observer = $sys;
}
if(x($_REQUEST,'dropitems')) {
$arr_drop = explode(',',$_REQUEST['dropitems']);
drop_items($arr_drop);
$json = array('success' => 1);
echo json_encode($json);
killme();
}
call_hooks('post_local_start', $_REQUEST);
// logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
@ -359,7 +381,18 @@ class Item extends Controller {
$consensus = intval($_REQUEST['consensus']);
$nocomment = intval($_REQUEST['nocomment']);
// If this is a poll, grab the poll data
$qtype = intval($_REQUEST['qtype']);
if($_REQUEST['answers'] && is_array($_REQUEST['answers'])) {
$pollchoices = [];
foreach($_REQUEST['answers'] as $q) {
$pollchoices[] = escape_tags($q);
}
$_REQUEST['obj_type'] = ACTIVITY_OBJ_POLL;
}
// 'origin' (if non-zero) indicates that this network is where the message originated,
// for the purpose of relaying comments to other conversation members.
// If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset.
@ -410,10 +443,14 @@ class Item extends Controller {
}
}
if($pagetitle) {
$pagetitle = strtolower(\URLify::transliterate($pagetitle));
if ($pagetitle) {
$pagetitle = strtolower(URLify::transliterate($pagetitle));
}
/**
* process collections by tagging them
*/
if (array_key_exists('collections',$_REQUEST) && is_array($_REQUEST['collections']) && count($_REQUEST['collections'])) {
foreach ($_REQUEST['collections'] as $clct) {
$r = q("select xchan_url, xchan_hash from xchan left join hubloc on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1",
@ -443,21 +480,27 @@ class Item extends Controller {
$thr_parent = '';
$parid = 0;
$r = false;
// If this is a comment, find the parent and preset some stuff
if ($parent || $parent_mid) {
if($parent || $parent_mid) {
if(! x($_REQUEST,'type'))
if (! x($_REQUEST,'type')) {
$_REQUEST['type'] = 'net-comment';
if($obj_type == ACTIVITY_OBJ_NOTE)
}
if ($obj_type == ACTIVITY_OBJ_NOTE) {
$obj_type = ACTIVITY_OBJ_COMMENT;
if($parent) {
}
// fetch the parent item
if ($parent) {
$r = q("SELECT * FROM item WHERE id = %d LIMIT 1",
intval($parent)
);
}
elseif($parent_mid && $uid) {
elseif ($parent_mid && $uid) {
// This is coming from an API source, and we are logged in
$r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
dbesc($parent_mid),
@ -465,29 +508,31 @@ class Item extends Controller {
);
}
// if this isn't the real parent of the conversation, find it
if($r) {
if ($r) {
$parid = $r[0]['parent'];
$parent_mid = $r[0]['mid'];
if($r[0]['id'] != $r[0]['parent']) {
if ($r[0]['id'] != $r[0]['parent']) {
$r = q("SELECT * FROM item WHERE id = parent AND parent = %d LIMIT 1",
intval($parid)
);
}
// if interacting with a pubstream item,
// if interacting with a pubstream item (owned by the sys channel),
// create a copy of the parent in your stream
if($r[0]['uid'] === $sys['channel_id'] && local_channel()) {
if ($r[0]['uid'] === $sys['channel_id'] && local_channel()) {
$r = [ copy_of_pubitem(App::get_channel(), $r[0]['mid']) ];
}
}
if(! $r) {
if (! $r) {
notice( t('Unable to locate original post.') . EOL);
if($api_source)
return ( [ 'success' => false, 'message' => 'invalid post id' ] );
if(x($_REQUEST,'return'))
if ($api_source) {
return ( [ 'success' => false, 'message' => 'invalid post id' ] );
}
if (x($_REQUEST,'return')) {
goaway(z_root() . "/" . $return_path );
}
killme();
}
@ -506,27 +551,30 @@ class Item extends Controller {
$moderated = false;
if(! $observer) {
if (! $observer) {
$observer = App::get_observer();
if(! $observer) {
if (! $observer) {
// perhaps we're allowing moderated comments from anonymous viewers
$observer = anon_identity_init($_REQUEST);
if($observer) {
if ($observer) {
$moderated = true;
$remote_xchan = $remote_observer = $observer;
}
}
}
if(! $observer) {
if (! $observer) {
notice( t('Permission denied.') . EOL) ;
if($api_source)
return ( [ 'success' => false, 'message' => 'permission denied' ] );
if(x($_REQUEST,'return'))
if ($api_source) {
return ( [ 'success' => false, 'message' => 'permission denied' ] );
}
if (x($_REQUEST,'return')) {
goaway(z_root() . "/" . $return_path );
}
killme();
}
if($parent) {
if ($parent) {
logger('mod_item: item_post parent=' . $parent);
$can_comment = false;
@ -547,6 +595,7 @@ class Item extends Controller {
}
}
else {
// fixme - $webpage could also be a wiki page or article and require a different permission to be checked.
if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],($webpage) ? 'write_pages' : 'post_wall')) {
notice( t('Permission denied.') . EOL) ;
if($api_source)
@ -556,13 +605,16 @@ class Item extends Controller {
killme();
}
}
// check if this author is being moderated through the 'moderated' (negative) permission
// when posting wall-to-wall
if ($moderated === false && intval($uid) !== intval($profile_uid)) {
$moderated = perm_is_allowed($profile_uid,$observer['xchan_hash'],'moderated');
}
// If this is a comment, check the moderated permission of the parent; who may be on another site
$remote_moderated = (($parent) ? their_perms_contains($profile_uid,$parent_item['owner_xchan'],'moderated') : false);
if($remote_moderated) {
if ($remote_moderated) {
notice( t('Comment may be moderated.') . EOL);
}
@ -570,7 +622,7 @@ class Item extends Controller {
$orig_post = null;
if($namespace && $remote_id) {
if ($namespace && $remote_id) {
// It wasn't an internally generated post - see if we've got an item matching this remote service id
$i = q("select iid from iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1",
dbesc($namespace),
@ -661,10 +713,10 @@ class Item extends Controller {
}
}
$acl = new \Zotlabs\Access\AccessControl($channel);
$acl = new AccessControl($channel);
$view_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_stream');
$comment_policy = \Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'post_comments');
$view_policy = PermissionLimits::Get($channel['channel_id'],'view_stream');
$comment_policy = PermissionLimits::Get($channel['channel_id'],'post_comments');
$public_policy = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy,true));
if($webpage)
@ -684,9 +736,9 @@ class Item extends Controller {
$private = $orig_post['item_private'];
}
if($private || $public_policy || $acl->is_private())
$private = 1;
if($public_policy || $acl->is_private()) {
$private = (($private) ? $private : 1);
}
$location = $orig_post['location'];
$coord = $orig_post['coord'];
@ -763,14 +815,14 @@ class Item extends Controller {
$allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0);
$private = intval($acl->is_private() || ($public_policy));
$private = (($private) ? $private : intval($acl->is_private() || ($public_policy)));
// If this is a comment, set the permissions from the parent.
if($parent_item) {
$private = 0;
$acl->set($parent_item);
$private = intval($acl->is_private() || $parent_item['item_private']);
$private = ((intval($parent_item['item_private']) ? $parent_item['item_private'] : $acl->is_private()));
$public_policy = $parent_item['public_policy'];
$owner_hash = $parent_item['owner_xchan'];
$webpage = $parent_item['item_type'];
@ -875,7 +927,12 @@ class Item extends Controller {
}
}
}
if(($str_contact_allow) && (! $str_group_allow)) {
// direct message - private between individual channels but not groups
$private = 2;
}
/**
*
@ -1102,7 +1159,9 @@ class Item extends Controller {
$plink = z_root() . '/item/' . $uuid;
}
$datarray['aid'] = $channel['channel_account_id'];
$datarray['uid'] = $profile_uid;
$datarray['uuid'] = $uuid;
@ -1168,7 +1227,7 @@ class Item extends Controller {
if(! array_key_exists('obj',$datarray)) {
$copy = $datarray;
$copy['author'] = $observer;
$datarray['obj'] = Activity::encode_item($copy,((defined('NOMADIC')) ? false : true));
$datarray['obj'] = Activity::encode_item($copy,((get_config('system','activitypub')) ? true : false));
}
// A specific ACL over-rides public_policy completely
@ -1176,9 +1235,15 @@ class Item extends Controller {
if(! empty_acl($datarray))
$datarray['public_policy'] = '';
if($iconfig)
if ($iconfig) {
$datarray['iconfig'] = $iconfig;
}
if ($private) {
IConfig::set($datarray,'ocap','relay',new_token());
}
// preview mode - prepare the body for display and send it via json
if($preview) {
@ -1422,13 +1487,14 @@ class Item extends Controller {
if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) {
$i = q("select id, uid, item_origin, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1",
$i = q("select * from item where id = %d limit 1",
intval(argv(2))
);
if($i) {
$can_delete = false;
$local_delete = false;
$regular_delete = false;
if(local_channel() && local_channel() == $i[0]['uid']) {
$local_delete = true;
@ -1437,6 +1503,7 @@ class Item extends Controller {
$ob_hash = get_observer_hash();
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) {
$can_delete = true;
$regular_delete = true;
}
// The site admin can delete any post/item on the site.
@ -1454,7 +1521,36 @@ class Item extends Controller {
notice( t('Permission denied.') . EOL);
return;
}
if ($i[0]['resource_type'] === 'event') {
// delete and sync the event separately
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($i[0]['resource_id']),
intval($i[0]['uid'])
);
if ($r && $regular_delete) {
$sync_event = $r[0];
q("delete from event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($i[0]['resource_id']),
intval($i[0]['uid'])
);
$sync_event['event_deleted'] = 1;
Libsync::build_sync_packet($i[0]['uid'],array('event' => array($sync_event)));
}
}
if ($i[0]['resource_type'] === 'photo') {
attach_delete($i[0]['uid'], $i[0]['resource_id'], true );
$ch = channelx_by_n($i[0]['uid']);
if ($ch && $regular_delete) {
$sync = attach_export_data($ch,$i[0]['resource_id'], true);
if ($sync) {
Libsync::build_sync_packet($i[0]['uid'],array('file' => array($sync)));
}
}
}
// if this is a different page type or it's just a local delete
// but not by the item author or owner, do a simple deletion

View file

@ -1,6 +1,7 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\Controller;
@ -46,7 +47,7 @@ class Like extends Controller {
$sys_channel = get_sys_channel();
$sys_channel_id = (($sys_channel) ? $sys_channel['channel_id'] : 0);
$observer = \App::get_observer();
$observer = App::get_observer();
$verb = notags(trim($_GET['verb']));
@ -178,7 +179,7 @@ class Like extends Controller {
$object = json_encode(Activity::fetch_profile([ 'id' => channel_url($ch[0]) ]));
// second like of the same thing is "undo" for the first like
$z = q("select * from likes where channel_id = %d and liker = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' limit 1",
@ -234,7 +235,7 @@ class Like extends Controller {
if($r) {
if($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) {
$r = [ copy_of_pubitem(\App::get_channel(), $r[0]['mid']) ];
$r = [ copy_of_pubitem(App::get_channel(), $r[0]['mid']) ];
}
}
@ -283,8 +284,10 @@ class Like extends Controller {
$multi_undo = false;
$item_normal = item_normal();
$item_normal = " and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0
and item.item_pending_remove = 0 and item.item_blocked = 0 and item.obj_type != '" . ACTIVITY_OBJ_FILE . "' ";
$r = q("SELECT id, parent, uid, verb FROM item WHERE verb in ( $verbs ) $item_normal
AND author_xchan = '%s' AND thr_parent = '%s' and uid = %d ",
dbesc($observer['xchan_hash']),
@ -360,6 +363,16 @@ class Like extends Controller {
$r = q("update item set item_hidden = 0 where id = %d",
intval($item['id'])
);
$r = q("select * from item where id = %d",
intval($item['id'])
);
if($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($ch[0]['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]);
}
Master::Summon(array('Notifier','wall-new',$item['id']));
}

View file

@ -138,6 +138,15 @@ class Linkinfo extends Controller {
$x = Activity::fetch($url);
if (is_array($x)) {
$y = new ActivityStreams($x);
if ($y->is_valid() && $y->type === 'Announce' && is_array($y->obj)
&& array_key_exists('object',$y->obj) && array_key_exists('actor',$y->obj)) {
// This is a relayed/forwarded Activity (as opposed to a shared/boosted object)
// Reparse the encapsulated Activity and use that instead
logger('relayed activity',LOGGER_DEBUG);
$y = new ActivityStreams($y->obj);
}
if ($y->is_valid()) {
$z = Activity::decode_note($y);
$r = q("select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_hash = '%s' OR hubloc_id_url = '%s'",

356
Zotlabs/Module/Lists.php Normal file
View file

@ -0,0 +1,356 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\AccessList;
use Zotlabs\Lib\ActivityStreams;
use Zotlabs\Lib\Activity;
use Zotlabs\Web\HTTPSig;
use Zotlabs\Lib\Config;
use Zotlabs\Lib\LDSignatures;
class Lists extends Controller {
function init() {
if (ActivityStreams::is_as_request()) {
$item_id = argv(1);
if( ! $item_id) {
http_status_exit(404, 'Not found');
}
$x = q("select * from pgrp where hash = '%s' limit 1",
dbesc($item_id)
);
if (! $x) {
http_status_exit(404, 'Not found');
}
$group = array_shift($x);
// process an authenticated fetch
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (! check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (! check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
}
elseif (! Config::get('system','require_authenticated_fetch',false)) {
http_status_exit(403,'Permission denied');
}
if (! perm_is_allowed($group['uid'],get_observer_hash(),'view_contacts')) {
http_status_exit(403,'Permission denied');
}
$channel = channelx_by_n($group['uid']);
if (! $channel) {
http_status_exit(404,'Not found');
}
if (! $group['visible']) {
if ($channel['channel_hash'] !== get_observer_hash()) {
http_status_exit(403,'Permission denied');
}
}
$members = AccessList::members($group['uid'],$group['id']);
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
z_root() . ZOT_APSCHEMA_REV
]], Activity::encode_follow_collection($members, App::$query_string, 'OrderedCollection'));
$headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x['signature'] = LDSignatures::sign($x,$channel);
$ret = json_encode($x, JSON_UNESCAPED_SLASHES);
$headers['Digest'] = HTTPSig::generate_digest_header($ret);
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
HTTPSig::set_headers($h);
echo $ret;
killme();
}
if (! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
App::$profile_uid = local_channel();
nav_set_selected('Access Lists');
}
function post() {
if (! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
if ((argc() == 2) && (argv(1) === 'new')) {
check_form_security_token_redirectOnErr('/lists/new', 'group_edit');
$name = notags(trim($_POST['groupname']));
$public = intval($_POST['public']);
$r = AccessList::add(local_channel(),$name,$public);
if ($r) {
info( t('Access list created.') . EOL );
}
else {
notice( t('Could not create access list.') . EOL );
}
goaway(z_root() . '/lists');
}
if ((argc() == 2) && (intval(argv(1)))) {
check_form_security_token_redirectOnErr('/lists', 'group_edit');
$r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1",
intval(argv(1)),
intval(local_channel())
);
if (! $r) {
notice( t('Access list not found.') . EOL );
goaway(z_root() . '/connections');
}
$group = array_shift($r);
$groupname = notags(trim($_POST['groupname']));
$public = intval($_POST['public']);
if ((strlen($groupname)) && (($groupname != $group['gname']) || ($public != $group['visible']))) {
$r = q("UPDATE pgrp SET gname = '%s', visible = %d WHERE uid = %d AND id = %d",
dbesc($groupname),
intval($public),
intval(local_channel()),
intval($group['id'])
);
if ($r) {
info( t('Access list updated.') . EOL );
}
Libsync::build_sync_packet(local_channel(),null,true);
}
goaway(z_root() . '/lists/' . argv(1) . '/' . argv(2));
}
return;
}
function get() {
$change = false;
logger('mod_lists: ' . \App::$cmd,LOGGER_DEBUG);
if (! local_channel()) {
notice( t('Permission denied') . EOL);
return;
}
// Switch to text mode interface if we have more than 'n' contacts or group members
$switchtotext = get_pconfig(local_channel(),'system','groupedit_image_limit');
if ($switchtotext === false) {
$switchtotext = get_config('system','groupedit_image_limit');
}
if ($switchtotext === false) {
$switchtotext = 400;
}
if ((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) {
$new = (((argc() == 2) && (argv(1) === 'new')) ? true : false);
$groups = q("SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC",
intval(local_channel())
);
$i = 0;
foreach ($groups as $group) {
$entries[$i]['name'] = $group['gname'];
$entries[$i]['id'] = $group['id'];
$entries[$i]['count'] = count(AccessList::members(local_channel(),$group['id']));
$i++;
}
$tpl = get_markup_template('privacy_groups.tpl');
$o = replace_macros($tpl, [
'$title' => t('Access Lists'),
'$add_new_label' => t('Create access list'),
'$new' => $new,
// new group form
'$gname' => array('groupname',t('Access list name')),
'$public' => array('public',t('Members are visible to other channels'), false),
'$form_security_token' => get_form_security_token("group_edit"),
'$submit' => t('Submit'),
// groups list
'$title' => t('Access Lists'),
'$name_label' => t('Name'),
'$count_label' => t('Members'),
'$entries' => $entries
]);
return $o;
}
$context = array('$submit' => t('Submit'));
$tpl = get_markup_template('group_edit.tpl');
if((argc() == 3) && (argv(1) === 'drop')) {
check_form_security_token_redirectOnErr('/lists', 'group_drop', 't');
if(intval(argv(2))) {
$r = q("SELECT gname FROM pgrp WHERE id = %d AND uid = %d LIMIT 1",
intval(argv(2)),
intval(local_channel())
);
if($r)
$result = AccessList::remove(local_channel(),$r[0]['gname']);
if($result)
info( t('Access list removed.') . EOL);
else
notice( t('Unable to remove access list.') . EOL);
}
goaway(z_root() . '/lists');
// NOTREACHED
}
if((argc() > 2) && intval(argv(1)) && argv(2)) {
check_form_security_token_ForbiddenOnErr('group_member_change', 't');
$r = q("SELECT abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 limit 1",
dbesc(base64url_decode(argv(2))),
intval(local_channel())
);
if(count($r))
$change = base64url_decode(argv(2));
}
if((argc() > 1) && (intval(argv(1)))) {
require_once('include/acl_selectors.php');
$r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1",
intval(argv(1)),
intval(local_channel())
);
if(! $r) {
notice( t('Access list not found.') . EOL );
goaway(z_root() . '/connections');
}
$group = $r[0];
$members = AccessList::members(local_channel(), $group['id']);
$preselected = array();
if(count($members)) {
foreach($members as $member)
if(! in_array($member['xchan_hash'],$preselected))
$preselected[] = $member['xchan_hash'];
}
if($change) {
if(in_array($change,$preselected)) {
AccessList::member_remove(local_channel(),$group['gname'],$change);
}
else {
AccessList::member_add(local_channel(),$group['gname'],$change);
}
$members = AccessList::members(local_channel(), $group['id']);
$preselected = array();
if(count($members)) {
foreach($members as $member)
$preselected[] = $member['xchan_hash'];
}
}
$context = $context + array(
'$title' => sprintf(t('Access List: %s'), $group['gname']),
'$details_label' => t('Edit'),
'$gname' => array('groupname',t('Access list name: '),$group['gname'], ''),
'$gid' => $group['id'],
'$drop' => $drop_txt,
'$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''),
'$form_security_token_edit' => get_form_security_token('group_edit'),
'$delete' => t('Delete access list'),
'$form_security_token_drop' => get_form_security_token("group_drop"),
);
}
if(! isset($group))
return;
$groupeditor = array(
'label_members' => t('List members'),
'members' => array(),
'label_contacts' => t('Not in this list'),
'contacts' => array(),
);
$sec_token = addslashes(get_form_security_token('group_member_change'));
$textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : 'card');
foreach($members as $member) {
if($member['xchan_url']) {
$member['archived'] = (intval($member['abook_archived']) ? true : false);
$member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;';
$groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode);
}
else
AccessList::member_remove(local_channel(),$group['gname'],$member['xchan_hash']);
}
$r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_self = 0 and abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc",
intval(local_channel())
);
if(count($r)) {
$textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : 'card');
foreach($r as $member) {
if(! in_array($member['xchan_hash'],$preselected)) {
$member['archived'] = (intval($member['abook_archived']) ? true : false);
$member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;';
$groupeditor['contacts'][] = micropro($member,true,'mpall', $textmode);
}
}
}
$context['$groupeditor'] = $groupeditor;
$context['$desc'] = t('Select a channel to toggle membership');
if($change) {
$tpl = get_markup_template('groupeditor.tpl');
echo replace_macros($tpl, $context);
killme();
}
return replace_macros($tpl, $context);
}
}

View file

@ -76,7 +76,7 @@ class Lockview extends \Zotlabs\Web\Controller {
killme();
}
if(($item['item_private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid']))
if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid']))
&& (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) {
// if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any

View file

@ -3,6 +3,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\PConfig;
require_once('include/security.php');
@ -20,16 +21,22 @@ class Manage extends Controller {
$change_channel = ((argc() > 1) ? intval(argv(1)) : 0);
if ((argc() > 2) && (argv(2) === 'default')) {
$r = q("select channel_id from channel where channel_id = %d and channel_account_id = %d limit 1",
intval($change_channel),
intval(get_account_id())
);
if ($r) {
q("update account set account_default_channel = %d where account_id = %d",
if (argc() > 2) {
if (argv(2) === 'default') {
$r = q("select channel_id from channel where channel_id = %d and channel_account_id = %d limit 1",
intval($change_channel),
intval(get_account_id())
);
if ($r) {
q("update account set account_default_channel = %d where account_id = %d",
intval($change_channel),
intval(get_account_id())
);
}
}
elseif (argv(2) === 'menu') {
$state = intval(PConfig::get($change_channel,'system','include_in_menu', 0));
PConfig::set($change_channel,'system','include_in_menu',1 - $state);
}
goaway(z_root() . '/manage');
}
@ -60,6 +67,7 @@ class Manage extends Controller {
$channels = $r;
for ($x = 0; $x < count($channels); $x ++) {
$channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']);
$channels[$x]['include_in_menu'] = intval(PConfig::get($channels[$x]['channel_id'],'system','include_in_menu',0));
$channels[$x]['default'] = (($channels[$x]['channel_id'] == $account['account_default_channel']) ? "1" : '');
$channels[$x]['default_links'] = '1';
$channels[$x]['collections_label'] = t('Collection');
@ -175,6 +183,8 @@ class Manage extends Controller {
'$desc' => t('Switch to one of your channels by selecting it.'),
'$msg_default' => t('Default Channel'),
'$msg_make_default' => t('Make Default'),
'$msg_include' => t('Add to menu'),
'$msg_no_include' => t('Remove from menu'),
'$create' => $create,
'$all_channels' => $channels,
'$mail_format' => t('%d new messages'),

View file

@ -64,7 +64,7 @@ class Network extends Controller {
$category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
$hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
$verb = ((x($_REQUEST,'verb')) ? $_REQUEST['verb'] : '');
$dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0);
$order = get_pconfig(local_channel(), 'mod_network', 'order', 0);
switch ($order) {
@ -122,8 +122,8 @@ class Network extends Controller {
$def_acl = [ 'allow_gid' => '<' . $r[0]['hash'] . '>' ];
}
$default_cmin = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmin',0) : (-1));
$default_cmax = ((Apps::system_app_installed(local_channel(),'Affinity Tool')) ? get_pconfig(local_channel(),'affinity','cmax',99) : (-1));
$default_cmin = ((Apps::system_app_installed(local_channel(),'Friend Zoom')) ? get_pconfig(local_channel(),'affinity','cmin',0) : (-1));
$default_cmax = ((Apps::system_app_installed(local_channel(),'Friend Zoom')) ? get_pconfig(local_channel(),'affinity','cmax',99) : (-1));
$cid = ((x($_GET,'cid')) ? intval($_GET['cid']) : 0);
$star = ((x($_GET,'star')) ? intval($_GET['star']) : 0);
@ -229,7 +229,7 @@ class Network extends Controller {
if ($group) {
$contact_str = '';
$contacts = AccessList::members($group);
$contacts = AccessList::members(local_channel(),$group);
if ($contacts) {
$contact_str = ids_to_querystr($contacts,'xchan',true);
}
@ -336,6 +336,7 @@ class Network extends Controller {
'$conv' => (($conv) ? $conv : '0'),
'$spam' => (($spam) ? $spam : '0'),
'$fh' => '0',
'$dm' => (($dm) ? $dm : '0'),
'$nouveau' => (($nouveau) ? $nouveau : '0'),
'$wall' => '0',
'$static' => $static,
@ -382,15 +383,27 @@ class Network extends Controller {
}
if ($verb) {
$sql_extra .= sprintf(" AND item.verb like '%s' ",
dbesc(protect_sprintf('%' . $verb . '%'))
);
if (substr($verb,0,1) === '.') {
$verb = substr($verb,1);
$sql_extra .= sprintf(" AND item.obj_type like '%s' ",
dbesc(protect_sprintf('%' . $verb . '%'))
);
}
else {
$sql_extra .= sprintf(" AND item.verb like '%s' ",
dbesc(protect_sprintf('%' . $verb . '%'))
);
}
}
if (strlen($file)) {
$sql_extra .= term_query('item',$file,TERM_FILE);
}
if ($dm) {
$sql_extra .= " and item_private = 2 ";
}
if ($conv) {
$item_thread_top = '';

View file

@ -0,0 +1,28 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libsync;
use Zotlabs\Web\Controller;
class Nocomment extends Controller {
function get() {
$desc = t('This app allows you to disable comments on individual posts.');
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'No Comment'))) {
return $text;
}
$desc = t('This app is installed. A button to control the ability to comment may be found below the post editor.');
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
return $text;
}
}

View file

@ -3,7 +3,7 @@ namespace Zotlabs\Module; /** @file */
use Zotlabs\Lib\Libsync;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
class Notes extends Controller {
@ -26,17 +26,38 @@ class Notes extends Controller {
set_pconfig(local_channel(),'notes','text.bak',$old_text);
}
set_pconfig(local_channel(),'notes','text',$body);
}
// push updates to channel clones
// push updates to channel clones
if((argc() > 1) && (argv(1) === 'sync')) {
Libsync::build_sync_packet();
}
if((argc() > 1) && (argv(1) === 'sync')) {
Libsync::build_sync_packet();
}
logger('notes saved.', LOGGER_DEBUG);
json_return_and_die($ret);
logger('notes saved.', LOGGER_DEBUG);
json_return_and_die($ret);
}
}
function get() {
$desc = t('This app allows you to create private notes for your personal use.');
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Notes'))) {
return $text;
}
$desc = t('This app is installed. The Notes tool can be found on your network stream page.');
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
return $text;
}
}

View file

@ -33,7 +33,7 @@ class Photo extends \Zotlabs\Web\Controller {
$channel = channelx_by_n($r[0]['uid']);
$obj = json_decode($r[0]['obj'],true);
$obj['actor'] = Activity::encode_person($channel,true,((defined('NOMADIC')) ? false : true));
$obj['actor'] = Activity::encode_person($channel,true,((get_config('system','activitypub')) ? true : false));
$x = array_merge(['@context' => [
ACTIVITYSTREAMS_JSONLD_REV,

View file

@ -0,0 +1,24 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
class Photomap extends Controller {
function get() {
$desc = t('This app provides a displayable map when viewing detail of photos that contain location information.');
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Photomap'))) {
return $text;
}
return $text . '<br><br>' . t('This app is currently installed.');
}
}

View file

@ -2,6 +2,7 @@
namespace Zotlabs\Module;
use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libprofile;
use Zotlabs\Lib\PermissionDescription;
@ -215,6 +216,71 @@ class Photos extends Controller {
}
}
// this still needs some work
if(defined('FIXED')) {
if((x($_POST,'rotate') !== false) && ( (intval($_POST['rotate']) == 1) || (intval($_POST['rotate']) == 2) )) {
logger('rotate');
$resource_id = argv(2);
$r = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = 0 limit 1",
dbesc($resource_id),
intval($page_owner_uid)
);
if($r) {
$ph = photo_factory(@file_get_contents(dbunescbin($r[0]['content'])), $r[0]['mimetype']);
if($ph->is_valid()) {
$rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 );
$ph->rotate($rotate_deg);
$edited = datetime_convert();
q("update attach set filesize = %d, edited = '%s' where hash = '%s' and uid = %d",
strlen($ph->imageString()),
dbescdate($edited),
dbesc($resource_id),
intval($page_owner_uid)
);
$ph->saveImage(dbunescbin($r[0]['content']));
$arr = [
'aid' => get_account_id(),
'uid' => intval($page_owner_uid),
'resource_id' => dbesc($resource_id),
'filename' => $r[0]['filename'],
'imgscale' => 0,
'album' => $r[0]['album'],
'os_path' => $r[0]['os_path'],
'os_storage' => 1,
'os_syspath' => dbunescbin($r[0]['content']),
'display_path' => $r[0]['display_path'],
'photo_usage' => PHOTO_NORMAL,
'edited' => dbescdate($edited)
];
$ph->save($arr);
unset($arr['os_syspath']);
if($width > 1024 || $height > 1024)
$ph->scaleImage(1024);
$ph->storeThumbnail($arr, PHOTO_RES_1024);
if($width > 640 || $height > 640)
$ph->scaleImage(640);
$ph->storeThumbnail($arr, PHOTO_RES_640);
if($width > 320 || $height > 320)
$ph->scaleImage(320);
$ph->storeThumbnail($arr, PHOTO_RES_320);
}
}
}}
if((argc() > 2) && ((x($_POST,'desc') !== false) || (x($_POST,'newtag') !== false))) {
$desc = ((x($_POST,'desc')) ? notags(trim($_POST['desc'])) : '');
@ -470,7 +536,7 @@ class Photos extends Controller {
return;
}
$unsafe = ((array_key_exists('unsafe',$_REQUEST) && $_REQUEST['unsafe']) ? 1 : 0);
$unsafe = 1 - get_safemode();
require_once('include/bbcode.php');
require_once('include/security.php');
@ -953,7 +1019,7 @@ class Photos extends Controller {
);
}
if($link_item['coord']) {
if($link_item['coord'] && Apps::system_app_installed($owner_uid,'Photomap')) {
$map = generate_map($link_item['coord']);
}
}

View file

@ -5,6 +5,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Enotify;
use Zotlabs\Lib\Apps;
require_once('include/bbcode.php');
@ -164,6 +165,10 @@ class Ping extends Controller {
$notify_pubs = ((local_channel()) ? ($vnotify & VNOTIFY_PUBS) && $discover_tab_on : $discover_tab_on);
if ($notify_pubs && local_channel() && ! Apps::system_app_installed(local_channel(),'Public Stream')) {
$notify_pubs = false;
}
$sys = get_sys_channel();
if ($notify_pubs) {
@ -291,6 +296,7 @@ class Ping extends Controller {
$mid = basename($tt['link']);
$mid = ((strpos($mid, 'b64.') === 0) ? @base64url_decode(substr($mid, 4)) : $mid);
if (in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) {
// we need the thread parent
@ -393,7 +399,7 @@ class Ping extends Controller {
if ($r) {
foreach ($r as $rr) {
$local_result[] = [
'notify_link' => z_root() . '/connections/ifpending',
'notify_link' => z_root() . '/connections/' . $rr['abook_id'],
'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'],
'url' => $rr['xchan_url'],

View file

@ -13,25 +13,30 @@ class Poster extends Controller {
$nick = argv(1);
$hash = argv(2);
if(! ($nick && $hash)) {
if (! ($nick && $hash)) {
return;
}
$u = channelx_by_nick($nick);
if (! $u) {
return;
}
$sql_extra = permissions_sql(intval($u['channel_id']));
$r = q("select content from attach where hash = '%s' and uid = %d and os_storage = 1 $sql_extra limit 1",
dbesc($hash),
intval($u['channel_id'])
);
if($r) {
if ($r) {
$path = dbunescbin($r[0]['content']);
if($path && @file_exists($path . '.thumb')) {
if ($path && @file_exists($path . '.thumb')) {
header('Content-Type: image/jpeg');
echo file_get_contents($path . '.thumb');
killme();
}
}
killme();
}
}

View file

@ -75,7 +75,7 @@ class Profile extends \Zotlabs\Web\Controller {
$chan = channelx_by_nick(argv(1));
if(! $chan)
http_status_exit(404, 'Not found');
$p = Activity::encode_person($chan,true,((defined('NOMADIC')) ? false : true));
$p = Activity::encode_person($chan,true,((get_config('system','activitypub')) ? true : false));
if(! $p) {
http_status_exit(404, 'Not found');
}

View file

@ -1,23 +1,23 @@
<?php
namespace Zotlabs\Module;
/*
* @file Profile_photo.php
* @brief Module-file with functions for uploading and scaling of profile-photos
*
*/
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libprofile;
/*
* @file Profile_photo.php
* @brief Module-file with functions for handling of profile-photos
*
*/
use Zotlabs\Daemon\Master;
require_once('include/photo_factory.php');
require_once('include/photos.php');
class Profile_photo extends Controller {
@ -33,7 +33,7 @@ class Profile_photo extends Controller {
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
Libprofile::load($channel['channel_address']);
}
@ -47,49 +47,46 @@ class Profile_photo extends Controller {
function post() {
if(! local_channel()) {
if (! local_channel()) {
return;
}
check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo');
if((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
if ((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) {
// logger('crop: ' . print_r($_POST,true));
// phase 2 - we have finished cropping
if(argc() != 2) {
if (argc() != 2) {
notice( t('Image uploaded but image cropping failed.') . EOL );
return;
}
$image_id = argv(1);
if(substr($image_id,-2,1) == '-') {
if (substr($image_id,-2,1) == '-') {
$scale = substr($image_id,-1,1);
$image_id = substr($image_id,0,-2);
}
// unless proven otherwise
$is_default_profile = 1;
if($_REQUEST['profile']) {
if ($_REQUEST['profile']) {
$r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1",
intval($_REQUEST['profile']),
intval(local_channel())
);
if($r) {
$profile = $r[0];
if(! intval($profile['is_default']))
if ($r) {
$profile = array_shift($r);
if (! intval($profile['is_default'])) {
$is_default_profile = 0;
}
}
}
$srcX = intval($_POST['xstart']);
$srcY = intval($_POST['ystart']);
$srcW = intval($_POST['xfinal']) - $srcX;
@ -99,13 +96,13 @@ class Profile_photo extends Controller {
dbesc($image_id),
dbesc(local_channel()),
intval($scale));
if($r) {
if ($r) {
$base_image = $r[0];
$base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
$base_image = array_shift($r);
$base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content']));
$im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
if ($im->is_valid()) {
$im->cropImage(300,$srcX,$srcY,$srcW,$srcH);
@ -126,19 +123,19 @@ class Profile_photo extends Controller {
$p['imgscale'] = PHOTO_RES_PROFILE_300;
$p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL);
$r1 = $im->save($p);
$r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300);
$im->scaleImage(80);
$p['imgscale'] = PHOTO_RES_PROFILE_80;
$r2 = $im->save($p);
$r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80);
$im->scaleImage(48);
$p['imgscale'] = PHOTO_RES_PROFILE_48;
$r3 = $im->save($p);
$r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48);
if($r1 === false || $r2 === false || $r3 === false) {
if ($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
$x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ",
@ -151,11 +148,11 @@ class Profile_photo extends Controller {
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
// If setting for the default profile, unset the profile photo flag from any other photos I own
if($is_default_profile) {
if ($is_default_profile) {
$r = q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d",
dbesc(z_root() . '/photo/profile/l/' . local_channel()),
@ -209,9 +206,9 @@ class Profile_photo extends Controller {
photo_profile_setperms(local_channel(),$base_image['resource_id'],$_REQUEST['profile']);
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
if ($sync) {
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles));
}
// Similarly, tell the nav bar to bypass the cache and update the avatar image.
$_SESSION['reload_avatar'] = true;
@ -219,15 +216,15 @@ class Profile_photo extends Controller {
info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
// Update directory in background
\Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
Master::Summon( [ 'Directory', $channel['channel_id'] ] );
}
else
else {
notice( t('Unable to process image') . EOL);
}
}
goaway(z_root() . '/profiles');
return; // NOTREACHED
}
// A new photo was uploaded. Store it and save some important details
@ -239,7 +236,7 @@ class Profile_photo extends Controller {
$smallest = 0;
if($_REQUEST['importfile']) {
if ($_REQUEST['importfile']) {
$hash = $_REQUEST['importfile'];
$importing = true;
}
@ -248,18 +245,18 @@ class Profile_photo extends Controller {
$matches = [];
$partial = false;
if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
$pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
if($pm) {
logger('Content-Range: ' . print_r($matches,true));
if ($pm) {
logger('Content-Range: ' . print_r($matches,true), LOGGER_DEBUG);
$partial = true;
}
}
if($partial) {
if ($partial) {
$x = save_chunk($channel,$matches[1],$matches[2],$matches[3]);
if($x['partial']) {
if ($x['partial']) {
header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
json_return_and_die($result);
}
@ -276,7 +273,7 @@ class Profile_photo extends Controller {
}
}
else {
if(! array_key_exists('userfile',$_FILES)) {
if (! array_key_exists('userfile',$_FILES)) {
$_FILES['userfile'] = [
'name' => $_FILES['files']['name'],
'type' => $_FILES['files']['type'],
@ -287,29 +284,27 @@ class Profile_photo extends Controller {
}
}
$res = attach_store(\App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash));
$res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash));
logger('attach_store: ' . print_r($res,true));
logger('attach_store: ' . print_r($res,true), LOGGER_DEBUG);
json_return_and_die([ 'message' => $hash ]);
}
if(($res && intval($res['data']['is_photo'])) || $importing) {
if (($res && intval($res['data']['is_photo'])) || $importing) {
$i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($hash),
intval(local_channel())
);
if(! $i) {
if (! $i) {
notice( t('Image upload failed.') . EOL );
return;
}
$os_storage = false;
foreach($i as $ii) {
if(intval($ii['imgscale']) < PHOTO_RES_640) {
foreach ($i as $ii) {
if (intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']);
$imagedata = $ii['content'];
@ -321,12 +316,12 @@ class Profile_photo extends Controller {
$imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata));
$ph = photo_factory($imagedata, $filetype);
if(! $ph->is_valid()) {
if (! $ph->is_valid()) {
notice( t('Unable to process image.') . EOL );
return;
}
return $this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
return $this->profile_photo_crop_ui_head($ph, $hash, $smallest);
// This will "fall through" to the get() method, and since
// App::$data['imagecrop'] is set, it will proceed to cropping
@ -336,7 +331,6 @@ class Profile_photo extends Controller {
/* @brief Generate content of profile-photo view
*
* @param $a Current application
* @return void
*
*/
@ -344,19 +338,20 @@ class Profile_photo extends Controller {
function get() {
if(! local_channel()) {
if (! local_channel()) {
notice( t('Permission denied.') . EOL );
return;
}
$channel = \App::get_channel();
$channel = App::get_channel();
$pf = 0;
$newuser = false;
if(argc() == 2 && argv(1) === 'new')
if (argc() == 2 && argv(1) === 'new') {
$newuser = true;
}
if(argv(1) === 'use') {
if (argv(1) === 'use') {
if (argc() < 3) {
notice( t('Permission denied.') . EOL );
return;
@ -364,7 +359,6 @@ class Profile_photo extends Controller {
$resource_id = argv(2);
$pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0);
$c = q("select id, is_default from profile where uid = %d",
@ -373,7 +367,7 @@ class Profile_photo extends Controller {
$multi_profiles = true;
if(($c) && (count($c) === 1) && (intval($c[0]['is_default']))) {
if (($c) && (count($c) === 1) && (intval($c[0]['is_default']))) {
$_REQUEST['profile'] = $c[0]['id'];
$multi_profiles = false;
}
@ -385,33 +379,34 @@ class Profile_photo extends Controller {
intval(local_channel()),
dbesc($resource_id)
);
if(! $r) {
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
$havescale = false;
foreach($r as $rr) {
if($rr['imgscale'] == PHOTO_RES_PROFILE_80)
foreach ($r as $rr) {
if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) {
$havescale = true;
}
}
// set an already loaded and cropped photo as profile photo
if($havescale) {
if ($havescale) {
// unset any existing profile photos
$r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d",
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval(local_channel()));
intval(local_channel())
);
$r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'",
intval(PHOTO_PROFILE),
intval(local_channel()),
dbesc($resource_id)
);
);
$r = q("UPDATE xchan set xchan_photo_date = '%s'
where xchan_hash = '%s'",
$r = q("UPDATE xchan set xchan_photo_date = '%s' where xchan_hash = '%s'",
dbesc(datetime_convert()),
dbesc($channel['xchan_hash'])
);
@ -419,11 +414,11 @@ class Profile_photo extends Controller {
photo_profile_setperms(local_channel(),$resource_id,$_REQUEST['profile']);
$sync = attach_export_data($channel,$resource_id);
if($sync)
if ($sync) {
Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
}
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
Master::Summon( [ 'Directory',local_channel() ] );
goaway(z_root() . '/profiles');
}
@ -432,154 +427,148 @@ class Profile_photo extends Controller {
intval(local_channel())
);
if(! $r) {
if (! $r) {
notice( t('Photo not available.') . EOL );
return;
}
if(intval($r[0]['os_storage']))
if (intval($r[0]['os_storage'])) {
$data = @file_get_contents(dbunescbin($r[0]['content']));
else
}
else {
$data = dbunescbin($r[0]['content']);
}
$ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if($ph->is_valid()) {
if ($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
$i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($r[0]['resource_id']),
intval(local_channel())
);
if($i) {
if ($i) {
$hash = $i[0]['resource_id'];
foreach($i as $ii) {
if(intval($ii['imgscale']) < PHOTO_RES_640) {
foreach ($i as $ii) {
if (intval($ii['imgscale']) < PHOTO_RES_640) {
$smallest = intval($ii['imgscale']);
}
}
}
}
if($multi_profiles) {
\App::$data['importfile'] = $resource_id;
if ($multi_profiles) {
App::$data['importfile'] = $resource_id;
}
else {
$this->profile_photo_crop_ui_head($a, $ph, $hash, $smallest);
$this->profile_photo_crop_ui_head($ph, $hash, $smallest);
}
// falls through with App::$data['imagecrop'] set so we go straight to the cropping section
}
// present an upload form
$profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc",
intval(local_channel())
);
if($profiles) {
for($x = 0; $x < count($profiles); $x ++) {
if ($profiles) {
for ($x = 0; $x < count($profiles); $x ++) {
$profiles[$x]['selected'] = false;
if($pf && $profiles[$x]['id'] == $pf)
if ($pf && $profiles[$x]['id'] == $pf) {
$profiles[$x]['selected'] = true;
if((! $pf) && $profiles[$x]['is_default'])
}
if ((! $pf) && $profiles[$x]['is_default']) {
$profiles[$x]['selected'] = true;
}
}
}
$importing = ((array_key_exists('importfile',\App::$data)) ? true : false);
$importing = ((array_key_exists('importfile',App::$data)) ? true : false);
if(! x(\App::$data,'imagecrop')) {
if (! array_key_exists('imagecrop', App::$data)) {
$tpl = get_markup_template('profile_photo.tpl');
$o .= replace_macros($tpl,array(
'$user' => \App::$channel['channel_address'],
'$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')),
'$importfile' => (($importing) ? \App::$data['importfile'] : ''),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')),
'$submit' => (($importing) ? t('Use') : t('Upload')),
'$profiles' => $profiles,
'$single' => ((count($profiles) == 1) ? true : false),
'$profile0' => $profiles[0],
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
$o .= replace_macros($tpl, [
'$user' => App::$channel['channel_address'],
'$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')),
'$importfile' => (($importing) ? App::$data['importfile'] : ''),
'$lbl_upfile' => t('Upload File:'),
'$lbl_profiles' => t('Select a profile:'),
'$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')),
'$submit' => (($importing) ? t('Use') : t('Upload')),
'$profiles' => $profiles,
'$single' => ((count($profiles) == 1) ? true : false),
'$profile0' => $profiles[0],
'$embedPhotos' => t('Use a photo from your albums'),
'$embedPhotosModalTitle' => t('Use a photo from your albums'),
'$embedPhotosModalCancel' => t('Cancel'),
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$select' => t('Select existing photo'),
));
'$embedPhotosModalOK' => t('OK'),
'$modalchooseimages' => t('Choose images to embed'),
'$modalchoosealbum' => t('Choose an album'),
'$modaldiffalbum' => t('Choose a different album'),
'$modalerrorlist' => t('Error getting album list'),
'$modalerrorlink' => t('Error getting photo link'),
'$modalerroralbum' => t('Error getting album'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$select' => t('Select previously uploaded photo'),
]);
call_hooks('profile_photo_content_end', $o);
return $o;
}
else {
// present a cropping form
$filename = \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution'];
$resolution = \App::$data['imagecrop_resolution'];
$tpl = get_markup_template("cropbody.tpl");
$o .= replace_macros($tpl,array(
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => \App::$data['imagecrop'] . '-' . \App::$data['imagecrop_resolution'],
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
$filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'];
$resolution = App::$data['imagecrop_resolution'];
$o .= replace_macros(get_markup_template('cropbody.tpl'), [
'$filename' => $filename,
'$profile' => intval($_REQUEST['profile']),
'$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'],
'$image_url' => z_root() . '/photo/' . $filename,
'$title' => t('Crop Image'),
'$desc' => t('Please adjust the image cropping for optimum viewing.'),
'$form_security_token' => get_form_security_token("profile_photo"),
'$done' => t('Done Editing')
));
'$done' => t('Done Editing')
]);
return $o;
}
return; // NOTREACHED
}
/* @brief Generate the UI for photo-cropping
*
* @param $a Current application
* @param $ph Photo-Factory
* @return void
*
*/
function profile_photo_crop_ui_head(&$a, $ph, $hash, $smallest){
function profile_photo_crop_ui_head($ph, $hash, $smallest) {
$max_length = get_config('system','max_image_length');
if(! $max_length)
if (! $max_length) {
$max_length = MAX_IMAGE_LENGTH;
if($max_length > 0)
}
if ($max_length > 0) {
$ph->scaleImage($max_length);
}
App::$data['width'] = $ph->getWidth();
App::$data['height'] = $ph->getHeight();
\App::$data['width'] = $ph->getWidth();
\App::$data['height'] = $ph->getHeight();
if(\App::$data['width'] < 500 || \App::$data['height'] < 500) {
if (App::$data['width'] < 500 || App::$data['height'] < 500) {
$ph->scaleImageUp(400);
\App::$data['width'] = $ph->getWidth();
\App::$data['height'] = $ph->getHeight();
App::$data['width'] = $ph->getWidth();
App::$data['height'] = $ph->getHeight();
}
\App::$data['imagecrop'] = $hash;
\App::$data['imagecrop_resolution'] = $smallest;
\App::$page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array());
App::$data['imagecrop'] = $hash;
App::$data['imagecrop_resolution'] = $smallest;
App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []);
return;
}
}

View file

@ -5,6 +5,7 @@ use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Libprofile;
use Zotlabs\Daemon\Master;
use Sabre\VObject\Reader;
@ -77,7 +78,7 @@ class Profiles extends Controller {
[
'aid' => intval(get_account_id()),
'uid' => intval(local_channel()),
'profile_guid' => random_string(),
'profile_guid' => new_uuid(),
'profile_name' => $name,
'fullname' => $r1[0]['fullname'],
'photo' => $r1[0]['photo'],
@ -108,18 +109,18 @@ class Profiles extends Controller {
$name = t('Profile-') . ($num_profiles + 1);
$r1 = q("SELECT * FROM profile WHERE uid = %d AND id = %d LIMIT 1",
intval(local_channel()),
intval(\App::$argv[2])
intval(argv(2))
);
if(! count($r1)) {
notice( t('Profile unavailable to clone.') . EOL);
\App::$error = 404;
App::$error = 404;
return;
}
unset($r1[0]['id']);
$r1[0]['is_default'] = 0;
$r1[0]['publish'] = 0;
$r1[0]['profile_name'] = dbesc($name);
$r1[0]['profile_guid'] = dbesc(random_string());
$r1[0]['profile_name'] = $name;
$r1[0]['profile_guid'] = new_uuid();
create_table_from_array('profile', $r1[0]);
@ -163,12 +164,7 @@ class Profiles extends Controller {
echo json_encode($r1[0]);
killme();
}
// Run Libprofile::load() here to make sure the theme is set before
// we start loading content
if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) {
if(feature_enabled(local_channel(),'multi_profiles'))
$id = argv(1);
@ -191,7 +187,7 @@ class Profiles extends Controller {
$chan = App::get_channel();
Libprofile::load($chan['channel_address'],$r[0]['id']);
Libprofile::load($chan['channel_address'],$r[0]['profile_guid']);
}
}
@ -323,7 +319,7 @@ class Profiles extends Controller {
$orig_vcard = null;
$channel = \App::get_channel();
$channel = App::get_channel();
$default_vcard_cat = ((defined('DEFAULT_VCARD_CAT')) ? DEFAULT_VCARD_CAT : 'HOME');
@ -594,15 +590,15 @@ class Profiles extends Controller {
if($r)
info( t('Profile updated.') . EOL);
$r = q("select * from profile where id = %d and uid = %d limit 1",
$sync = q("select * from profile where id = %d and uid = %d limit 1",
intval(argv(1)),
intval(local_channel())
);
if($r) {
Libsync::build_sync_packet(local_channel(),array('profile' => $r));
if($sync) {
Libsync::build_sync_packet(local_channel(),array('profile' => $sync));
}
$channel = \App::get_channel();
$channel = App::get_channel();
if($namechanged && $is_default) {
$r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s'",
@ -617,9 +613,8 @@ class Profiles extends Controller {
}
if($is_default) {
// reload the info for the sidebar widget - why does this not work?
Libprofile::load($channel['channel_address']);
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
Master::Summon(array('Directory',local_channel()));
goaway(z_root() . '/profiles/' . $sync[0]['id']);
}
}
}

View file

@ -1,11 +1,15 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription;
require_once('include/conversation.php');
require_once('include/acl_selectors.php');
class Pubstream extends \Zotlabs\Web\Controller {
class Pubstream extends Controller {
function get($update = 0, $load = false) {
@ -51,7 +55,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
if(local_channel() && (! $update)) {
$channel = \App::get_channel();
$channel = App::get_channel();
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
@ -66,7 +70,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'default_location' => $channel['channel_location'],
'nickname' => $channel['channel_address'],
'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
'acl' => populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'acl' => populate_acl($channel_acl,true,PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
'permissions' => $channel_acl,
'bang' => '',
'visitor' => true,
@ -105,14 +109,14 @@ class Pubstream extends \Zotlabs\Web\Controller {
$o .= '<div id="live-pubstream"></div>' . "\r\n";
$o .= "<script> var profile_uid = " . ((intval(local_channel())) ? local_channel() : (-1))
. "; var profile_page = " . \App::$pager['page']
. "; var profile_page = " . App::$pager['page']
. "; divmore_height = " . intval($maxheight) . "; </script>\r\n";
//if we got a decoded hash we must encode it again before handing to javascript
if($decoded)
$mid = 'b64.' . base64url_encode($mid);
\App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
'$baseurl' => z_root(),
'$pgtype' => 'pubstream',
'$uid' => ((local_channel()) ? local_channel() : '0'),
@ -125,11 +129,12 @@ class Pubstream extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '1',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$list' => '0',
'$static' => $static,
'$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
'$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1),
'$search' => '',
'$xchan' => '',
'$order' => 'comment',
@ -149,8 +154,8 @@ class Pubstream extends \Zotlabs\Web\Controller {
$pager_sql = '';
}
else {
\App::set_pager_itemspage(20);
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
App::set_pager_itemspage(20);
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
}
require_once('include/channel.php');
@ -163,7 +168,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$sys = get_sys_channel();
$uids = " and item.uid = " . intval($sys['channel_id']) . " ";
$sql_extra = item_permissions_sql($sys['channel_id']);
\App::$data['firehose'] = intval($sys['channel_id']);
App::$data['firehose'] = intval($sys['channel_id']);
}
if(get_config('system','public_list_mode'))
@ -179,7 +184,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : '');
$net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : '');
$abook_uids = " and abook.abook_channel = " . intval(\App::$profile['profile_uid']) . " ";
$abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " ";
$simple_update = (($_SESSION['loadtime']) ? " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' " : '');

View file

@ -74,7 +74,3 @@ These are handled in a similar fashion to their counterparts in the Unix shell
or C/C++ languages. Do not confuse the argc(),argv() functions with the
global variables $argc,$argv which are passed to command line programs. These
are handled separately by command line and Zotlabs/Daemon class functions.

View file

@ -1,68 +1,76 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
class Removeaccount extends \Zotlabs\Web\Controller {
class Removeaccount extends Controller {
function post() {
if(! local_channel())
if (! local_channel()) {
return;
}
if($_SESSION['delegate'])
if ($_SESSION['delegate']) {
return;
}
if((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password']))))
if ((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password'])))) {
return;
}
if((! x($_POST,'verify')) || (! strlen(trim($_POST['verify']))))
if ((! x($_POST,'verify')) || (! strlen(trim($_POST['verify'])))) {
return;
}
if($_POST['verify'] !== $_SESSION['remove_account_verify'])
if ($_POST['verify'] !== $_SESSION['remove_account_verify']) {
return;
}
$account = \App::get_account();
$account = App::get_account();
$account_id = get_account_id();
$x = account_verify_password($account['account_email'],$_POST['qxz_password']);
if(! ($x && $x['account']))
if (! ($account && $account_id)) {
return;
}
$x = account_verify_password($account['account_email'],$_POST['qxz_password']);
if (! ($x && $x['account'])) {
return;
}
if($account['account_password_changed'] > NULL_DATE) {
if ($account['account_password_changed'] > NULL_DATE) {
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
if($account['account_password_changed'] > d1) {
if ($account['account_password_changed'] > d1) {
notice( t('Account removals are not allowed within 48 hours of changing the account password.') . EOL);
return;
}
}
$global_remove = intval($_POST['global']);
account_remove($account_id, 1 - $global_remove);
account_remove($account_id);
}
function get() {
if(! local_channel())
if (! local_channel()) {
goaway(z_root());
}
$hash = random_string();
$_SESSION['remove_account_verify'] = $hash;
$tpl = get_markup_template('removeaccount.tpl');
$o .= replace_macros($tpl, array(
$o .= replace_macros(get_markup_template('removeaccount.tpl'), [
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove This Account'),
'$desc' => array(t('WARNING: '), t('This account and all its channels will be completely removed from the network. '), t('This action is permanent and can not be undone!')),
'$passwd' => t('Please enter your password for verification:'),
'$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')),
'$submit' => t('Remove Account')
));
return $o;
'$hash' => $hash,
'$title' => t('Remove This Account'),
'$desc' => [ t('WARNING: '), t('This account and all its channels will be completely removed from this server. '), t('This action is permanent and can not be undone!') ],
'$passwd' => t('Please enter your password for verification:'),
'$submit' => t('Remove Account')
]);
return $o;
}
}

View file

@ -1,35 +1,45 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
class Removeme extends \Zotlabs\Web\Controller {
class Removeme extends Controller {
function post() {
if(! local_channel())
if (! local_channel()) {
return;
}
if($_SESSION['delegate'])
if ($_SESSION['delegate']) {
return;
}
if((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password']))))
if ((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password'])))) {
return;
}
if((! x($_POST,'verify')) || (! strlen(trim($_POST['verify']))))
if ((! x($_POST,'verify')) || (! strlen(trim($_POST['verify'])))) {
return;
}
if($_POST['verify'] !== $_SESSION['remove_account_verify'])
if ($_POST['verify'] !== $_SESSION['remove_channel_verify']) {
return;
$account = \App::get_account();
}
$account = App::get_account();
if (! $account) {
return;
}
$x = account_verify_password($account['account_email'],$_POST['qxz_password']);
if(! ($x && $x['account']))
if (! ($x && $x['account'])) {
return;
}
if($account['account_password_changed'] > NULL_DATE) {
if ($account['account_password_changed'] > NULL_DATE) {
$d1 = datetime_convert('UTC','UTC','now - 48 hours');
if($account['account_password_changed'] > d1) {
notice( t('Channel removals are not allowed within 48 hours of changing the account password.') . EOL);
@ -37,35 +47,30 @@ class Removeme extends \Zotlabs\Web\Controller {
}
}
$global_remove = intval($_POST['global']);
channel_remove(local_channel(),1 - $global_remove,true);
channel_remove(local_channel(),true,true);
}
function get() {
if(! local_channel())
if (! local_channel()) {
goaway(z_root());
}
$hash = random_string();
$_SESSION['remove_account_verify'] = $hash;
$_SESSION['remove_channel_verify'] = $hash;
$tpl = get_markup_template('removeme.tpl');
$o .= replace_macros($tpl, array(
$o .= replace_macros(get_markup_template('removeme.tpl'), [
'$basedir' => z_root(),
'$hash' => $hash,
'$title' => t('Remove This Channel'),
'$desc' => [ t('WARNING: '), t('This channel will be completely removed from the network. '), t('This action is permanent and can not be undone!') ],
'$desc' => [ t('WARNING: '), t('This channel will be completely removed from this server. '), t('This action is permanent and can not be undone!') ],
'$passwd' => t('Please enter your password for verification:'),
'$global' => [ 'global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), [ t('No'),t('Yes') ] ],
'$submit' => t('Remove Channel')
));
]);
return $o;
}
}

23
Zotlabs/Module/Safe.php Normal file
View file

@ -0,0 +1,23 @@
<?php
namespace Zotlabs\Module;
use Zotlabs\Web\Controller;
class Safe extends Controller {
function init() {
$x = get_safemode();
if ($x) {
$_SESSION['safemode'] = 0;
}
else {
$_SESSION['safemode'] = 1;
}
goaway(z_root());
}
}

View file

@ -59,7 +59,8 @@ class Search extends \Zotlabs\Web\Controller {
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
$o .= search($search,'search-box','/search',((local_channel()) ? true : false));
if (strpos($search,'#') === 0) {
$tag = true;
$search = substr($search,1);
@ -131,6 +132,7 @@ class Search extends \Zotlabs\Web\Controller {
'$conv' => '0',
'$spam' => '0',
'$fh' => '0',
'$dm' => '0',
'$nouveau' => '0',
'$wall' => '0',
'$static' => $static,

View file

@ -2,16 +2,22 @@
namespace Zotlabs\Module\Settings;
use App;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\AccessList;
use Zotlabs\Access\Permissions;
use Zotlabs\Access\PermissionRoles;
use Zotlabs\Access\PermissionLimits;
use Zotlabs\Access\AccessControl;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\Permcat;
class Channel {
function post() {
$channel = \App::get_channel();
$channel = App::get_channel();
check_form_security_token_redirectOnErr('/settings', 'settings');
@ -22,11 +28,7 @@ class Channel {
$role = ((x($_POST,'permissions_role')) ? notags(trim($_POST['permissions_role'])) : '');
$oldrole = get_pconfig(local_channel(),'system','permissions_role');
// This mapping can be removed after 3.4 release
if($oldrole === 'social_party') {
$oldrole = 'social_federation';
}
if(($role != $oldrole) || ($role === 'custom')) {
if($role === 'custom') {
@ -37,12 +39,12 @@ class Channel {
intval(local_channel())
);
$global_perms = \Zotlabs\Access\Permissions::Perms();
$global_perms = Permissions::Perms();
foreach($global_perms as $k => $v) {
\Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,intval($_POST[$k]));
PermissionLimits::Set(local_channel(),$k,intval($_POST[$k]));
}
$acl = new \Zotlabs\Access\AccessControl($channel);
$acl = new AccessControl($channel);
$acl->set_from_array($_POST);
$x = $acl->get();
@ -56,7 +58,7 @@ class Channel {
);
}
else {
$role_permissions = \Zotlabs\Access\PermissionRoles::role_perms($_POST['permissions_role']);
$role_permissions = PermissionRoles::role_perms($_POST['permissions_role']);
if(! $role_permissions) {
notice('Permissions category could not be found.');
return;
@ -97,8 +99,8 @@ class Channel {
}
if($role_permissions['perms_connect']) {
$x = \Zotlabs\Access\Permissions::FilledPerms($role_permissions['perms_connect']);
$str = \Zotlabs\Access\Permissions::serialise($x);
$x = Permissions::FilledPerms($role_permissions['perms_connect']);
$str = Permissions::serialise($x);
set_abconfig(local_channel(),$channel['channel_hash'],'system','my_perms',$str);
$autoperms = intval($role_permissions['perms_auto']);
@ -106,7 +108,7 @@ class Channel {
if($role_permissions['limits']) {
foreach($role_permissions['limits'] as $k => $v) {
\Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,$v);
PermissionLimits::Set(local_channel(),$k,$v);
}
}
if(array_key_exists('directory_publish',$role_permissions)) {
@ -118,6 +120,12 @@ class Channel {
set_pconfig(local_channel(),'system','permissions_role',$role);
}
// The post_comments permission is critical to privacy so we always allow you to set it, no matter what
// permission role is in place.
$post_comments = array_key_exists('post_comments',$_POST) ? intval($_POST['post_comments']) : PERMS_SPECIFIC;
PermissionLimits::Set(local_channel(),'post_comments',$post_comments);
$publish = (((x($_POST,'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0);
$username = ((x($_POST,'username')) ? notags(trim($_POST['username'])) : '');
$timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : '');
@ -143,17 +151,16 @@ class Channel {
$cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0);
$suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0);
// $anymention = ((x($_POST,'anymention')) ? intval($_POST['anymention']) : 0);
// $hyperdrive = ((x($_POST,'hyperdrive')) ? intval($_POST['hyperdrive']) : 0);
$hyperdrive = ((x($_POST,'hyperdrive')) ? intval($_POST['hyperdrive']) : 0);
$activitypub = ((x($_POST,'activitypub')) ? intval($_POST['activitypub']) : 0);
$public_uploads = ((isset($_POST['public_uploads'])) ? intval($_POST['public_uploads']) : 0);
$post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0);
$post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0);
$post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0);
$adult = (($_POST['adult'] == 1) ? 1 : 0);
$defpermcat = ((x($_POST,'defpermcat')) ? notags(trim($_POST['defpermcat'])) : 'default');
$cal_first_day = (((x($_POST,'first_day')) && (intval($_POST['first_day']) == 1)) ? 1: 0);
$cal_first_day = (((x($_POST,'first_day')) && intval($_POST['first_day']) >= 0 && intval($_POST['first_day']) < 7) ? intval($_POST['first_day']) : 0);
$mailhost = ((array_key_exists('mailhost',$_POST)) ? notags(trim($_POST['mailhost'])) : '');
$profile_assign = ((x($_POST,'profile_assign')) ? notags(trim($_POST['profile_assign'])) : '');
@ -263,8 +270,8 @@ class Channel {
set_pconfig(local_channel(),'system','email_notify_host',$mailhost);
set_pconfig(local_channel(),'system','profile_assign',$profile_assign);
// set_pconfig(local_channel(),'system','anymention',$anymention);
// set_pconfig(local_channel(),'system','hyperdrive',$hyperdrive);
set_pconfig(local_channel(),'system','force_public_uploads',$public_uploads);
set_pconfig(local_channel(),'system','hyperdrive',$hyperdrive);
set_pconfig(local_channel(),'system','activitypub',$activitypub);
set_pconfig(local_channel(),'system','autoperms',$autoperms);
$r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d",
@ -286,6 +293,10 @@ class Channel {
intval($publish),
intval(local_channel())
);
$r = q("UPDATE xchan SET xchan_hidden = %d WHERE xchan_hash = '%s'",
intval(1 - $publish),
intval($channel['channel_hash'])
);
}
if($name_change) {
@ -300,12 +311,12 @@ class Channel {
);
}
\Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
Master::Summon( [ 'Directory', local_channel() ] );
Libsync::build_sync_packet();
if($email_changed && \App::$config['system']['register_policy'] == REGISTER_VERIFY) {
if($email_changed && App::$config['system']['register_policy'] == REGISTER_VERIFY) {
// FIXME - set to un-verified, blocked and redirect to logout
// Q: Why? Are we verifying people or email addresses?
@ -322,7 +333,7 @@ class Channel {
require_once('include/permissions.php');
$yes_no = array(t('No'),t('Yes'));
$yes_no = [ t('No'), t('Yes') ];
$p = q("SELECT * FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1",
@ -333,13 +344,13 @@ class Channel {
load_pconfig(local_channel(),'expire');
$channel = \App::get_channel();
$channel = App::get_channel();
$global_perms = \Zotlabs\Access\Permissions::Perms();
$global_perms = Permissions::Perms();
$permiss = array();
$permiss = [];
$perm_opts = array(
$perm_opts = [
array( t('Nobody except yourself'), 0),
array( t('Only those you specifically allow'), PERMS_SPECIFIC),
array( t('Approved connections'), PERMS_CONTACTS),
@ -348,13 +359,13 @@ class Channel {
array( t('Anybody in this network'), PERMS_NETWORK),
array( t('Anybody authenticated'), PERMS_AUTHED),
array( t('Anybody on the internet'), PERMS_PUBLIC)
);
];
$limits = \Zotlabs\Access\PermissionLimits::Get(local_channel());
$limits = PermissionLimits::Get(local_channel());
$anon_comments = get_config('system','anonymous_comments',true);
foreach($global_perms as $k => $perm) {
$options = array();
$options = [];
$can_be_public = ((strstr($k,'view') || ($k === 'post_comments' && $anon_comments)) ? true : false);
foreach($perm_opts as $opt) {
if($opt[1] == PERMS_PUBLIC && (! $can_be_public))
@ -364,7 +375,12 @@ class Channel {
if($k === 'view_stream') {
$options = [$perm_opts[7][1] => $perm_opts[7][0]];
}
$permiss[] = array($k,$perm,$limits[$k],'',$options);
if($k === 'post_comments') {
$comment_perms = [ $k, $perm, $limits[$k],'',$options ];
}
else {
$permiss[] = array($k,$perm,$limits[$k],'',$options);
}
}
// logger('permiss: ' . print_r($permiss,true));
@ -380,12 +396,8 @@ class Channel {
$adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT);
$sys_expire = get_config('system','default_expire_days');
// $unkmail = \App::$user['unkmail'];
// $cntunkmail = \App::$user['cntunkmail'];
$hide_presence = intval(get_pconfig(local_channel(), 'system','hide_online_status'));
$expire_items = get_pconfig(local_channel(), 'expire','items');
$expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1
@ -395,7 +407,6 @@ class Channel {
$expire_starred = get_pconfig(local_channel(), 'expire','starred');
$expire_starred = (($expire_starred===false)? '1' : $expire_starred); // default if not set: 1
$public_uploads = get_pconfig(local_channel(), 'expire','force_public_uploads',1);
$expire_photos = get_pconfig(local_channel(), 'expire','photos');
$expire_photos = (($expire_photos===false)? '0' : $expire_photos); // default if not set: 0
@ -436,24 +447,27 @@ class Channel {
));
$subdir = ((strlen(\App::get_path())) ? '<br />' . t('or') . ' ' . z_root() . '/channel/' . $nickname : '');
$subdir = ((strlen(App::get_path())) ? '<br />' . t('or') . ' ' . z_root() . '/channel/' . $nickname : '');
$webbie = $nickname . '@' . \App::get_hostname();
$intl_nickname = unpunify($nickname) . '@' . unpunify(\App::get_hostname());
$tpl_addr = get_markup_template("settings_nick_set.tpl");
$prof_addr = replace_macros($tpl_addr,array(
$webbie = $nickname . '@' . App::get_hostname();
$intl_nickname = unpunify($nickname) . '@' . unpunify(App::get_hostname());
$prof_addr = replace_macros(get_markup_template('channel_settings_header.tpl'),array(
'$desc' => t('Your channel address is'),
'$nickname' => (($intl_nickname === $webbie) ? $webbie : $intl_nickname . '&nbsp;(' . $webbie . ')'),
'$compat' => t('Friends using compatible applications can use this address to connect with you.'),
'$subdir' => $subdir,
'$davdesc' => t('Your files/photos are accessible via WebDAV at'),
'$davdesc' => t('Your files/photos are accessible as a network drive at'),
'$davpath' => z_root() . '/dav/' . $nickname,
'$basepath' => \App::get_hostname()
'$windows' => t('(Windows)'),
'$other' => t('(other platforms)'),
'$or' => t('or'),
'$davspath' => 'davs://' . App::get_hostname() . '/dav/' . $nickname,
'$basepath' => App::get_hostname()
));
$pcat = new \Zotlabs\Lib\Permcat(local_channel());
$pcat = new Permcat(local_channel());
$pcatlist = $pcat->listing();
$permcats = [];
if($pcatlist) {
@ -465,9 +479,7 @@ class Channel {
$default_permcat = get_pconfig(local_channel(),'system','default_permcat','default');
$stpl = get_markup_template('settings.tpl');
$acl = new \Zotlabs\Access\AccessControl($channel);
$acl = new AccessControl($channel);
$perm_defaults = $acl->get();
$group_select = AccessList::select(local_channel(),$channel['channel_default_group']);
@ -495,19 +507,28 @@ class Channel {
if(in_array($permissions_role,['forum','repository'])) {
$autoperms = replace_macros(get_markup_template('field_checkbox.tpl'), [
'$field' => [ 'autoperms',t('Automatic membership approval'), ((get_pconfig(local_channel(),'system','autoperms',0)) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no ]]);
// $anymention = replace_macros(get_markup_template('field_checkbox.tpl'), [
// '$field' => [ 'anymention', t('Allow forum delivery with @mentions'), ((get_pconfig(local_channel(),'system','anymention')) ? 1 : 0), t('Allows delivery from projects which do not support !mentions for forums.'), $yes_no ]]);
}
else {
$autoperms = '<input type="hidden" name="autoperms" value="' . intval(get_pconfig(local_channel(),'system','autoperms')) . '" />';
// $anymention = '<input type="hidden" name="anymention" value="' . intval(get_pconfig(local_channel(),'system','anymention')) . '" />';
}
// $hyperdrive = [ 'hyperdrive', t('Enable hyperdrive'), ((get_pconfig(local_channel(),'system','hyperdrive',true)) ? 1 : 0), t('Dramatically increases the content available in your stream.'), $yes_no ];
$hyperdrive = [ 'hyperdrive', t('Enable hyperdrive'), ((get_pconfig(local_channel(),'system','hyperdrive',true)) ? 1 : 0), t('Import public third-party conversations in which your connections participate.'), $yes_no ];
if (get_config('system','activitypub')) {
$apconfig = true;
$activitypub = replace_macros(get_markup_template('field_checkbox.tpl'), [ '$field' => [ 'activitypub', t('Enable ActivityPub protocol'), ((get_pconfig(local_channel(),'system','activitypub',true)) ? 1 : 0), t(''), $yes_no ]]);
}
else {
$apconfig = false;
$activitypub = '<input type="hidden" name="activitypub" value="1" >' . EOL;
}
$apheader = t('ActivityPub');
$apdoc = t('ActivityPub is an emerging internet standard for social communications. ') . t('It provides access to a large and growing number of existing users and supported software applications, however it is still evolving. If this is enabled you will obtain much greater social reach, however you will almost certainly encounter compatibility issues, with varying levels of severity and personal impact. ') . EOL . t('Your system administrator has allowed this experimental service on this website. Please disable it if you prefer a bit more stability in your life.');
$permissions_set = (($permissions_role != 'custom') ? true : false);
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
$perm_roles = PermissionRoles::roles();
$vnotify = get_pconfig(local_channel(),'system','vnotify');
$always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices');
@ -521,42 +542,38 @@ class Channel {
$site_firehose = intval(get_config('system','site_firehose',0)) == 1;
$o .= replace_macros($stpl,array(
'$ptitle' => t('Channel Settings'),
$o .= replace_macros(get_markup_template('settings.tpl'), [
'$ptitle' => t('Channel Settings'),
'$submit' => t('Submit'),
'$baseurl' => z_root(),
'$uid' => local_channel(),
'$form_security_token' => get_form_security_token("settings"),
'$nickname_block' => $prof_addr,
'$h_basic' => t('Basic Settings'),
'$username' => array('username', t('Full Name:'), $username,''),
'$email' => array('email', t('Email Address:'), $email, ''),
'$timezone' => array('timezone_select' , t('Your Timezone:'), $timezone, '', get_timezones()),
'$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')),
'$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no),
'$username' => array('username', t('Full name'), $username,''),
'$email' => array('email', t('Email Address'), $email, ''),
'$timezone' => array('timezone_select' , t('Your timezone'), $timezone, t('This is important for showing the correct time on shared events'), get_timezones()),
'$defloc' => array('defloc', t('Default post location'), $defloc, t('Optional geographical location to display on your posts')),
'$allowloc' => array('allow_location', t('Obtain post location from your web browser or device'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no),
'$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no),
'$adult' => array('adult', t('Adult content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no),
'$h_prv' => t('Security and Privacy Settings'),
'$h_prv' => t('Security and Privacy'),
'$permissions_set' => $permissions_set,
'$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'),
'$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no),
'$lbl_pmacro' => t('Simple Privacy Settings:'),
'$pmacro3' => t('Very Public - <em>extremely permissive (should be used with caution)</em>'),
'$pmacro2' => t('Typical - <em>default public, privacy when desired (similar to social network permissions but with improved privacy)</em>'),
'$pmacro1' => t('Private - <em>default private, never open or public</em>'),
'$pmacro0' => t('Blocked - <em>default blocked to/from everybody</em>'),
'$permiss_arr' => $permiss,
'$comment_perms' => $comment_perms,
'$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no),
'$lbl_p2macro' => t('Channel Permission Limits'),
'$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')),
'$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')),
'$public_uploads' => [ 'public_uploads', t('Disable access checking on post attachments'), $public_uploads, t('Private media access is only implemented in a very small number of federated networks.'), $yes_no ],
'$permissions' => t('Default Access List'),
'$permdesc' => t("(click to open/close)"),
'$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))),
@ -580,9 +597,12 @@ class Channel {
'$autoperms' => $autoperms,
// '$anymention' => $anymention,
// '$hyperdrive' => $hyperdrive,
'$h_not' => t('Notification Settings'),
'$hyperdrive' => $hyperdrive,
'$activitypub' => $activitypub,
'$apconfig' => $apconfig,
'$apheader' => $apheader,
'$apdoc' => $apdoc,
'$h_not' => t('Notifications'),
'$activity_options' => t('By default post a status message when:'),
'$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no),
'$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no),
@ -618,7 +638,7 @@ class Channel {
'$vnotify14' => array('vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no),
'$vnotify15' => array('vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no),
'$vnotify16' => ((is_site_admin()) ? array('vnotify16', t('Reported content'), ($vnotify & VNOTIFY_REPORTS), VNOTIFY_REPORTS, '', $yes_no) : [] ),
'$mailhost' => [ 'mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(),'system','email_notify_host',\App::get_hostname()), sprintf( t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'),\App::get_hostname()) ],
'$mailhost' => [ 'mailhost', t('Email notification hub (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),
'$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')),
@ -626,25 +646,30 @@ class Channel {
'$sec_addon' => $plugin['security'],
'$notify_addon' => $plugin['notify'],
'$misc_addon' => $plugin['misc'],
'$lbl_time' => t('Date and time'),
'$miscdoc' => t('This section is reserved for use by optional addons and apps to provide additional settings.'),
'$h_advn' => t('Advanced Account/Page Type Settings'),
'$h_descadvn' => t('Change the behaviour of this account for special situations'),
'$pagetype' => $pagetype,
'$lbl_misc' => t('Miscellaneous Settings'),
'$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')),
'$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')),
'$lbl_misc' => t('Miscellaneous'),
'$photo_path' => array('photo_path', t('Default photo upload folder name'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')),
'$attach_path' => array('attach_path', t('Default file upload folder name'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')),
'$menus' => $menu,
'$menu_desc' => t('Personal menu to display in your channel pages'),
'$removeme' => t('Remove Channel'),
'$removechannel' => t('Remove this channel.'),
'$firefoxshare' => t('Firefox Share $Projectname provider'),
'$cal_first_day' => array('first_day', t('Start calendar week on Monday'), ((get_pconfig(local_channel(),'system','cal_first_day')) ? 1 : ''), '', $yes_no),
));
call_hooks('settings_form',$o);
//$o .= '</form>' . "\r\n";
'$cal_first_day' => array('first_day', t('Calendar week begins on'), intval(get_pconfig(local_channel(),'system','cal_first_day')), t('This varies by country/culture'),
[ 0 => t('Sunday'),
1 => t('Monday'),
2 => t('Tuesday'),
3 => t('Wednesday'),
4 => t('Thursday'),
5 => t('Friday'),
6 => t('Saturday')
]),
]);
call_hooks('settings_form',$o);
return $o;
}
}

View file

@ -11,7 +11,7 @@ class Oauth2 {
if(x($_POST,'remove')){
check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2');
$name = ((x($_POST,'name')) ? escape_tags(trim($_POST['name'])) : '');
logger("REMOVE! ".$name." uid: ".local_channel());
logger("REMOVE! ".$name." uid: ".local_channel());
$key = $_POST['remove'];
q("DELETE FROM oauth_authorization_codes WHERE client_id='%s' AND user_id=%d",
dbesc($name),
@ -34,20 +34,22 @@ class Oauth2 {
check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2');
$name = ((x($_POST,'name')) ? escape_tags(trim($_POST['name'])) : '');
$clid = ((x($_POST,'clid')) ? escape_tags(trim($_POST['clid'])) : '');
$secret = ((x($_POST,'secret')) ? escape_tags(trim($_POST['secret'])) : '');
$redirect = ((x($_POST,'redirect')) ? escape_tags(trim($_POST['redirect'])) : '');
$grant = ((x($_POST,'grant')) ? escape_tags(trim($_POST['grant'])) : '');
$scope = ((x($_POST,'scope')) ? escape_tags(trim($_POST['scope'])) : '');
$ok = true;
if($name == '' || $secret == '') {
if($clid == '' || $secret == '') {
$ok = false;
notice( t('Name and Secret are required') . EOL);
notice( t('ID and Secret are required') . EOL);
}
if($ok) {
if ($_POST['submit']==t("Update")){
$r = q("UPDATE oauth_clients SET
client_name = '%s',
client_id = '%s',
client_secret = '%s',
redirect_uri = '%s',
@ -56,17 +58,19 @@ class Oauth2 {
user_id = %d
WHERE client_id='%s' and user_id = %s",
dbesc($name),
dbesc($clid),
dbesc($secret),
dbesc($redirect),
dbesc($grant),
dbesc($scope),
intval(local_channel()),
dbesc($name),
intval(local_channel()));
dbesc($clid),
intval(local_channel()));
} else {
$r = q("INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, grant_types, scope, user_id)
VALUES ('%s','%s','%s','%s','%s',%d)",
$r = q("INSERT INTO oauth_clients (client_name, client_id, client_secret, redirect_uri, grant_types, scope, user_id)
VALUES ('%s','%s','%s','%s','%s','%s',%d)",
dbesc($name),
dbesc($clid),
dbesc($secret),
dbesc($redirect),
dbesc($grant),
@ -95,6 +99,7 @@ class Oauth2 {
'$submit' => t('Submit'),
'$cancel' => t('Cancel'),
'$name' => array('name', t('Name'), '', t('Name of application')),
'$clid' => array('clid', t('Consumer ID'), random_string(16), t('Automatically generated - change if desired. Max length 20')),
'$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')),
'$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')),
'$grant' => array('grant', t('Grant Types'), '', t('leave blank unless your application specifically requires this')),
@ -122,7 +127,8 @@ class Oauth2 {
'$title' => t('Add application'),
'$submit' => t('Update'),
'$cancel' => t('Cancel'),
'$name' => array('name', t('Name'), $app['client_id'], t('Name of application')),
'$name' => array('name', t('Name'), $app['client_name'], t('Name of application')),
'$clid' => array('clid', t('Consumer ID'), $app['client_id'], t('Automatically generated - change if desired. Max length 20')),
'$secret' => array('secret', t('Consumer Secret'), $app['client_secret'], t('Automatically generated - change if desired. Max length 20')),
'$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], t('Redirect URI - leave blank unless your application specifically requires this')),
'$grant' => array('grant', t('Grant Types'), $app['grant_types'], t('leave blank unless your application specifically requires this')),

View file

@ -15,7 +15,7 @@ class Siteinfo extends Controller {
function get() {
if(defined('NOMADIC')) {
if(! get_config('system','activitypub')) {
$federated = [ 'zot6' ];
}
else {

View file

@ -1,62 +1,60 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/security.php');
require_once('include/bbcode.php');
class Subthread extends \Zotlabs\Web\Controller {
class Subthread extends Controller {
function get() {
if(! local_channel()) {
if (! local_channel()) {
return;
}
$sys = get_sys_channel();
$channel = \App::get_channel();
$channel = App::get_channel();
$item_id = ((argc() > 2) ? notags(trim(argv(2))) : 0);
if(argv(1) === 'sub')
if (argv(1) === 'sub') {
$activity = ACTIVITY_FOLLOW;
elseif(argv(1) === 'unsub')
}
elseif (argv(1) === 'unsub') {
$activity = ACTIVITY_UNFOLLOW;
}
$i = q("select * from item where id = %d and uid = %d",
intval($item_id),
intval(local_channel())
);
if(! $i) {
if (! $i) {
$i = q("select * from item where id = %d and uid = %d",
intval($postid),
intval($sys['channel_id'])
);
if($i) {
if ($i) {
$i = [ copy_of_pubitem($channel, $i[0]['mid']) ];
$item_id = (($i) ? $i[0]['id'] : 0);
}
}
if(! $i) {
if (! $i) {
return;
}
$r = q("SELECT parent FROM item WHERE id = %d",
intval($item_id)
$r = q("select * from item where id = parent and id = %d limit 1",
dbesc($i[0]['parent'])
);
if($r) {
$r = q("select * from item where id = parent and id = %d limit 1",
dbesc($r[0]['parent'])
);
}
if((! $item_id) || (! $r)) {
if ((! $item_id) || (! $r)) {
logger('subthread: no item ' . $item_id);
return;
}
@ -64,11 +62,12 @@ class Subthread extends \Zotlabs\Web\Controller {
$item = $r[0];
$owner_uid = $item['uid'];
$observer = \App::get_observer();
$observer = App::get_observer();
$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
if(! perm_is_allowed($owner_uid,$ob_hash,'post_comments'))
if (! perm_is_allowed($owner_uid,$ob_hash,'post_comments')) {
return;
}
$sys = get_sys_channel();
@ -81,30 +80,31 @@ class Subthread extends \Zotlabs\Web\Controller {
// Even if the activity is rejected by the item owner, it should still get attached
// to the local discover conversation on this site.
if(($owner_uid != $sys['channel_id']) && (! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments'))) {
notice( t('Permission denied') . EOL);
killme();
if (($owner_uid != $sys['channel_id']) && (! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments'))) {
notice( t('Permission denied') . EOL);
killme();
}
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($item['owner_xchan'])
);
if($r)
if ($r) {
$thread_owner = $r[0];
else
}
else {
killme();
}
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($item['author_xchan'])
);
if($r)
if ($r) {
$item_author = $r[0];
else
}
else {
killme();
}
$uuid = new_uuid();
$mid = z_root() . '/item/' . $uuid;
@ -114,36 +114,21 @@ class Subthread extends \Zotlabs\Web\Controller {
$objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE );
$body = $item['body'];
$obj = json_encode(array(
'type' => $objtype,
'id' => $item['mid'],
'parent' => (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']),
'link' => $links,
'title' => $item['title'],
'content' => $item['body'],
'created' => $item['created'],
'edited' => $item['edited'],
'author' => array(
'name' => $item_author['xchan_name'],
'address' => $item_author['xchan_addr'],
'guid' => $item_author['xchan_guid'],
'guid_sig' => $item_author['xchan_guid_sig'],
'link' => array(
array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']),
array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])),
),
));
if(! intval($item['item_thread_top']))
$obj = Activity::fetch_item( [ 'id' => $item['mid'] ] );
$objtype = $obj['type'];
if (! intval($item['item_thread_top']))
$post_type = 'comment';
if($activity === ACTIVITY_FOLLOW)
if ($activity === ACTIVITY_FOLLOW) {
$bodyverb = t('%1$s is following %2$s\'s %3$s');
if($activity === ACTIVITY_UNFOLLOW)
}
if ($activity === ACTIVITY_UNFOLLOW) {
$bodyverb = t('%1$s stopped following %2$s\'s %3$s');
$arr = array();
}
$arr = [];
$arr['uuid'] = $uuid;
$arr['mid'] = $mid;
@ -156,11 +141,14 @@ class Subthread extends \Zotlabs\Web\Controller {
$arr['author_xchan'] = $observer['xchan_hash'];
$arr['item_origin'] = 1;
$arr['item_notshown'] = 1;
if(intval($item['item_wall']))
if (intval($item['item_wall'])) {
$arr['item_wall'] = 1;
else
}
else {
$arr['item_wall'] = 0;
}
$ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]';
$alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]';
$plink = '[zrl=' . z_root() . '/display/' . gen_link_id($item['mid']) . ']' . $post_type . '[/zrl]';
@ -169,7 +157,7 @@ class Subthread extends \Zotlabs\Web\Controller {
$arr['verb'] = $activity;
$arr['obj_type'] = $objtype;
$arr['obj'] = $obj;
$arr['obj'] = json_encode($obj);
$arr['allow_cid'] = $item['allow_cid'];
$arr['allow_gid'] = $item['allow_gid'];
@ -183,12 +171,6 @@ class Subthread extends \Zotlabs\Web\Controller {
call_hooks('post_local_end', $arr);
killme();
killme();
}
}

View file

@ -4,10 +4,11 @@ namespace Zotlabs\Module;
use Zotlabs\Lib\Libsync;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
require_once('include/socgraph.php');
class Suggestions extends \Zotlabs\Web\Controller {
class Suggestions extends Controller {
function init() {
if (! local_channel())

View file

@ -3,6 +3,7 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Apps;
require_once('include/event.php');
@ -96,4 +97,19 @@ class Tasks extends Controller {
json_return_and_die($x);
}
}
function get() {
$desc = t('This app provides a simple personal and task list.');
$text = '<div class="section-content-info-wrapper">' . $desc . '</div>';
if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Tasks'))) {
return $text;
}
$obj = new \Zotlabs\Widget\Tasklist;
return $obj->widget([]);
}
}

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