diff options
author | Mario Vavti <mario@mariovavti.com> | 2017-08-16 10:32:35 +0200 |
---|---|---|
committer | Mario Vavti <mario@mariovavti.com> | 2017-08-16 10:32:35 +0200 |
commit | 4a7384bc0ce1893a432bf4b7d67bca23796fe9db (patch) | |
tree | 5623c66a3f66445284529d6207e4ab4a2edb2810 /Zotlabs | |
parent | c664a4bdcd1bd578f5ec3c2884f7c97e9f68d2d7 (diff) | |
parent | 90bc21f2d560d879d7eaf05a85af6d6dca53ebac (diff) | |
download | volse-hubzilla-4a7384bc0ce1893a432bf4b7d67bca23796fe9db.tar.gz volse-hubzilla-4a7384bc0ce1893a432bf4b7d67bca23796fe9db.tar.bz2 volse-hubzilla-4a7384bc0ce1893a432bf4b7d67bca23796fe9db.zip |
Merge branch '2.6RC'2.6
Diffstat (limited to 'Zotlabs')
100 files changed, 2756 insertions, 539 deletions
diff --git a/Zotlabs/Access/PermissionLimits.php b/Zotlabs/Access/PermissionLimits.php index 909b654d5..8caeedb91 100644 --- a/Zotlabs/Access/PermissionLimits.php +++ b/Zotlabs/Access/PermissionLimits.php @@ -10,7 +10,7 @@ class PermissionLimits { $perms = Permissions::Perms(); $limits = array(); foreach($perms as $k => $v) { - if(strstr($k,'view')) + if(strstr($k,'view') || $k === 'post_comments') $limits[$k] = PERMS_PUBLIC; else $limits[$k] = PERMS_SPECIFIC; diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php index d51e4d0ea..62c4af0ff 100644 --- a/Zotlabs/Access/Permissions.php +++ b/Zotlabs/Access/Permissions.php @@ -1,45 +1,52 @@ <?php - namespace Zotlabs\Access; use Zotlabs\Lib as Zlib; +/** + * @brief Extensible permissions. + * + * To add new permissions, add to the list of $perms below, with a simple description. + * + * Also visit PermissionRoles.php and add to the $ret['perms_connect'] property for any role + * if this permission should be granted to new connections. + * + * Next look at PermissionRoles::new_custom_perms() and provide a handler for updating custom + * permission roles. You will want to set a default PermissionLimit for each channel and also + * provide a sane default for any existing connections. You may or may not wish to provide a + * default auto permission. If in doubt, leave this alone as custom permissions by definition + * are the responsibility of the channel owner to manage. You just don't want to create any + * suprises or break things so you have an opportunity to provide sane settings. + * + * Update the version here and in PermissionRoles. + * + * + * Permissions with 'view' in the name are considered read permissions. Anything + * else requires authentication. Read permission limits are PERMS_PUBLIC and anything else + * is given PERMS_SPECIFIC. + * + * PermissionLimits::Std_limits() retrieves the standard limits. A permission role + * MAY alter an individual setting after retrieving the Std_limits if you require + * something different for a specific permission within the given role. + * + */ class Permissions { - /** - * Extensible permissions. - * To add new permissions, add to the list of $perms below, with a simple description. - * - * Also visit PermissionRoles.php and add to the $ret['perms_connect'] property for any role - * if this permission should be granted to new connections. - * - * Next look at PermissionRoles::new_custom_perms() and provide a handler for updating custom - * permission roles. You will want to set a default PermissionLimit for each channel and also - * provide a sane default for any existing connections. You may or may not wish to provide a - * default auto permission. If in doubt, leave this alone as custom permissions by definition - * are the responsibility of the channel owner to manage. You just don't want to create any - * suprises or break things so you have an opportunity to provide sane settings. - * - * Update the version here and in PermissionRoles - * - * - * Permissions with 'view' in the name are considered read permissions. Anything - * else requires authentication. Read permission limits are PERMS_PUBLIC and anything else - * is given PERMS_SPECIFIC. - * - * PermissionLimits::Std_limits() retrieves the standard limits. A permission role - * MAY alter an individual setting after retrieving the Std_limits if you require - * something different for a specific permission within the given role. - * - */ - static public function version() { // This must match the version in PermissionRoles.php before permission updates can run. return 2; } - + /** + * @brief Return an array with Permissions. + * + * @hooks permissions_list + * * \e array \b permissions + * * \e string \b filter + * @param string $filter (optional) only passed to hook permission_list + * @return Associative array with permissions and short description. + */ static public function Perms($filter = '') { $perms = [ @@ -63,18 +70,27 @@ class Permissions { 'delegate' => t('Can administer my channel') ]; - $x = array('permissions' => $perms, 'filter' => $filter); - call_hooks('permissions_list',$x); - return($x['permissions']); + $x = [ + 'permissions' => $perms, + 'filter' => $filter + ]; + call_hooks('permissions_list', $x); + return($x['permissions']); } + /** + * @brief Perms from the above list that are blocked from anonymous observers. + * + * e.g. you must be authenticated. + * + * @hooks write_perms + * * \e array \b permissions + * @return Associative array with permissions and short description. + */ static public function BlockedAnonPerms() { - // Perms from the above list that are blocked from anonymous observers. - // e.g. you must be authenticated. - - $res = array(); + $res = []; $perms = PermissionLimits::Std_limits(); foreach($perms as $perm => $limit) { if($limit != PERMS_PUBLIC) { @@ -82,17 +98,22 @@ class Permissions { } } - $x = array('permissions' => $res); - call_hooks('write_perms',$x); - return($x['permissions']); + $x = ['permissions' => $res]; + call_hooks('write_perms', $x); + return($x['permissions']); } - // converts [ 0 => 'view_stream', ... ] - // to [ 'view_stream' => 1 ] - // for any permissions in $arr; - // Undeclared permissions are set to 0 - + /** + * @brief Converts indexed perms array to associative perms array. + * + * Converts [ 0 => 'view_stream', ... ] + * to [ 'view_stream' => 1 ] for any permissions in $arr; + * Undeclared permissions which exist in Perms() are added and set to 0. + * + * @param array $arr + * @return array + */ static public function FilledPerms($arr) { if(is_null($arr)) { btlogger('FilledPerms: null'); @@ -101,15 +122,26 @@ class Permissions { $everything = self::Perms(); $ret = []; foreach($everything as $k => $v) { - if(in_array($k,$arr)) + if(in_array($k, $arr)) $ret[$k] = 1; else $ret[$k] = 0; } - return $ret; + return $ret; } + /** + * @brief Convert perms array to indexed array. + * + * Converts [ 'view_stream' => 1 ] for any permissions in $arr + * to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ] + * + * @param array $arr associative perms array 'view_stream' => 1 + * @return Indexed array with elements that look like + * * \e string \b name the perm name (e.g. view_stream) + * * \e int \b value the value of the perm (e.g. 1) + */ static public function OPerms($arr) { $ret = []; if($arr) { @@ -120,7 +152,12 @@ class Permissions { return $ret; } - + /** + * @brief + * + * @param int $channel_id + * @return boolean|array + */ static public function FilledAutoperms($channel_id) { if(! intval(get_pconfig($channel_id,'system','autoperms'))) return false; @@ -137,16 +174,34 @@ class Permissions { return $arr; } - static public function PermsCompare($p1,$p2) { + /** + * @brief Compares that all Permissions from $p1 exist also in $p2. + * + * @param array $p1 The perms that have to exist in $p2 + * @param array $p2 The perms to compare against + * @return boolean true if all perms from $p1 exist also in $p2 + */ + static public function PermsCompare($p1, $p2) { foreach($p1 as $k => $v) { - if(! array_key_exists($k,$p2)) + if(! array_key_exists($k, $p2)) return false; + if($p1[$k] != $p2[$k]) return false; } + return true; } + /** + * @brief + * + * @param int $channel_id A channel id + * @return associative array + * * \e array \b perms Permission array + * * \e int \b automatic 0 or 1 + */ + static public function connect_perms($channel_id) { $my_perms = []; @@ -155,7 +210,7 @@ class Permissions { // If a default permcat exists, use that - $pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default'); + $pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default'); if(! in_array($pc, [ '','default' ])) { $pcp = new Zlib\Permcat($channel_id); $permcat = $pcp->fetch($pc); @@ -167,7 +222,7 @@ class Permissions { } // look up the permission role to see if it specified auto-connect - // and if there was no permcat or a default permcat, set the perms + // and if there was no permcat or a default permcat, set the perms // from the role $role = get_pconfig($channel_id,'system','permissions_role'); @@ -195,7 +250,7 @@ class Permissions { } // If we reached this point with no permissions, the channel is using - // custom perms but they are not automatic. They will be stored in abconfig with + // custom perms but they are not automatic. They will be stored in abconfig with // the channel's channel_hash (the 'self' connection). if(! $my_perms) { diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php index c84708ba4..65edbedfa 100644 --- a/Zotlabs/Daemon/Cron.php +++ b/Zotlabs/Daemon/Cron.php @@ -174,7 +174,8 @@ class Cron { // pull in some public posts - if(! get_config('system','disable_discover_tab')) + $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false; + if(! $disable_discover_tab) Master::Summon(array('Externals')); $generation = 0; diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php index 038790572..f0351fcdd 100644 --- a/Zotlabs/Daemon/Cron_daily.php +++ b/Zotlabs/Daemon/Cron_daily.php @@ -51,6 +51,7 @@ class Cron_daily { update_channels_active_halfyear_stat(); update_channels_active_monthly_stat(); update_local_posts_stat(); + update_local_comments_stat(); // expire old delivery reports @@ -87,7 +88,7 @@ class Cron_daily { call_hooks('cron_daily',datetime_convert()); - set_config('system','last_expire_day',$d2); + set_config('system','last_expire_day',intval(datetime_convert('UTC','UTC','now','d'))); /** * End Cron Daily diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php index 3109a5d86..0ca589e4a 100755 --- a/Zotlabs/Daemon/Importdoc.php +++ b/Zotlabs/Daemon/Importdoc.php @@ -21,12 +21,18 @@ class Importdoc { $files = glob("$d/$f"); if($files) { foreach($files as $fi) { - if($fi === 'doc/html') + if($fi === 'doc/html') { continue; - if(is_dir($fi)) + } + if(is_dir($fi)) { self::update_docs_dir("$fi/*"); - else - store_doc_file($fi); + } + else { + // don't update media content + if(strpos(z_mime_content_type($fi),'text') === 0) { + store_doc_file($fi); + } + } } } } diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 3afe1a5dc..6bca22025 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -64,8 +64,6 @@ require_once('include/bbcode.php'); * purge_all channel_id * expire channel_id * relay item_id (item was relayed to owner, we will deliver it as owner) - * single_activity item_id (deliver to a singleton network from the appropriate clone) - * single_mail mail_id (deliver to a singleton network from the appropriate clone) * location channel_id * request channel_id xchan_hash message_id * rating xlink_id @@ -105,7 +103,7 @@ class Notifier { $normal_mode = true; $packet_type = 'undefined'; - if($cmd === 'mail' || $cmd === 'single_mail') { + if($cmd === 'mail') { $normal_mode = false; $mail = true; $private = true; @@ -270,7 +268,8 @@ class Notifier { // 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; @@ -391,7 +390,6 @@ class Notifier { return; } } - } $walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false); @@ -408,7 +406,7 @@ class Notifier { if(! $recipients) return; -// logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG); + // logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG); $env_recips = (($private) ? array() : null); @@ -421,40 +419,40 @@ class Notifier { foreach($details as $d) { $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')'; - if($private) - $env_recips[] = array('guid' => $d['xchan_guid'],'guid_sig' => $d['xchan_guid_sig'],'hash' => $d['xchan_hash']); - - if($d['xchan_network'] === 'mail' && $normal_mode) { - $delivery_options = get_xconfig($d['xchan_hash'],'system','delivery_mode'); - if(! $delivery_options) - format_and_send_email($channel,$d,$target_item); + if($private) { + $env_recips[] = [ + 'guid' => $d['xchan_guid'], + 'guid_sig' => $d['xchan_guid_sig'], + 'hash' => $d['xchan_hash'] + ]; } } } - $narr = array( - 'channel' => $channel, - 'upstream' => $upstream, - 'env_recips' => $env_recips, - 'packet_recips' => $packet_recips, - 'recipients' => $recipients, - 'item' => $item, - 'target_item' => $target_item, + $narr = [ + 'channel' => $channel, + 'upstream' => $upstream, + 'env_recips' => $env_recips, + 'packet_recips' => $packet_recips, + 'recipients' => $recipients, + 'item' => $item, + 'target_item' => $target_item, + 'parent_item' => $parent_item, 'top_level_post' => $top_level_post, - 'private' => $private, + 'private' => $private, 'relay_to_owner' => $relay_to_owner, - 'uplink' => $uplink, - 'cmd' => $cmd, - 'mail' => $mail, - 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false), - 'location' => $location, - 'request' => $request, - 'normal_mode' => $normal_mode, - 'packet_type' => $packet_type, - 'walltowall' => $walltowall, - 'queued' => array() - ); + 'uplink' => $uplink, + 'cmd' => $cmd, + 'mail' => $mail, + 'single' => false, + 'location' => $location, + 'request' => $request, + 'normal_mode' => $normal_mode, + 'packet_type' => $packet_type, + 'walltowall' => $walltowall, + 'queued' => [] + ]; call_hooks('notifier_process', $narr); if($narr['queued']) { @@ -491,8 +489,6 @@ class Notifier { $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. @@ -523,49 +519,48 @@ class Notifier { if($hub['hubloc_network'] == 'zot') { if(! in_array($hub['hubloc_sitekey'],$keys)) { $hublist[] = $hub['hubloc_host']; - $dhubs[] = $hub; - $keys[] = $hub['hubloc_sitekey']; + $dhubs[] = $hub; + $keys[] = $hub['hubloc_sitekey']; } } else { if(! in_array($hub['hubloc_url'],$urls)) { $hublist[] = $hub['hubloc_host']; - $dhubs[] = $hub; - $urls[] = $hub['hubloc_url']; + $dhubs[] = $hub; + $urls[] = $hub['hubloc_url']; } } } logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG); - foreach($dhubs as $hub) { if($hub['hubloc_network'] !== 'zot') { - - $narr = array( - 'channel' => $channel, - 'upstream' => $upstream, - 'env_recips' => $env_recips, - 'packet_recips' => $packet_recips, - 'recipients' => $recipients, - 'item' => $item, - 'target_item' => $target_item, - 'hub' => $hub, + $narr = [ + 'channel' => $channel, + 'upstream' => $upstream, + 'env_recips' => $env_recips, + 'packet_recips' => $packet_recips, + 'recipients' => $recipients, + 'item' => $item, + 'target_item' => $target_item, + 'parent_item' => $parent_item, + 'hub' => $hub, 'top_level_post' => $top_level_post, - 'private' => $private, + 'private' => $private, 'relay_to_owner' => $relay_to_owner, - 'uplink' => $uplink, - 'cmd' => $cmd, - 'mail' => $mail, - 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false), - 'location' => $location, - 'request' => $request, - 'normal_mode' => $normal_mode, - 'packet_type' => $packet_type, - 'walltowall' => $walltowall, - 'queued' => array() - ); + 'uplink' => $uplink, + 'cmd' => $cmd, + 'mail' => $mail, + 'single' => false, + 'location' => $location, + 'request' => $request, + 'normal_mode' => $normal_mode, + 'packet_type' => $packet_type, + 'walltowall' => $walltowall, + 'queued' => [] + ]; call_hooks('notifier_hub',$narr); @@ -577,21 +572,6 @@ class Notifier { } - // singleton deliveries by definition 'not got zot'. - // Single deliveries are other federated networks (plugins) 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 - // is running it will receive a sync packet. On receipt of this sync packet it - // will invoke a delivery to those connections which are connected to just that - // hub instance. - - if($cmd === 'single_mail' || $cmd === 'single_activity') { - continue; - } - - // default: zot protocol - $hash = random_string(); $packet = null; @@ -617,14 +597,16 @@ class Notifier { else { $env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : ''); $packet = zot_build_packet($channel,'notify',$env,(($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash); - queue_insert(array( - 'hash' => $hash, - 'account_id' => $target_item['aid'], - 'channel_id' => $target_item['uid'], - 'posturl' => $hub['hubloc_callback'], - 'notify' => $packet, - 'msg' => json_encode($encoded_item) - )); + queue_insert( + [ + 'hash' => $hash, + 'account_id' => $target_item['aid'], + 'channel_id' => $target_item['uid'], + 'posturl' => $hub['hubloc_callback'], + 'notify' => $packet, + 'msg' => json_encode($encoded_item) + ] + ); // 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'))) { @@ -645,9 +627,9 @@ class Notifier { if($normal_mode) { $x = q("select * from hook where hook = 'notifier_normal'"); - if($x) - Master::Summon(array('Deliver_hooks',$target_item['id'])); - + if($x) { + Master::Summon( [ 'Deliver_hooks', $target_item['id'] ] ); + } } if($deliveries) diff --git a/Zotlabs/Extend/Hook.php b/Zotlabs/Extend/Hook.php index fef3ebe9b..c6f9ea850 100644 --- a/Zotlabs/Extend/Hook.php +++ b/Zotlabs/Extend/Hook.php @@ -40,6 +40,15 @@ class Hook { return $r; } + static public function register_array($file,$arr) { + if($arr) { + foreach($arr as $k => $v) { + self::register($k,$file,$v); + } + } + } + + static public function unregister($hook,$file,$function,$version = 1,$priority = 0) { if(is_array($function)) { $function = serialize($function); diff --git a/Zotlabs/Lib/ActivityStreams2.php b/Zotlabs/Lib/ActivityStreams2.php new file mode 100644 index 000000000..904782bf7 --- /dev/null +++ b/Zotlabs/Lib/ActivityStreams2.php @@ -0,0 +1,86 @@ +<?php + +namespace Zotlabs\Lib; + + +class ActivityStreams2 { + + public $data; + public $valid = false; + public $id = ''; + public $type = ''; + public $actor = null; + public $obj = null; + public $tgt = null; + + function __construct($string) { + + $this->data = json_decode($string,true); + if($this->data) { + $this->valid = true; + } + + if($this->is_valid()) { + $this->id = $this->get_property_obj('id'); + $this->type = $this->get_primary_type(); + $this->actor = $this->get_compound_property('actor'); + $this->obj = $this->get_compound_property('object'); + $this->tgt = $this->get_compound_property('target'); + } + } + + function is_valid() { + return $this->valid; + } + + function get_property_obj($property,$base = '') { + if(! $base) { + $base = $this->data; + } + return $base[$property]; + } + + function fetch_property($url) { + $redirects = 0; + $x = z_fetch_url($url,true,$redirects, + ['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"']]); + if($x['success']) + return json_decode($x['body'],true); + return null; + } + + function get_compound_property($property,$base = '') { + $x = $this->get_property_obj($property,$base); + if($this->is_url($x)) { + $x = $this->fetch_property($x); + } + return $x; + } + + function is_url($url) { + if(($url) && (! is_array($url)) && (strpos($url,'http') === 0)) { + return true; + } + return false; + } + + function get_primary_type($base = '') { + if(! $base) + $base = $this->data; + $x = $this->get_property_obj('type',$base); + if(is_array($x)) { + foreach($x as $y) { + if(strpos($y,':') === false) { + return $y; + } + } + } + return $x; + } + + function debug() { + $x = var_export($this,true); + return $x; + } + +}
\ No newline at end of file diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index 2ace361ca..68587df49 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -209,6 +209,7 @@ class Apps { static public function translate_system_apps(&$arr) { $apps = array( + 'Apps' => t('Apps'), 'Site Admin' => t('Site Admin'), 'Report Bug' => t('Report Bug'), 'View Bookmarks' => t('View Bookmarks'), @@ -371,6 +372,7 @@ class Apps { '$feature' => (($papp['embed']) ? false : true), '$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true), '$navapps' => (($mode == 'nav') ? true : false), + '$order' => (($mode == 'nav-order') ? true : false), '$add' => t('Add to app-tray'), '$remove' => t('Remove from app-tray') )); @@ -539,6 +541,129 @@ class Apps { return($r); } + static public function app_order($uid,$apps) { + + if(! $apps) + return $apps; + + $x = (($uid) ? get_pconfig($uid,'system','app_order') : get_config('system','app_order')); + if(($x) && (! is_array($x))) { + $y = explode(',',$x); + $y = array_map('trim',$y); + $x = $y; + } + + if(! (is_array($x) && ($x))) + return $apps; + + $ret = []; + foreach($x as $xx) { + $y = self::find_app_in_array($xx,$apps); + if($y) { + $ret[] = $y; + } + } + foreach($apps as $ap) { + if(! self::find_app_in_array($ap['name'],$ret)) { + $ret[] = $ap; + } + } + return $ret; + + } + + static function find_app_in_array($name,$arr) { + if(! $arr) + return false; + foreach($arr as $x) { + if($x['name'] === $name) { + return $x; + } + } + return false; + } + + static function moveup($uid,$guid) { + $syslist = array(); + $list = self::app_list($uid, false, 'nav_featured_app'); + if($list) { + foreach($list as $li) { + $syslist[] = self::app_encode($li); + } + } + self::translate_system_apps($syslist); + + usort($syslist,'self::app_name_compare'); + + $syslist = self::app_order($uid,$syslist); + + if(! $syslist) + return; + + $newlist = []; + + foreach($syslist as $k => $li) { + if($li['guid'] === $guid) { + $position = $k; + break; + } + } + if(! $position) + return; + $dest_position = $position - 1; + $saved = $syslist[$dest_position]; + $syslist[$dest_position] = $syslist[$position]; + $syslist[$position] = $saved; + + $narr = []; + foreach($syslist as $x) { + $narr[] = $x['name']; + } + + set_pconfig($uid,'system','app_order',implode(',',$narr)); + + } + + static function movedown($uid,$guid) { + $syslist = array(); + $list = self::app_list($uid, false, 'nav_featured_app'); + if($list) { + foreach($list as $li) { + $syslist[] = self::app_encode($li); + } + } + self::translate_system_apps($syslist); + + usort($syslist,'self::app_name_compare'); + + $syslist = self::app_order($uid,$syslist); + + if(! $syslist) + return; + + $newlist = []; + + foreach($syslist as $k => $li) { + if($li['guid'] === $guid) { + $position = $k; + break; + } + } + if($position >= count($syslist) - 1) + return; + $dest_position = $position + 1; + $saved = $syslist[$dest_position]; + $syslist[$dest_position] = $syslist[$position]; + $syslist[$position] = $saved; + + $narr = []; + foreach($syslist as $x) { + $narr[] = $x['name']; + } + + set_pconfig($uid,'system','app_order',implode(',',$narr)); + + } static public function app_decode($s) { $x = base64_decode(str_replace(array('<br />',"\r","\n",' '),array('','','',''),$s)); diff --git a/Zotlabs/Lib/Cache.php b/Zotlabs/Lib/Cache.php index f211269be..cea075659 100644 --- a/Zotlabs/Lib/Cache.php +++ b/Zotlabs/Lib/Cache.php @@ -9,10 +9,10 @@ namespace Zotlabs\Lib; class Cache { public static function get($key) { - $key = substr($key,0,254); + $hash = hash('whirlpool',$key); $r = q("SELECT v FROM cache WHERE k = '%s' limit 1", - dbesc($key) + dbesc($hash) ); if ($r) @@ -22,20 +22,20 @@ class Cache { public static function set($key,$value) { - $key = substr($key,0,254); + $hash = hash('whirlpool',$key); $r = q("SELECT * FROM cache WHERE k = '%s' limit 1", - dbesc($key) + dbesc($hash) ); if($r) { q("UPDATE cache SET v = '%s', updated = '%s' WHERE k = '%s'", dbesc($value), dbesc(datetime_convert()), - dbesc($key)); + dbesc($hash)); } else { q("INSERT INTO cache ( k, v, updated) VALUES ('%s','%s','%s')", - dbesc($key), + dbesc($hash), dbesc($value), dbesc(datetime_convert())); } diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php index 5625a3f79..6e042feba 100644 --- a/Zotlabs/Lib/Config.php +++ b/Zotlabs/Lib/Config.php @@ -53,7 +53,7 @@ class Config { $dbvalue = ((is_array($value)) ? serialize($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); - if(get_config($family, $key) === false || (! self::get_from_storage($family, $key))) { + if(self::Get($family, $key) === false || (! self::get_from_storage($family, $key))) { $ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ", dbesc($family), dbesc($key), diff --git a/Zotlabs/Lib/DB_Upgrade.php b/Zotlabs/Lib/DB_Upgrade.php index bb72e7a05..8f0488f6f 100644 --- a/Zotlabs/Lib/DB_Upgrade.php +++ b/Zotlabs/Lib/DB_Upgrade.php @@ -10,15 +10,17 @@ class DB_Upgrade { function __construct($db_revision) { - $update_file = 'install/' . PLATFORM_NAME . '/update.php'; + $platform_name = System::get_platform_name(); + + $update_file = 'install/' . $platform_name . '/update.php'; if(! file_exists($update_file)) { $update_file = 'install/update.php'; $this->config_name = 'db_version'; $this->func_prefix = 'update_r'; } else { - $this->config_name = PLATFORM_NAME . '_db_version'; - $this->func_prefix = PLATFORM_NAME . '_update_'; + $this->config_name = $platform_name . '_db_version'; + $this->func_prefix = $platform_name . '_update_'; } $build = get_config('system', $this->config_name, 0); diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index a10675a87..9f3347d19 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -170,6 +170,7 @@ class Enotify { xchan_query($p); + $moderated = (($p[0]['item_blocked'] == ITEM_MODERATED) ? true : false); $item_post_type = item_post_type($p[0]); // $private = $p[0]['item_private']; @@ -208,13 +209,21 @@ class Enotify { // Before this we have the name of the replier on the subject rendering // differents subjects for messages on the same thread. - $subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']); + if($moderated) + $subject = sprintf( t('[$Projectname:Notify] Moderated Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']); + else + $subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']); $preamble = sprintf( t('%1$s, %2$s commented on an item/conversation you have been following.'), $recip['channel_name'], $sender['xchan_name']); $epreamble = $dest_str; $sitelink = t('Please visit %s to view and/or reply to the conversation.'); $tsitelink = sprintf( $sitelink, $siteurl ); $hsitelink = sprintf( $sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>'); + if($moderated) { + $tsitelink .= "\n\n" . sprintf( t('Please visit %s to approve or reject this comment.'), z_root() . '/moderate' ); + $hsitelink .= "<br><br>" . sprintf( t('Please visit %s to approve or reject this comment.'), '<a href="' . z_root() . '/moderate">' . z_root() . '/moderate</a>' ); + } + } if ($params['type'] == NOTIFY_LIKE) { diff --git a/Zotlabs/Lib/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php index ed3df436c..78b54ebda 100644 --- a/Zotlabs/Lib/NativeWikiPage.php +++ b/Zotlabs/Lib/NativeWikiPage.php @@ -44,7 +44,7 @@ class NativeWikiPage { $pages[] = [ 'resource_id' => $resource_id, 'title' => escape_tags($title), - 'url' => urlencode(urlencode($title)), + 'url' => str_replace('%2F','/',urlencode(str_replace('%2F','/',urlencode($title)))), 'link_id' => 'id_' . substr($resource_id, 0, 10) . '_' . $page_item['id'] ]; } diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php index d70697fbc..25478e764 100644 --- a/Zotlabs/Lib/PConfig.php +++ b/Zotlabs/Lib/PConfig.php @@ -119,7 +119,7 @@ class PConfig { $dbvalue = ((is_array($value)) ? serialize($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); - if(get_pconfig($uid, $family, $key) === false) { + if(self::Get($uid, $family, $key) === false) { if(! array_key_exists($uid, \App::$config)) \App::$config[$uid] = array(); if(! array_key_exists($family, \App::$config[$uid])) diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index 306c90f4a..a5790fb07 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -19,6 +19,9 @@ class System { static public function get_project_version() { if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['hide_version']) return ''; + if(is_array(\App::$config) && is_array(\App::$config['system']) && array_key_exists('std_version',\App::$config['system'])) + return \App::$config['system']['std_version']; + return self::get_std_version(); } @@ -54,12 +57,8 @@ class System { return 'https://github.com/redmatrix/hubzilla'; } - - static public function get_server_role() { - if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['server_role']) - return \App::$config['system']['server_role']; - return 'standard'; + return 'pro'; } static public function get_std_version() { @@ -72,11 +71,8 @@ class System { if(get_directory_realm() != DIRECTORY_REALM) return true; - - foreach(['hubzilla','zap'] as $t) { - if(stristr($p,$t)) - return true; - } + if(in_array(strtolower($p),['hubzilla','zap','red'])) + return true; return false; } } diff --git a/Zotlabs/Lib/Techlevels.php b/Zotlabs/Lib/Techlevels.php index 6a8c36fb3..380901678 100644 --- a/Zotlabs/Lib/Techlevels.php +++ b/Zotlabs/Lib/Techlevels.php @@ -7,12 +7,12 @@ class Techlevels { static public function levels() { $techlevels = [ - '0' => t('Beginner/Basic'), - '1' => t('Novice - not skilled but willing to learn'), - '2' => t('Intermediate - somewhat comfortable'), - '3' => t('Advanced - very comfortable'), - '4' => t('Expert - I can write computer code'), - '5' => t('Wizard - I probably know more than you do') + '0' => t('0. Beginner/Basic'), + '1' => t('1. Novice - not skilled but willing to learn'), + '2' => t('2. Intermediate - somewhat comfortable'), + '3' => t('3. Advanced - very comfortable'), + '4' => t('4. Expert - I can write computer code'), + '5' => t('5. Wizard - I probably know more than you do') ]; return $techlevels; } diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 5910ea672..17d65dbc7 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -153,7 +153,7 @@ class ThreadItem { $response_verbs[] = 'attendyes'; $response_verbs[] = 'attendno'; $response_verbs[] = 'attendmaybe'; - if($this->is_commentable()) { + if($this->is_commentable() && $observer) { $isevent = true; $attend = array( t('I will attend'), t('I will not attend'), t('I might attend')); } @@ -164,7 +164,7 @@ class ThreadItem { $response_verbs[] = 'agree'; $response_verbs[] = 'disagree'; $response_verbs[] = 'abstain'; - if($this->is_commentable()) { + if($this->is_commentable() && $observer) { $conlabels = array( t('I agree'), t('I disagree'), t('I abstain')); $canvote = true; } @@ -251,8 +251,6 @@ class ThreadItem { ); } - $server_role = get_config('system','server_role'); - $has_bookmarks = false; if(is_array($item['term'])) { foreach($item['term'] as $t) { @@ -265,7 +263,7 @@ class ThreadItem { if(($item['obj_type'] === ACTIVITY_OBJ_EVENT) && $conv->get_profile_owner() == local_channel()) $has_event = true; - if($this->is_commentable()) { + if($this->is_commentable() && $observer) { $like = array( t("I like this \x28toggle\x29"), t("like")); $dislike = array( t("I don't like this \x28toggle\x29"), t("dislike")); } @@ -371,7 +369,7 @@ class ThreadItem { 'has_tags' => $has_tags, 'reactions' => $this->reactions, // Item toolbar buttons - 'emojis' => (($this->is_toplevel() && $this->is_commentable() && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''), + 'emojis' => (($this->is_toplevel() && $this->is_commentable() && $observer && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''), 'like' => $like, 'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''), 'share' => $share, @@ -714,7 +712,6 @@ class ThreadItem { call_hooks('comment_buttons',$arr); $comment_buttons = $arr['comment_buttons']; - $comment_box = replace_macros($template,array( '$return_path' => '', '$threaded' => $this->is_threaded(), @@ -743,8 +740,12 @@ class ThreadItem { '$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' && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false), + '$anonname' => [ 'anonname', t('Your full name (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ], + '$anonmail' => [ 'anonmail', t('Your email address (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ], + '$anonurl' => [ 'anonurl', t('Your website URL (optional)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ] )); return $comment_box; diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php index beb626f31..35ccf4fdb 100644 --- a/Zotlabs/Lib/ThreadStream.php +++ b/Zotlabs/Lib/ThreadStream.php @@ -18,6 +18,7 @@ class ThreadStream { private $observer = null; private $writable = false; private $commentable = false; + private $uploadable = false; private $profile_owner = 0; private $preview = false; private $prepared_item = ''; @@ -158,7 +159,7 @@ class ThreadStream { if(intval($item->get_data_value('item_nocomment'))) { $item->set_commentable(false); } - elseif(($this->observer) && (! $item->is_commentable())) { + elseif(! $item->is_commentable()) { if((array_key_exists('owner',$item->data)) && intval($item->data['owner']['abook_self'])) $item->set_commentable(perm_is_allowed($this->profile_owner,$ob_hash,'post_comments')); else diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php index c3c50cac2..83fafbdff 100644 --- a/Zotlabs/Module/Acl.php +++ b/Zotlabs/Module/Acl.php @@ -412,10 +412,12 @@ class Acl extends \Zotlabs\Web\Controller { $directory = find_upstream_directory($dirmode); $url = $directory['url'] . '/dirsearch'; } + + $token = get_config('system','realm_token'); $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100); if($url) { - $query = $url . '?f=' ; + $query = $url . '?f=' . (($token) ? '&t=' . urlencode($token) : ''); $query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode($search) : ''); $x = z_fetch_url($query); diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php index 536d85dde..30f3dfa48 100644 --- a/Zotlabs/Module/Admin.php +++ b/Zotlabs/Module/Admin.php @@ -52,6 +52,8 @@ class Admin extends \Zotlabs\Web\Controller { * Page content */ + nav_set_selected('Admin'); + $o = ''; if(argc() > 1) { @@ -91,10 +93,10 @@ class Admin extends \Zotlabs\Web\Controller { intval(ACCOUNT_BLOCKED) ); if ($r) { - $accounts['total'] = array('label' => t('# Accounts'), 'val' => $r[0]['total']); - $accounts['blocked'] = array('label' => t('# blocked accounts'), 'val' => $r[0]['blocked']); - $accounts['expired'] = array('label' => t('# expired accounts'), 'val' => $r[0]['expired']); - $accounts['expiring'] = array('label' => t('# expiring accounts'), 'val' => $r[0]['expiring']); + $accounts['total'] = array('label' => t('Accounts'), 'val' => $r[0]['total']); + $accounts['blocked'] = array('label' => t('Blocked accounts'), 'val' => $r[0]['blocked']); + $accounts['expired'] = array('label' => t('Expired accounts'), 'val' => $r[0]['expired']); + $accounts['expiring'] = array('label' => t('Expiring accounts'), 'val' => $r[0]['expiring']); } // pending registrations @@ -105,9 +107,9 @@ class Admin extends \Zotlabs\Web\Controller { $channels = array(); $r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0"); if ($r) { - $channels['total'] = array('label' => t('# Channels'), 'val' => $r[0]['total']); - $channels['main'] = array('label' => t('# primary'), 'val' => $r[0]['main']); - $channels['clones'] = array('label' => t('# clones'), 'val' => $r[0]['clones']); + $channels['total'] = array('label' => t('Channels'), 'val' => $r[0]['total']); + $channels['main'] = array('label' => t('Primary'), 'val' => $r[0]['main']); + $channels['clones'] = array('label' => t('Clones'), 'val' => $r[0]['clones']); } // We can do better, but this is a quick queue status @@ -118,14 +120,11 @@ class Admin extends \Zotlabs\Web\Controller { // If no plugins active return 0, otherwise list of plugin names $plugins = (count(\App::$plugins) == 0) ? count(\App::$plugins) : \App::$plugins; + if(is_array($plugins)) + sort($plugins); + // Could be extended to provide also other alerts to the admin $alertmsg = ''; - // annoy admin about upcoming unsupported PHP version - if (version_compare(PHP_VERSION, '5.4', '<')) { - $alertmsg = 'Your PHP version ' . PHP_VERSION . ' will not be supported with the next major release of $Projectname. You are strongly urged to upgrade to a current version.' - . '<br>PHP 5.3 has reached its <a href="http://php.net/eol.php" class="alert-link">End of Life (EOL)</a> in August 2014.' - . ' A list about current PHP versions can be found <a href="http://php.net/supported-versions.php" class="alert-link">here</a>.'; - } $vmaster = get_repository_version('master'); $vdev = get_repository_version('dev'); diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index d05e70aa9..4c5b82e78 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -17,7 +17,6 @@ class Site { check_form_security_token_redirectOnErr('/admin/site', 'admin_site'); $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : ''); - $server_role = ((x($_POST,'server_role')) ? notags(trim($_POST['server_role'])) : 'standard'); $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false); @@ -68,7 +67,6 @@ class Site { if(array_key_exists('techlevel', $_POST)) $techlevel = intval($_POST['techlevel']); - set_config('system', 'server_role', $server_role); set_config('system', 'feed_contacts', $feed_contacts); set_config('system', 'delivery_interval', $delivery_interval); set_config('system', 'delivery_batch_count', $delivery_batch_count); @@ -254,12 +252,6 @@ class Site { // now invert the logic for the setting. $discover_tab = (1 - $discover_tab); - $server_roles = [ - 'basic' => t('Basic/Minimal Social Networking'), - 'standard' => t('Standard Configuration (default)'), - 'pro' => t('Professional') - ]; - $techlevels = [ '0' => t('Beginner/Basic'), '1' => t('Novice - not skilled but willing to learn'), @@ -286,8 +278,6 @@ class Site { // name, label, value, help string, extra data... '$sitename' => array('sitename', t("Site name"), htmlspecialchars(get_config('system','sitename'), ENT_QUOTES, 'UTF-8'),''), - '$server_role' => array('server_role', t("Server Configuration/Role"), get_config('system','server_role'),'',$server_roles), - '$techlevel' => [ 'techlevel', t('Site default technical skill level'), get_config('system','techlevel'), t('Used to provide a member experience matched to technical comfort level'), $techlevels ], '$techlock' => [ 'techlock', t('Lock the technical skill level setting'), get_config('system','techlevel_lock'), t('Members can set their own technical comfort level by default') ], diff --git a/Zotlabs/Module/Ap_probe.php b/Zotlabs/Module/Ap_probe.php new file mode 100644 index 000000000..769cd4c4e --- /dev/null +++ b/Zotlabs/Module/Ap_probe.php @@ -0,0 +1,38 @@ +<?php +namespace Zotlabs\Module; + +require_once('include/zot.php'); + + +class Ap_probe extends \Zotlabs\Web\Controller { + + function get() { + + $o .= '<h3>ActivityPub Probe Diagnostic</h3>'; + + $o .= '<form action="ap_probe" method="get">'; + $o .= 'Lookup URI: <input type="text" style="width: 250px;" name="addr" value="' . $_GET['addr'] .'" /><br>'; + $o .= 'Request Signed version: <input type=checkbox name="magenv" value="1" ><br>'; + $o .= '<input type="submit" name="submit" value="Submit" /></form>'; + + $o .= '<br /><br />'; + + if(x($_GET,'addr')) { + $addr = $_GET['addr']; + + if($_GET['magenv']) { + $headers = 'Accept: application/magic-envelope+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; + } + else { + $headers = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; + } + + $redirects = 0; + $x = z_fetch_url($addr,true,$redirects, [ 'headers' => [ $headers ]]); + if($x['success']) + $o .= '<pre>' . str_replace(['\\n','\\'],["\n",''],jindent($x['body'])) . '</pre>'; + } + return $o; + } + +} diff --git a/Zotlabs/Module/Appman.php b/Zotlabs/Module/Appman.php index 70cc7e44b..5c0667357 100644 --- a/Zotlabs/Module/Appman.php +++ b/Zotlabs/Module/Appman.php @@ -84,6 +84,20 @@ class Appman extends \Zotlabs\Web\Controller { } $channel = \App::get_channel(); + + if(argc() > 2) { + if(argv(2) === 'moveup') { + Zlib\Apps::moveup(local_channel(),argv(1)); + } + if(argv(2) === 'movedown') { + Zlib\Apps::movedown(local_channel(),argv(1)); + } + goaway(z_root() . '/apporder'); + } + + + + $app = null; $embed = null; if($_REQUEST['appid']) { diff --git a/Zotlabs/Module/Apporder.php b/Zotlabs/Module/Apporder.php new file mode 100644 index 000000000..1097a01eb --- /dev/null +++ b/Zotlabs/Module/Apporder.php @@ -0,0 +1,40 @@ +<?php + +namespace Zotlabs\Module; + +use \Zotlabs\Lib as Zlib; + +class Apporder extends \Zotlabs\Web\Controller { + + function post() { + + } + + function get() { + $syslist = array(); + $list = Zlib\Apps::app_list(local_channel(), false, 'nav_featured_app'); + if($list) { + foreach($list as $li) { + $syslist[] = Zlib\Apps::app_encode($li); + } + } + Zlib\Apps::translate_system_apps($syslist); + + usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare'); + + $syslist = Zlib\Apps::app_order(local_channel(),$syslist); + + foreach($syslist as $app) { + $nav_apps[] = Zlib\Apps::app_render($app,'nav-order'); + + } + + return replace_macros(get_markup_template('apporder.tpl'), + [ + '$header' => t('Change Order of Navigation Apps'), + '$desc' => t('Use arrows to move the corresponding app up or down in the display list'), + '$nav_apps' => $nav_apps + ] + ); + } +} diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php new file mode 100644 index 000000000..06f66c456 --- /dev/null +++ b/Zotlabs/Module/Authorize.php @@ -0,0 +1,71 @@ +<?php + +namespace Zotlabs\Module; + + +class Authorize extends \Zotlabs\Web\Controller { + + + function get() { + + + // workaround for HTTP-auth in CGI mode + if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + if (x($_SERVER, 'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + + + + require_once('include/oauth2.php'); + + $request = \OAuth2\Request::createFromGlobals(); + $response = new \OAuth2\Response(); + + // validate the authorize request + if (! $oauth2_server->validateAuthorizeRequest($request, $response)) { + $response->send(); + killme(); + } + + // display an authorization form + if (empty($_POST)) { + + return ' +<form method="post"> + <label>Do You Authorize TestClient?</label><br /> + <input type="submit" name="authorized" value="yes"> + <input type="submit" name="authorized" value="no"> +</form>'; + } + + // print the authorization code if the user has authorized your client + $is_authorized = ($_POST['authorized'] === 'yes'); + $oauth2_server->handleAuthorizeRequest($request, $response, $is_authorized); + if ($is_authorized) { + // this is only here so that you get to see your code in the cURL request. Otherwise, + // we'd redirect back to the client + $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40); + echo("SUCCESS! Authorization Code: $code"); + + } + + $response->send(); + killme(); + } + +}
\ No newline at end of file diff --git a/Zotlabs/Module/Block.php b/Zotlabs/Module/Block.php index e671730f6..d0fed44fe 100644 --- a/Zotlabs/Module/Block.php +++ b/Zotlabs/Module/Block.php @@ -3,8 +3,6 @@ namespace Zotlabs\Module; require_once('include/items.php'); require_once('include/conversation.php'); -require_once('include/page_widgets.php'); - class Block extends \Zotlabs\Web\Controller { diff --git a/Zotlabs/Module/Bookmarks.php b/Zotlabs/Module/Bookmarks.php index 682f8e76c..e62f5ce96 100644 --- a/Zotlabs/Module/Bookmarks.php +++ b/Zotlabs/Module/Bookmarks.php @@ -7,6 +7,9 @@ class Bookmarks extends \Zotlabs\Web\Controller { function init() { if(! local_channel()) return; + + nav_set_selected(t('View Bookmarks')); + $item_id = intval($_REQUEST['item']); $burl = trim($_REQUEST['burl']); diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php new file mode 100644 index 000000000..d0619ef0b --- /dev/null +++ b/Zotlabs/Module/Cdav.php @@ -0,0 +1,1209 @@ +<?php +namespace Zotlabs\Module; + +require_once('include/event.php'); + +class Cdav extends \Zotlabs\Web\Controller { + + function init() { + + if((argv(1) !== 'calendar') && (argv(1) !== 'addressbook')) { + + // workaround for HTTP-auth in CGI mode + if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + if (x($_SERVER, 'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + /** + * This server combines both CardDAV and CalDAV functionality into a single + * server. It is assumed that the server runs at the root of a HTTP domain (be + * that a domainname-based vhost or a specific TCP port. + * + * This example also assumes that you're using SQLite and the database has + * already been setup (along with the database tables). + * + * You may choose to use MySQL instead, just change the PDO connection + * statement. + */ + + /** + * UTC or GMT is easy to work with, and usually recommended for any + * application. + */ + date_default_timezone_set('UTC'); + + /** + * Make sure this setting is turned on and reflect the root url for your WebDAV + * server. + * + * This can be for example the root / or a complete path to your server script. + */ + + $baseUri = '/cdav/'; + + /** + * Database + * + */ + + $pdo = \DBA::$dba->db; + + // Autoloader + require_once 'vendor/autoload.php'; + + /** + * The backends. Yes we do really need all of them. + * + * This allows any developer to subclass just any of them and hook into their + * own backend systems. + */ + + $auth = new \Zotlabs\Storage\BasicAuth(); + $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'CalDAV/CardDAV'); + + if (local_channel()) { + logger('loggedin'); + $channel = \App::get_channel(); + $auth->setCurrentUser($channel['channel_address']); + $auth->channel_id = $channel['channel_id']; + $auth->channel_hash = $channel['channel_hash']; + $auth->channel_account_id = $channel['channel_account_id']; + if($channel['channel_timezone']) + $auth->setTimezone($channel['channel_timezone']); + $auth->observer = $channel['channel_hash']; + + $principalUri = 'principals/' . $channel['channel_address']; + if(!cdav_principal($principalUri)) { + $this->activate($pdo, $channel); + if(!cdav_principal($principalUri)) { + return; + } + } + + } + + + $principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo); + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + + /** + * The directory tree + * + * Basically this is an array which contains the 'top-level' directories in the + * WebDAV server. + */ + + $nodes = [ + // /principals + new \Sabre\CalDAV\Principal\Collection($principalBackend), + // /calendars + new \Sabre\CalDAV\CalendarRoot($principalBackend, $caldavBackend), + // /addressbook + new \Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend), + ]; + + // The object tree needs in turn to be passed to the server class + + $server = new \Sabre\DAV\Server($nodes); + + if(isset($baseUri)) + $server->setBaseUri($baseUri); + + // Plugins + $server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth)); + //$server->addPlugin(new \Sabre\DAV\Browser\Plugin()); + $server->addPlugin(new \Sabre\DAV\Sync\Plugin()); + $server->addPlugin(new \Sabre\DAV\Sharing\Plugin()); + $server->addPlugin(new \Sabre\DAVACL\Plugin()); + + // CalDAV plugins + $server->addPlugin(new \Sabre\CalDAV\Plugin()); + $server->addPlugin(new \Sabre\CalDAV\SharingPlugin()); + //$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin()); + $server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin()); + + // CardDAV plugins + $server->addPlugin(new \Sabre\CardDAV\Plugin()); + $server->addPlugin(new \Sabre\CardDAV\VCFExportPlugin()); + + // And off we go! + $server->exec(); + + killme(); + + } + + } + + function post() { + if(! local_channel()) + return; + + $channel = \App::get_channel(); + $principalUri = 'principals/' . $channel['channel_address']; + + if(!cdav_principal($principalUri)) + return; + + $pdo = \DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + if(argc() == 2 && argv(1) === 'calendar') { + + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $calendars = $caldavBackend->getCalendarsForUser($principalUri); + + //create new calendar + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + do { + $duplicate = false; + $calendarUri = random_string(40); + + $r = q("SELECT uri FROM calendarinstances WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", + dbesc($principalUri), + dbesc($calendarUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + $properties = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], + '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'], + '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] + ]; + + $id = $caldavBackend->createCalendar($principalUri, $calendarUri, $properties); + + // set new calendar to be visible + set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); + } + + //create new calendar object via ajax request + if($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { + + $id = explode(':', $_REQUEST['target']); + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $title = $_REQUEST['title']; + $dtstart = new \DateTime($_REQUEST['dtstart']); + if($_REQUEST['dtend']) + $dtend = new \DateTime($_REQUEST['dtend']); + $description = $_REQUEST['description']; + $location = $_REQUEST['location']; + + do { + $duplicate = false; + $objectUri = random_string(40) . '.ics'; + + $r = q("SELECT uri FROM calendarobjects WHERE calendarid = %s AND uri = '%s' LIMIT 1", + intval($id[0]), + dbesc($objectUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + + $vcalendar = new \Sabre\VObject\Component\VCalendar([ + 'VEVENT' => [ + 'SUMMARY' => $title, + 'DTSTART' => $dtstart + ] + ]); + if($dtend) + $vcalendar->VEVENT->add('DTEND', $dtend); + if($description) + $vcalendar->VEVENT->add('DESCRIPTION', $description); + if($location) + $vcalendar->VEVENT->add('LOCATION', $location); + + $calendarData = $vcalendar->serialize(); + + $caldavBackend->createCalendarObject($id, $objectUri, $calendarData); + + killme(); + } + + //edit calendar name and color + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) { + + $id = explode(':', $_REQUEST['id']); + + if(! cdav_perms($id[0],$calendars)) + return; + + $mutations = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], + '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'] + ]; + + $patch = new \Sabre\DAV\PropPatch($mutations); + + $caldavBackend->updateCalendar($id, $patch); + + $patch->commit(); + + } + + //edit calendar object via ajax request + if($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { + + $id = explode(':', $_REQUEST['target']); + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $uri = $_REQUEST['uri']; + $title = $_REQUEST['title']; + $dtstart = new \DateTime($_REQUEST['dtstart']); + $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : ''; + $description = $_REQUEST['description']; + $location = $_REQUEST['location']; + + $object = $caldavBackend->getCalendarObject($id, $uri); + + $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); + + if($title) + $vcalendar->VEVENT->SUMMARY = $title; + if($dtstart) + $vcalendar->VEVENT->DTSTART = $dtstart; + if($dtend) + $vcalendar->VEVENT->DTEND = $dtend; + else + unset($vcalendar->VEVENT->DTEND); + if($description) + $vcalendar->VEVENT->DESCRIPTION = $description; + if($location) + $vcalendar->VEVENT->LOCATION = $location; + + $calendarData = $vcalendar->serialize(); + + $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + + killme(); + } + + //delete calendar object via ajax request + if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = explode(':', $_REQUEST['target']); + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $uri = $_REQUEST['uri']; + + $caldavBackend->deleteCalendarObject($id, $uri); + + killme(); + } + + //edit calendar object date/timeme via ajax request (drag and drop) + if($_REQUEST['update'] && $_REQUEST['id'] && $_REQUEST['uri']) { + + $id = [$_REQUEST['id'][0], $_REQUEST['id'][1]]; + + if(!cdav_perms($id[0],$calendars,true)) + return; + + $uri = $_REQUEST['uri']; + $dtstart = new \DateTime($_REQUEST['dtstart']); + $dtend = $_REQUEST['dtend'] ? new \DateTime($_REQUEST['dtend']) : ''; + + $object = $caldavBackend->getCalendarObject($id, $uri); + + $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); + + if($dtstart) { + $vcalendar->VEVENT->DTSTART = $dtstart; + } + if($dtend) { + $vcalendar->VEVENT->DTEND = $dtend; + } + else { + unset($vcalendar->VEVENT->DTEND); + } + + $calendarData = $vcalendar->serialize(); + + $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + + killme(); + } + + //share a calendar - this only works on local system (with channels on the same server) + if($_REQUEST['sharee'] && $_REQUEST['share']) { + + $id = [intval($_REQUEST['calendarid']), intval($_REQUEST['instanceid'])]; + + if(! cdav_perms($id[0],$calendars)) + return; + + $hash = $_REQUEST['sharee']; + + $sharee_arr = channelx_by_hash($hash); + + $sharee = new \Sabre\DAV\Xml\Element\Sharee(); + + $sharee->href = 'mailto:' . $sharee_arr['xchan_addr']; + $sharee->principal = 'principals/' . $sharee_arr['channel_address']; + $sharee->access = intval($_REQUEST['access']); + $sharee->properties = ['{DAV:}displayname' => $channel['channel_name']]; + + $caldavBackend->updateInvites($id, [$sharee]); + } + } + + if(argc() >= 2 && argv(1) === 'addressbook') { + + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); + + //create new addressbook + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + do { + $duplicate = false; + $addressbookUri = random_string(20); + + $r = q("SELECT uri FROM addressbooks WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", + dbesc($principalUri), + dbesc($addressbookUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + $properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']]; + + $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties); + } + + //edit addressbook + if($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) { + + $id = $_REQUEST['id']; + + if(! cdav_perms($id,$addressbooks)) + return; + + $mutations = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'] + ]; + + $patch = new \Sabre\DAV\PropPatch($mutations); + + $carddavBackend->updateAddressBook($id, $patch); + + $patch->commit(); + } + + //create addressbook card + if($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { + $id = $_REQUEST['target']; + + do { + $duplicate = false; + $uri = random_string(40) . '.vcf'; + + $r = q("SELECT uri FROM cards WHERE addressbookid = %s AND uri = '%s' LIMIT 1", + intval($id), + dbesc($uri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + //TODO: this mostly duplictes the procedure in update addressbook card. should move this part to a function to avoid duplication + $fn = $_REQUEST['fn']; + + $vcard = new \Sabre\VObject\Component\VCard([ + 'FN' => $fn, + 'N' => array_reverse(explode(' ', $fn)) + ]); + + $org = $_REQUEST['org']; + if($org) { + $vcard->ORG = $org; + } + + $title = $_REQUEST['title']; + if($title) { + $vcard->TITLE = $title; + } + + $tel = $_REQUEST['tel']; + $tel_type = $_REQUEST['tel_type']; + if($tel) { + $i = 0; + foreach($tel as $item) { + if($item) { + $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); + } + $i++; + } + } + + $email = $_REQUEST['email']; + $email_type = $_REQUEST['email_type']; + if($email) { + $i = 0; + foreach($email as $item) { + if($item) { + $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); + } + $i++; + } + } + + $impp = $_REQUEST['impp']; + $impp_type = $_REQUEST['impp_type']; + if($impp) { + $i = 0; + foreach($impp as $item) { + if($item) { + $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); + } + $i++; + } + } + + $url = $_REQUEST['url']; + $url_type = $_REQUEST['url_type']; + if($url) { + $i = 0; + foreach($url as $item) { + if($item) { + $vcard->add('URL', $item, ['type' => $url_type[$i]]); + } + $i++; + } + } + + $adr = $_REQUEST['adr']; + $adr_type = $_REQUEST['adr_type']; + + if($adr) { + $i = 0; + foreach($adr as $item) { + if($item) { + $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); + } + $i++; + } + } + + $note = $_REQUEST['note']; + if($note) { + $vcard->NOTE = $note; + } + + $cardData = $vcard->serialize(); + + $carddavBackend->createCard($id, $uri, $cardData); + + } + + //edit addressbook card + if($_REQUEST['update'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = $_REQUEST['target']; + + if(!cdav_perms($id,$addressbooks)) + return; + + $uri = $_REQUEST['uri']; + + $object = $carddavBackend->getCard($id, $uri); + $vcard = \Sabre\VObject\Reader::read($object['carddata']); + + $fn = $_REQUEST['fn']; + if($fn) { + $vcard->FN = $fn; + $vcard->N = array_reverse(explode(' ', $fn)); + } + + $org = $_REQUEST['org']; + if($org) { + $vcard->ORG = $org; + } + else { + unset($vcard->ORG); + } + + $title = $_REQUEST['title']; + if($title) { + $vcard->TITLE = $title; + } + else { + unset($vcard->TITLE); + } + + $tel = $_REQUEST['tel']; + $tel_type = $_REQUEST['tel_type']; + if($tel) { + $i = 0; + unset($vcard->TEL); + foreach($tel as $item) { + if($item) { + $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->TEL); + } + + $email = $_REQUEST['email']; + $email_type = $_REQUEST['email_type']; + if($email) { + $i = 0; + unset($vcard->EMAIL); + foreach($email as $item) { + if($item) { + $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->EMAIL); + } + + $impp = $_REQUEST['impp']; + $impp_type = $_REQUEST['impp_type']; + if($impp) { + $i = 0; + unset($vcard->IMPP); + foreach($impp as $item) { + if($item) { + $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->IMPP); + } + + $url = $_REQUEST['url']; + $url_type = $_REQUEST['url_type']; + if($url) { + $i = 0; + unset($vcard->URL); + foreach($url as $item) { + if($item) { + $vcard->add('URL', $item, ['type' => $url_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->URL); + } + + $adr = $_REQUEST['adr']; + $adr_type = $_REQUEST['adr_type']; + if($adr) { + $i = 0; + unset($vcard->ADR); + foreach($adr as $item) { + if($item) { + $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); + } + $i++; + } + } + else { + unset($vcard->ADR); + } + + $note = $_REQUEST['note']; + if($note) { + $vcard->NOTE = $note; + } + else { + unset($vcard->NOTE); + } + + $cardData = $vcard->serialize(); + + $carddavBackend->updateCard($id, $uri, $cardData); + } + + //delete addressbook card + if($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = $_REQUEST['target']; + + if(!cdav_perms($id,$addressbooks)) + return; + + $uri = $_REQUEST['uri']; + + $carddavBackend->deleteCard($id, $uri); + } + } + + //Import calendar or addressbook + if(($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) { + + $src = @file_get_contents($_FILES['userfile']['tmp_name']); + + if($src) { + + if($_REQUEST['c_upload']) { + $id = explode(':', $_REQUEST['target']); + $ext = 'ics'; + $table = 'calendarobjects'; + $column = 'calendarid'; + $objects = new \Sabre\VObject\Splitter\ICalendar($src); + $profile = \Sabre\VObject\Node::PROFILE_CALDAV; + $backend = new \Sabre\CalDAV\Backend\PDO($pdo); + } + + if($_REQUEST['a_upload']) { + $id[] = intval($_REQUEST['target']); + $ext = 'vcf'; + $table = 'cards'; + $column = 'addressbookid'; + $objects = new \Sabre\VObject\Splitter\VCard($src); + $profile = \Sabre\VObject\Node::PROFILE_CARDDAV; + $backend = new \Sabre\CardDAV\Backend\PDO($pdo); + } + + while ($object = $objects->getNext()) { + + if($_REQUEST['a_upload']) { + $object = $object->convert(\Sabre\VObject\Document::VCARD40); + } + + $ret = $object->validate($profile & \Sabre\VObject\Node::REPAIR); + + //level 3 Means that the document is invalid, + //level 2 means a warning. A warning means it's valid but it could cause interopability issues, + //level 1 means that there was a problem earlier, but the problem was automatically repaired. + + if($ret[0]['level'] < 3) { + do { + $duplicate = false; + $objectUri = random_string(40) . '.' . $ext; + + $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1", + dbesc($id[0]), + dbesc($objectUri) + ); + + if (count($r)) + $duplicate = true; + } while ($duplicate == true); + + if($_REQUEST['c_upload']) { + $backend->createCalendarObject($id, $objectUri, $object->serialize()); + } + + if($_REQUEST['a_upload']) { + $backend->createCard($id[0], $objectUri, $object->serialize()); + } + } + else { + if($_REQUEST['c_upload']) { + notice( '<strong>' . t('INVALID EVENT DISMISSED!') . '</strong>' . EOL . + '<strong>' . t('Summary: ') . '</strong>' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . + '<strong>' . t('Date: ') . '</strong>' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . + '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL + ); + } + + if($_REQUEST['a_upload']) { + notice( '<strong>' . t('INVALID CARD DISMISSED!') . '</strong>' . EOL . + '<strong>' . t('Name: ') . '</strong>' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . + '<strong>' . t('Reason: ') . '</strong>' . $ret[0]['message'] . EOL + ); + } + } + } + } + @unlink($src); + } + } + + function get() { + + if(!local_channel()) + return; + + $channel = \App::get_channel(); + $principalUri = 'principals/' . $channel['channel_address']; + + $pdo = \DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + head_add_css('cdav.css'); + + if(!cdav_principal($principalUri)) { + $this->activate($pdo, $channel); + if(!cdav_principal($principalUri)) { + return; + } + } + + if(argv(1) === 'calendar') { + nav_set_selected(t('CalDAV')); + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $calendars = $caldavBackend->getCalendarsForUser($principalUri); + } + + //Display calendar(s) here + if(argc() == 2 && argv(1) === 'calendar') { + + head_add_css('/library/fullcalendar/fullcalendar.css'); + head_add_css('cdav_calendar.css'); + + head_add_js('/library/moment/moment.min.js', 1); + head_add_js('/library/fullcalendar/fullcalendar.min.js', 1); + head_add_js('/library/fullcalendar/locale-all.js', 1); + + foreach($calendars as $calendar) { + $editable = (($calendar['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript + $color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad'); + $sharer = (($calendar['share-access'] == 3) ? $calendar['{urn:ietf:params:xml:ns:caldav}calendar-description'] : ''); + $switch = get_pconfig(local_channel(), 'cdav_calendar', $calendar['id'][0]); + if($switch) { + $sources .= '{ + url: \'/cdav/calendar/json/' . $calendar['id'][0] . '/' . $calendar['id'][1] . '\', + color: \'' . $color . '\' + }, '; + } + + if($calendar['share-access'] != 2) { + $writable_calendars[] = [ + 'displayname' => $calendar['{DAV:}displayname'], + 'sharer' => $sharer, + 'id' => $calendar['id'] + ]; + } + } + + $sources = rtrim($sources, ', '); + + $first_day = get_pconfig(local_channel(),'system','cal_first_day'); + $first_day = (($first_day) ? $first_day : 0); + + $title = ['title', t('Event title')]; + $dtstart = ['dtstart', t('Start date and time'), '', t('Example: YYYY-MM-DD HH:mm')]; + $dtend = ['dtend', t('End date and time'), '', t('Example: YYYY-MM-DD HH:mm')]; + $description = ['description', t('Description')]; + $location = ['location', t('Location')]; + + $o .= replace_macros(get_markup_template('cdav_calendar.tpl'), [ + '$sources' => $sources, + '$color' => $color, + '$lang' => \App::$language, + '$first_day' => $first_day, + '$prev' => t('Previous'), + '$next' => t('Next'), + '$today' => t('Today'), + '$month' => t('Month'), + '$week' => t('Week'), + '$day' => t('Day'), + '$list_month' => t('List month'), + '$list_week' => t('List week'), + '$list_day' => t('List day'), + '$title' => $title, + '$writable_calendars' => $writable_calendars, + '$dtstart' => $dtstart, + '$dtend' => $dtend, + '$description' => $description, + '$location' => $location, + '$more' => t('More'), + '$less' => t('Less'), + '$calendar_select_label' => t('Select calendar'), + '$delete' => t('Delete'), + '$delete_all' => t('Delete all'), + '$cancel' => t('Cancel'), + '$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.') + ]); + + return $o; + + } + + //Provide json data for calendar + if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'json' && intval(argv(3)) && intval(argv(4))) { + + $id = [argv(3), argv(4)]; + + if(! cdav_perms($id[0],$calendars)) + killme(); + + if (x($_GET,'start')) + $start = new \DateTime($_GET['start']); + if (x($_GET,'end')) + $end = new \DateTime($_GET['end']); + + $filters['name'] = 'VCALENDAR'; + $filters['prop-filters'][0]['name'] = 'VEVENT'; + $filters['comp-filters'][0]['name'] = 'VEVENT'; + $filters['comp-filters'][0]['time-range']['start'] = $start; + $filters['comp-filters'][0]['time-range']['end'] = $end; + + $uris = $caldavBackend->calendarQuery($id, $filters); + if($uris) { + + $objects = $caldavBackend->getMultipleCalendarObjects($id, $uris); + + foreach($objects as $object) { + + $vcalendar = \Sabre\VObject\Reader::read($object['calendardata']); + + if(isset($vcalendar->VEVENT->RRULE)) + $vcalendar = $vcalendar->expand($start, $end); + + foreach($vcalendar->VEVENT as $vevent) { + $title = (string)$vevent->SUMMARY; + $dtstart = (string)$vevent->DTSTART; + $dtend = (string)$vevent->DTEND; + $description = (string)$vevent->DESCRIPTION; + $location = (string)$vevent->LOCATION; + + $rw = ((cdav_perms($id[0],$calendars,true)) ? true : false); + $recurrent = ((isset($vevent->{'RECURRENCE-ID'})) ? true : false); + + $editable = $rw ? true : false; + + if($recurrent) + $editable = false; + + $allDay = false; + + // allDay event rules + if(!strpos($dtstart, 'T') && !strpos($dtend, 'T')) + $allDay = true; + if(strpos($dtstart, 'T000000') && strpos($dtend, 'T000000')) + $allDay = true; + + $events[] = [ + 'calendar_id' => $id, + 'uri' => $object['uri'], + 'title' => $title, + 'start' => $dtstart, + 'end' => $dtend, + 'description' => $description, + 'location' => $location, + 'allDay' => $allDay, + 'editable' => $editable, + 'recurrent' => $recurrent, + 'rw' => $rw + ]; + } + } + json_return_and_die($events); + } + else { + killme(); + } + } + + //enable/disable calendars + if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && intval(argv(3)) && (argv(4) == 1 || argv(4) == 0)) { + $id = argv(3); + + if(! cdav_perms($id,$calendars)) + killme(); + + set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4)); + killme(); + } + + //drop calendar + if(argc() == 5 && argv(1) === 'calendar' && argv(2) === 'drop' && intval(argv(3)) && intval(argv(4))) { + $id = [argv(3), argv(4)]; + + if(! cdav_perms($id[0],$calendars)) + killme(); + + $caldavBackend->deleteCalendar($id); + killme(); + } + + //drop sharee + if(argc() == 6 && argv(1) === 'calendar' && argv(2) === 'dropsharee' && intval(argv(3)) && intval(argv(4))) { + + $id = [argv(3), argv(4)]; + $hash = argv(5); + + if(! cdav_perms($id[0],$calendars)) + killme(); + + $sharee_arr = channelx_by_hash($hash); + + $sharee = new \Sabre\DAV\Xml\Element\Sharee(); + + $sharee->href = 'mailto:' . $sharee_arr['xchan_addr']; + $sharee->principal = 'principals/' . $sharee_arr['channel_address']; + $sharee->access = 4; + $caldavBackend->updateInvites($id, [$sharee]); + + killme(); + } + + + if(argv(1) === 'addressbook') { + nav_set_selected(t('CardDAV')); + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); + } + + //Display Adressbook here + if(argc() == 3 && argv(1) === 'addressbook' && intval(argv(2))) { + + $id = argv(2); + + $displayname = cdav_perms($id,$addressbooks); + + if(!$displayname) + return; + + head_add_css('cdav_addressbook.css'); + + $o = ''; + + $sabrecards = $carddavBackend->getCards($id); + foreach($sabrecards as $sabrecard) { + $uris[] = $sabrecard['uri']; + } + + if($uris) { + $objects = $carddavBackend->getMultipleCards($id, $uris); + + foreach($objects as $object) { + $vcard = \Sabre\VObject\Reader::read($object['carddata']); + + $photo = ''; + if($vcard->PHOTO) { + $photo_value = strtolower($vcard->PHOTO->getValueType()); // binary or uri + if($photo_value === 'binary') { + $photo_type = strtolower($vcard->PHOTO['TYPE']); // mime jpeg, png or gif + $photo = 'data:image/' . $photo_type . ';base64,' . base64_encode((string)$vcard->PHOTO); + } + else { + $url = parse_url((string)$vcard->PHOTO); + $photo = 'data:' . $url['path']; + } + } + + $fn = ''; + if($vcard->FN) { + $fn = (string)$vcard->FN; + } + + $org = ''; + if($vcard->ORG) { + $org = (string)$vcard->ORG; + } + + $title = ''; + if($vcard->TITLE) { + $title = (string)$vcard->TITLE; + } + + $tels = []; + if($vcard->TEL) { + foreach($vcard->TEL as $tel) { + $type = (($tel['TYPE']) ? translate_type((string)$tel['TYPE']) : ''); + $tels[] = [ + 'type' => $type, + 'nr' => (string)$tel + ]; + } + } + + $emails = []; + if($vcard->EMAIL) { + foreach($vcard->EMAIL as $email) { + $type = (($email['TYPE']) ? translate_type((string)$email['TYPE']) : ''); + $emails[] = [ + 'type' => $type, + 'address' => (string)$email + ]; + } + } + + $impps = []; + if($vcard->IMPP) { + foreach($vcard->IMPP as $impp) { + $type = (($impp['TYPE']) ? translate_type((string)$impp['TYPE']) : ''); + $impps[] = [ + 'type' => $type, + 'address' => (string)$impp + ]; + } + } + + $urls = []; + if($vcard->URL) { + foreach($vcard->URL as $url) { + $type = (($url['TYPE']) ? translate_type((string)$url['TYPE']) : ''); + $urls[] = [ + 'type' => $type, + 'address' => (string)$url + ]; + } + } + + $adrs = []; + if($vcard->ADR) { + foreach($vcard->ADR as $adr) { + $type = (($adr['TYPE']) ? translate_type((string)$adr['TYPE']) : ''); + $adrs[] = [ + 'type' => $type, + 'address' => $adr->getParts() + ]; + } + } + + $note = ''; + if($vcard->NOTE) { + $note = (string)$vcard->NOTE; + } + + $cards[] = [ + 'id' => $object['id'], + 'uri' => $object['uri'], + + 'photo' => $photo, + 'fn' => $fn, + 'org' => $org, + 'title' => $title, + 'tels' => $tels, + 'emails' => $emails, + 'impps' => $impps, + 'urls' => $urls, + 'adrs' => $adrs, + 'note' => $note + ]; + } + + usort($cards, function($a, $b) { return strcasecmp($a['fn'], $b['fn']); }); + } + + $o .= replace_macros(get_markup_template('cdav_addressbook.tpl'), [ + '$id' => $id, + '$cards' => $cards, + '$displayname' => $displayname, + '$name_label' => t('Name'), + '$org_label' => t('Organisation'), + '$title_label' => t('Title'), + '$tel_label' => t('Phone'), + '$email_label' => t('Email'), + '$impp_label' => t('Instant messenger'), + '$url_label' => t('Website'), + '$adr_label' => t('Address'), + '$note_label' => t('Note'), + '$mobile' => t('Mobile'), + '$home' => t('Home'), + '$work' => t('Work'), + '$other' => t('Other'), + '$add_card' => t('Add Contact'), + '$add_field' => t('Add Field'), + '$create' => t('Create'), + '$update' => t('Update'), + '$delete' => t('Delete'), + '$cancel' => t('Cancel'), + '$po_box' => t('P.O. Box'), + '$extra' => t('Additional'), + '$street' => t('Street'), + '$locality' => t('Locality'), + '$region' => t('Region'), + '$zip_code' => t('ZIP Code'), + '$country' => t('Country') + ]); + + return $o; + } + + //delete addressbook + if(argc() > 3 && argv(1) === 'addressbook' && argv(2) === 'drop' && intval(argv(3))) { + $id = argv(3); + + if(! cdav_perms($id,$addressbooks)) + return; + + $carddavBackend->deleteAddressBook($id); + killme(); + } + + } + + function activate($pdo, $channel) { + + if(! $channel) + return; + + $uri = 'principals/' . $channel['channel_address']; + + + $r = q("select * from principals where uri = '%s' limit 1", + dbesc($uri) + ); + if($r) { + $r = q("update principals set email = '%s', displayname = '%s' where uri = '%s' ", + dbesc($channel['xchan_addr']), + dbesc($channel['channel_name']), + dbesc($uri) + ); + } + else { + $r = q("insert into principals ( uri, email, displayname ) values('%s','%s','%s') ", + dbesc($uri), + dbesc($channel['xchan_addr']), + dbesc($channel['channel_name']) + ); + + //create default calendar + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $properties = [ + '{DAV:}displayname' => t('Default Calendar'), + '{http://apple.com/ns/ical/}calendar-color' => '#3a87ad', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] + ]; + + $id = $caldavBackend->createCalendar($uri, 'default', $properties); + set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); + + //create default addressbook + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + $properties = ['{DAV:}displayname' => t('Default Addressbook')]; + $carddavBackend->createAddressBook($uri, $default, $properties); + + } + } + + +} diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 61df35a60..a44984c97 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -94,7 +94,7 @@ class Channel extends \Zotlabs\Web\Controller { } else { if(\App::$profile['profile_uid'] == local_channel()) { - nav_set_selected('home'); + nav_set_selected(t('Channel Home')); } } @@ -217,10 +217,10 @@ class Channel extends \Zotlabs\Web\Controller { else { if(x($category)) { - $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY)); + $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $category, TERM_CATEGORY)); } if(x($hashtags)) { - $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); + $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); } if($datequery) { @@ -236,9 +236,9 @@ class Channel extends \Zotlabs\Web\Controller { if($load || ($checkjs->disabled())) { if($mid) { - $r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal + $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal AND item_wall = 1 $sql_extra limit 1", - dbesc($mid), + dbesc($mid . '%'), intval(\App::$profile['profile_uid']) ); if (! $r) { @@ -325,8 +325,8 @@ class Channel extends \Zotlabs\Web\Controller { '$order' => '', '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), '$file' => '', - '$cats' => (($category) ? $category : ''), - '$tags' => (($hashtags) ? $hashtags : ''), + '$cats' => (($category) ? urlencode($category) : ''), + '$tags' => (($hashtags) ? urlencode($hashtags) : ''), '$mid' => $mid, '$verb' => '', '$dend' => $datequery, @@ -365,10 +365,10 @@ class Channel extends \Zotlabs\Web\Controller { if($checkjs->disabled()) { - $o .= conversation($a,$items,'channel',$update,'traditional'); + $o .= conversation($items,'channel',$update,'traditional'); } else { - $o .= conversation($a,$items,'channel',$update,$page_mode); + $o .= conversation($items,'channel',$update,$page_mode); } if((! $update) || ($checkjs->disabled())) { diff --git a/Zotlabs/Module/Chanview.php b/Zotlabs/Module/Chanview.php index 01ee74d5a..24ab9b022 100644 --- a/Zotlabs/Module/Chanview.php +++ b/Zotlabs/Module/Chanview.php @@ -102,27 +102,32 @@ class Chanview extends \Zotlabs\Web\Controller { } $is_zot = false; + $connected = false; if (\App::$poi) { $url = \App::$poi['xchan_url']; if(\App::$poi['xchan_network'] === 'zot') { $is_zot = true; } + if(local_channel()) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1", + intval(local_channel()), + dbesc(\App::$poi['xchan_hash']) + ); + if($c) + $connected = true; + } } - + // We will load the chanview template if it's a foreign network, // just so that we can provide a connect button along with a profile // photo. Chances are we can't load the remote profile into an iframe // because of cross-domain security headers. So provide a link to // the remote profile. - + // If we are already connected, just go to the profile. // Zot channels will usually have a connect link. - // If it isn't zot, 'pro' members won't be able to use the connect - // button as it is a foreign network so just send them to the remote - // profile. - - if($is_zot || \Zotlabs\Lib\System::get_server_role() === 'pro') { + if($is_zot || $connected) { if($is_zot && $observer) { $url = zid($url); } diff --git a/Zotlabs/Module/Chat.php b/Zotlabs/Module/Chat.php index 23a3e65da..138ca1cb5 100644 --- a/Zotlabs/Module/Chat.php +++ b/Zotlabs/Module/Chat.php @@ -89,9 +89,11 @@ class Chat extends \Zotlabs\Web\Controller { function get() { - if(local_channel()) + if(local_channel()) { $channel = \App::get_channel(); - + nav_set_selected(t('My Chatrooms')); + } + $ob = \App::get_observer(); $observer = get_observer_hash(); if(! $observer) { diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php index 7370eeda3..75191a279 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -86,12 +86,13 @@ class Cloud extends \Zotlabs\Web\Controller { // require_once('\Zotlabs\Storage/QuotaPlugin.php'); // $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth)); - ob_start(); +// ob_start(); // All we need to do now, is to fire up the server $server->exec(); - ob_end_flush(); - +// ob_end_flush(); + if($browser->build_page) + construct_page(); killme(); } diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php index b079ae860..6ad1e9528 100644 --- a/Zotlabs/Module/Connections.php +++ b/Zotlabs/Module/Connections.php @@ -19,7 +19,7 @@ class Connections extends \Zotlabs\Web\Controller { } - function get() { + function get() { $sort_type = 0; $o = ''; @@ -29,6 +29,8 @@ class Connections extends \Zotlabs\Web\Controller { notice( t('Permission denied.') . EOL); return login(); } + + nav_set_selected(t('Connections')); $blocked = false; $hidden = false; @@ -63,15 +65,14 @@ class Connections extends \Zotlabs\Web\Controller { $hidden = true; break; case 'archived': - $search_flags = " and abook_archived = 1 "; - $head = t('Archived'); + $search_flags = " and ( abook_archived = 1 OR abook_not_here = 1) "; + $head = t('Archived/Unreachable'); $archived = true; break; case 'pending': $search_flags = " and abook_pending = 1 "; $head = t('New'); $pending = true; - nav_set_selected('intros'); break; case 'ifpending': $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 ", @@ -81,7 +82,6 @@ class Connections extends \Zotlabs\Web\Controller { $search_flags = " and abook_pending = 1 "; $head = t('New'); $pending = true; - nav_set_selected('intros'); \App::$argv[1] = 'pending'; } else { @@ -91,7 +91,6 @@ class Connections extends \Zotlabs\Web\Controller { \App::$argc = 1; unset(\App::$argv[1]); } - nav_set_selected('intros'); break; // case 'unconnected': // $search_flags = " and abook_unconnected = 1 "; @@ -168,10 +167,10 @@ class Connections extends \Zotlabs\Web\Controller { ), 'archived' => array( - 'label' => t('Archived'), + 'label' => t('Archived/Unreachable'), 'url' => z_root() . '/connections/archived', 'sel' => ($archived) ? 'active' : '', - 'title' => t('Only show archived connections'), + 'title' => t('Only show archived/unreachable connections'), ), 'hidden' => array( @@ -243,7 +242,8 @@ class Connections extends \Zotlabs\Web\Controller { ((intval($rr['abook_archived'])) ? t('Archived') : ''), ((intval($rr['abook_hidden'])) ? t('Hidden') : ''), ((intval($rr['abook_ignored'])) ? t('Ignored') : ''), - ((intval($rr['abook_blocked'])) ? t('Blocked') : '') + ((intval($rr['abook_blocked'])) ? t('Blocked') : ''), + ((intval($rr['abook_not_here'])) ? t('Not connected at this location') : '') ); foreach($status as $str) { @@ -257,11 +257,12 @@ class Connections extends \Zotlabs\Web\Controller { $contacts[] = array( 'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']), 'edit_hover' => t('Edit connection'), + 'edit' => t('Edit'), 'delete_hover' => t('Delete connection'), 'id' => $rr['abook_id'], 'thumb' => $rr['xchan_photo_m'], 'name' => $rr['xchan_name'], - 'classes' => (intval($rr['abook_archived']) ? 'archived' : ''), + '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', 'delete' => t('Delete'), diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 484e69b52..d301c2d45 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -842,6 +842,22 @@ class Connedit extends \Zotlabs\Web\Controller { } else $locstr = t('none'); + + $clone_warn = ''; + $clonable = (in_array($contact['xchan_network'],['zot','rss']) ? true : false); + if(! $clonable) { + $clone_warn = '<strong>'; + $clone_warn .= ((intval($contact['abook_not_here'])) + ? t('This connection is unreachable from this location.') + : t('This connection may be unreachable from other channel locations.') + ); + $clone_warn .= '</strong><br>' . t('Location independence is not supported by their network.'); + } + + + + if(intval($contact['abook_not_here']) && $unclonable) + $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'])), @@ -856,6 +872,7 @@ class Connedit extends \Zotlabs\Web\Controller { '$addr_text' => t('This connection\'s primary address is'), '$loc_text' => t('Available locations:'), '$locstr' => $locstr, + '$unclonable' => $clone_warn, '$notself' => (($self) ? '' : '1'), '$self' => (($self) ? '1' : ''), '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php index edcf43cd6..6268e99c6 100644 --- a/Zotlabs/Module/Directory.php +++ b/Zotlabs/Module/Directory.php @@ -77,7 +77,7 @@ class Directory extends \Zotlabs\Web\Controller { $pubforums = get_directory_setting($observer, 'pubforums'); $o = ''; - nav_set_selected('directory'); + nav_set_selected(t('Directory')); if(x($_POST,'search')) $search = notags(trim($_POST['search'])); @@ -233,7 +233,7 @@ class Directory extends \Zotlabs\Web\Controller { $age = ''; if(strlen($rr['birthday'])) { - if(($years = age($rr['birthday'],'UTC','')) != 0) + if(($years = age($rr['birthday'],'UTC','')) > 0) $age = $years; } diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index 815672091..df3cb1e2b 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -308,12 +308,12 @@ class Display extends \Zotlabs\Web\Controller { if ($checkjs->disabled()) { - $o .= conversation($a, $items, 'display', $update, 'traditional'); + $o .= conversation($items, 'display', $update, 'traditional'); if ($items[0]['title']) \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title']; } else { - $o .= conversation($a, $items, 'display', $update, 'client'); + $o .= conversation($items, 'display', $update, 'client'); } if($updateable) { diff --git a/Zotlabs/Module/Editpost.php b/Zotlabs/Module/Editpost.php index 629bdd3fd..a54c42e7f 100644 --- a/Zotlabs/Module/Editpost.php +++ b/Zotlabs/Module/Editpost.php @@ -39,6 +39,11 @@ class Editpost extends \Zotlabs\Web\Controller { return; } + if($itm[0]['resource_type'] === 'photo' && $itm[0]['resource_id']) { + notice( t('Item is not editable') . EOL); + return; + } + if($itm[0]['resource_type'] === 'event' && $itm[0]['resource_id']) { goaway(z_root() . '/events/' . $itm[0]['resource_id'] . '?expandform=1'); } diff --git a/Zotlabs/Module/Editwebpage.php b/Zotlabs/Module/Editwebpage.php index db33cd1db..da536a729 100644 --- a/Zotlabs/Module/Editwebpage.php +++ b/Zotlabs/Module/Editwebpage.php @@ -112,7 +112,7 @@ class Editwebpage extends \Zotlabs\Web\Controller { intval($itm[0]['id']) ); if($item_id) - $page_title = $item_id[0]['v']; + $page_title = urldecode($item_id[0]['v']); $mimetype = $itm[0]['mimetype']; diff --git a/Zotlabs/Module/Events.php b/Zotlabs/Module/Events.php index edc6dd3f0..0541f5e9b 100644 --- a/Zotlabs/Module/Events.php +++ b/Zotlabs/Module/Events.php @@ -272,7 +272,7 @@ class Events extends \Zotlabs\Web\Controller { return; } - nav_set_selected('all_events'); + nav_set_selected(t('Events')); if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) { $r = q("update event set dismissed = 1 where id = %d and uid = %d", diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php index 785dff394..d6f363e77 100644 --- a/Zotlabs/Module/Filestorage.php +++ b/Zotlabs/Module/Filestorage.php @@ -5,14 +5,6 @@ namespace Zotlabs\Module; * */ -require_once('include/attach.php'); - - -/** - * - * @param object &$a - */ - class Filestorage extends \Zotlabs\Web\Controller { function post() { @@ -36,7 +28,7 @@ class Filestorage extends \Zotlabs\Web\Controller { $channel = \App::get_channel(); $acl = new \Zotlabs\Access\AccessList($channel); - $acl->set_from_array($_REQUEST); + $acl->set_from_array($_POST); $x = $acl->get(); $cloudPath = get_parent_cloudpath($channel_id, $channel['channel_address'], $resource); diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php index 3d859d94b..0b05d78a4 100644 --- a/Zotlabs/Module/Getfile.php +++ b/Zotlabs/Module/Getfile.php @@ -35,6 +35,7 @@ class Getfile extends \Zotlabs\Web\Controller { $sig = $_POST['signature']; $resource = $_POST['resource']; $revision = intval($_POST['revision']); + $resolution = (-1); if(! $hash) killme(); @@ -46,6 +47,11 @@ class Getfile extends \Zotlabs\Web\Controller { killme(); } + if(substr($resource,-2,1) == '-') { + $resolution = intval(substr($resource,-1,1)); + $resource = substr($resource,0,-2); + } + $slop = intval(get_pconfig($channel['channel_id'],'system','getfile_time_slop')); if($slop < 1) $slop = 3; @@ -63,6 +69,35 @@ class Getfile extends \Zotlabs\Web\Controller { killme(); } + + if($resolution > 0) { + $r = q("select * from photo where resource_id = '%s' and uid = %d limit 1", + dbesc($resource), + intval($channel['channel_id']) + ); + if($r) { + header('Content-type: ' . $r[0]['mimetype']); + + if(intval($r[0]['os_storage'])) { + $fname = dbunescbin($r[0]['content']); + if(strpos($fname,'store') !== false) + $istream = fopen($fname,'rb'); + else + $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname,'rb'); + $ostream = fopen('php://output','wb'); + if($istream && $ostream) { + pipe_streams($istream,$ostream); + fclose($istream); + fclose($ostream); + } + } + else { + echo dbunescbin($r[0]['content']); + } + } + killme(); + } + $r = attach_by_hash($resource,$channel['channel_hash'],$revision); if(! $r['success']) { diff --git a/Zotlabs/Module/Group.php b/Zotlabs/Module/Group.php index 646310356..93a089d02 100644 --- a/Zotlabs/Module/Group.php +++ b/Zotlabs/Module/Group.php @@ -56,6 +56,7 @@ class Group extends \Zotlabs\Web\Controller { ); if($r) info( t('Privacy group updated.') . EOL ); + build_sync_packet(local_channel(),null,true); } goaway(z_root() . '/group/' . argv(1) . '/' . argv(2)); @@ -63,7 +64,8 @@ class Group extends \Zotlabs\Web\Controller { return; } - function get() { + function get() { + $change = false; logger('mod_group: ' . \App::$cmd,LOGGER_DEBUG); diff --git a/Zotlabs/Module/Hcard.php b/Zotlabs/Module/Hcard.php index 13097939e..912c84fd2 100644 --- a/Zotlabs/Module/Hcard.php +++ b/Zotlabs/Module/Hcard.php @@ -14,6 +14,8 @@ class Hcard extends \Zotlabs\Web\Controller { return; } + logger('hcard_request: ' . $which, LOGGER_DEBUG); + $profile = ''; $channel = \App::get_channel(); diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php index e247416d9..e98cb9d4d 100644 --- a/Zotlabs/Module/Help.php +++ b/Zotlabs/Module/Help.php @@ -15,7 +15,7 @@ require_once('include/help.php'); class Help extends \Zotlabs\Web\Controller { function get() { - nav_set_selected('help'); + nav_set_selected(t('Help')); if($_REQUEST['search']) { $o .= '<div id="help-content" class="generic-content-wrapper">'; @@ -44,42 +44,42 @@ class Help extends \Zotlabs\Web\Controller { return $o; } - - - if(argc() > 2 && argv(argc()-2) === 'assets') { - $path = ''; - for($x = 1; $x < argc(); $x ++) { - if(strlen($path)) - $path .= '/'; - $path .= argv($x); - } - $realpath = 'doc/' . $path; - //Set the content-type header as appropriate - $imageInfo = getimagesize($realpath); - switch ($imageInfo[2]) { - case IMAGETYPE_JPEG: - header("Content-Type: image/jpeg"); - break; - case IMAGETYPE_GIF: - header("Content-Type: image/gif"); - break; - case IMAGETYPE_PNG: - header("Content-Type: image/png"); - break; - default: - break; - } - header("Content-Length: " . filesize($realpath)); + + + if(argc() > 2 && argv(argc()-2) === 'assets') { + $path = ''; + for($x = 1; $x < argc(); $x ++) { + if(strlen($path)) + $path .= '/'; + $path .= argv($x); + } + $realpath = 'doc/' . $path; + //Set the content-type header as appropriate + $imageInfo = getimagesize($realpath); + switch ($imageInfo[2]) { + case IMAGETYPE_JPEG: + header("Content-Type: image/jpeg"); + break; + case IMAGETYPE_GIF: + header("Content-Type: image/gif"); + break; + case IMAGETYPE_PNG: + header("Content-Type: image/png"); + break; + default: + break; + } + header("Content-Length: " . filesize($realpath)); - // dump the picture and stop the script - readfile($realpath); - killme(); - } + // dump the picture and stop the script + readfile($realpath); + killme(); + } $headings = [ - 'about' => t('About'), - 'member' => t('Members'), - 'admin' => t('Administrators'), + 'about' => t('About'), + 'member' => t('Members'), + 'admin' => t('Administrators'), 'developer' => t('Developers'), 'tutorials' => t('Tutorials') ]; @@ -87,13 +87,13 @@ class Help extends \Zotlabs\Web\Controller { if(array_key_exists(argv(1), $headings)) $heading = $headings[argv(1)]; - $content = get_help_content(); + $content = get_help_content(); return replace_macros(get_markup_template('help.tpl'), array( - '$title' => t('$Projectname Documentation'), + '$title' => t('$Projectname Documentation'), '$tocHeading' => t('Contents'), - '$content' => $content, - '$heading' => $heading + '$content' => $content, + '$heading' => $heading )); } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index ce3fd469a..40ce8f6d1 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -121,8 +121,7 @@ class Import extends \Zotlabs\Web\Controller { $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); notice($t); } - if(array_key_exists('server_role',$data['compatibility']) && $data['compatibility']['server_role'] == 'basic') - $moving = true; + } if($moving) @@ -333,6 +332,10 @@ class Import extends \Zotlabs\Web\Controller { $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100 ) ? 1 : 0); } + if(array_key_exists('abook_instance',$abook) && $abook['abook_instance'] && strpos($abook['abook_instance'],z_root()) === false) { + $abook['abook_not_here'] = 1; + } + if($abook['abook_self']) { $role = get_pconfig($channel['channel_id'],'system','permissions_role'); if(($role === 'forum') || ($abook['abook_my_perms'] & PERMS_W_TAGWALL)) { diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php index 6b6f80a31..bbd98150d 100644 --- a/Zotlabs/Module/Invite.php +++ b/Zotlabs/Module/Invite.php @@ -49,7 +49,7 @@ class Invite extends \Zotlabs\Web\Controller { if(! $recip) continue; - if(! valid_email($recip)) { + if(! validate_email($recip)) { notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL); continue; } @@ -88,12 +88,14 @@ class Invite extends \Zotlabs\Web\Controller { } - function get() { + function get() { if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } + + nav_set_selected(t('Invite')); $tpl = get_markup_template('invite.tpl'); $invonly = false; diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index ec36c22d8..5e7a3fbc0 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -33,7 +33,7 @@ class Item extends \Zotlabs\Web\Controller { // 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,'commenter'))) + if((! local_channel()) && (! remote_channel()) && (! x($_REQUEST,'anonname'))) return; $uid = local_channel(); @@ -77,7 +77,7 @@ class Item extends \Zotlabs\Web\Controller { call_hooks('post_local_start', $_REQUEST); - // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); + // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false); @@ -205,10 +205,29 @@ class Item extends \Zotlabs\Web\Controller { $route = $parent_item['route']; } + + $moderated = false; - if(! $observer) + if(! $observer) { $observer = \App::get_observer(); + if(! $observer) { + $observer = anon_identity_init($_REQUEST); + if($observer) { + $moderated = true; + $remote_xchan = $remote_observer = $observer; + } + } + } + if(! $observer) { + notice( t('Permission denied.') . EOL) ; + if($api_source) + return ( [ 'success' => false, 'message' => 'permission denied' ] ); + if(x($_REQUEST,'return')) + goaway(z_root() . "/" . $return_path ); + killme(); + } + if($parent) { logger('mod_item: item_post parent=' . $parent); $can_comment = false; @@ -312,7 +331,7 @@ class Item extends \Zotlabs\Web\Controller { $walltowall = false; $walltowall_comment = false; - if($remote_xchan) + if($remote_xchan && ! $moderated) $observer = $remote_observer; if($observer) { @@ -615,7 +634,7 @@ class Item extends \Zotlabs\Web\Controller { $attach_link = ''; $hash = substr($mtch,0,strpos($mtch,',')); $rev = intval(substr($mtch,strpos($mtch,','))); - $r = attach_by_hash_nodata($hash,$rev); + $r = attach_by_hash_nodata($hash, $observer['xchan_hash'], $rev); if($r['success']) { $attachments[] = array( 'href' => z_root() . '/attach/' . $r['data']['hash'], @@ -799,7 +818,7 @@ class Item extends \Zotlabs\Web\Controller { $datarray['owner'] = $owner_xchan; $datarray['author'] = $observer; $datarray['attach'] = json_encode($datarray['attach']); - $o = conversation($a,array($datarray),'search',false,'preview'); + $o = conversation(array($datarray),'search',false,'preview'); // logger('preview: ' . $o, LOGGER_DEBUG); echo json_encode(array('preview' => $o)); killme(); @@ -842,8 +861,8 @@ class Item extends \Zotlabs\Web\Controller { } - if(mb_strlen($datarray['title']) > 255) - $datarray['title'] = mb_substr($datarray['title'],0,255); + if(mb_strlen($datarray['title']) > 191) + $datarray['title'] = mb_substr($datarray['title'],0,191); if($webpage) { Zlib\IConfig::Set($datarray,'system', webpage_to_namespace($webpage), @@ -909,6 +928,11 @@ class Item extends \Zotlabs\Web\Controller { if($parent) { + // prevent conversations which you are involved from being expired + + if(local_channel()) + retain_item($parent); + // only send comment notification if this is a wall-to-wall comment, // otherwise it will happen during delivery @@ -996,6 +1020,10 @@ class Item extends \Zotlabs\Web\Controller { \Zotlabs\Daemon\Master::Summon(array('Notifier', $notify_type, $post_id)); logger('post_complete'); + + if($moderated) { + info(t('Your comment is awaiting approval.') . EOL); + } // figure out how to return, depending on from whence we came diff --git a/Zotlabs/Module/Lang.php b/Zotlabs/Module/Lang.php index 69f10fe6d..84776c3ea 100644 --- a/Zotlabs/Module/Lang.php +++ b/Zotlabs/Module/Lang.php @@ -5,6 +5,7 @@ namespace Zotlabs\Module; class Lang extends \Zotlabs\Web\Controller { function get() { + nav_set_selected(t('Language')); return lang_selector(); } diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php index 5ce8ec7f0..c995079ce 100644 --- a/Zotlabs/Module/Like.php +++ b/Zotlabs/Module/Like.php @@ -373,6 +373,10 @@ class Like extends \Zotlabs\Web\Controller { $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink'])); $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + if($objtype === ACTIVITY_OBJ_NOTE && (! intval($item['item_thread_top']))) + $objtype = ACTIVITY_OBJ_COMMENT; + $body = $item['body']; @@ -500,6 +504,11 @@ class Like extends \Zotlabs\Web\Controller { $post = item_store($arr); $post_id = $post['item_id']; + + // save the conversation from expiration + + if(local_channel() && array_key_exists('item',$post) && (intval($post['item']['id']) != intval($post['item']['parent']))) + retain_item($post['item']['parent']); $arr['id'] = $post_id; diff --git a/Zotlabs/Module/Mail.php b/Zotlabs/Module/Mail.php index d605a78a9..e5509961a 100644 --- a/Zotlabs/Module/Mail.php +++ b/Zotlabs/Module/Mail.php @@ -22,32 +22,40 @@ class Mail extends \Zotlabs\Web\Controller { $recipient = ((x($_REQUEST,'messageto')) ? notags(trim($_REQUEST['messageto'])) : ''); $rstr = ((x($_REQUEST,'messagerecip')) ? notags(trim($_REQUEST['messagerecip'])) : ''); $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0); - $expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE); + $expires = ((x($_REQUEST,'expires')) ? datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expires']) : NULL_DATE); + $raw = ((x($_REQUEST,'raw')) ? intval($_REQUEST['raw']) : 0); + $mimetype = ((x($_REQUEST,'mimetype')) ? notags(trim($_REQUEST['mimetype'])) : 'text/bbcode'); if($preview) { - $body = cleanup_bbcode($body); - $results = linkify_tags($a, $body, local_channel()); + if($raw) { + $body = mail_prepare_binary(['id' => 'M0']); + echo json_encode(['preview' => $body]); + } + else { + $body = cleanup_bbcode($body); + $results = linkify_tags($a, $body, local_channel()); - if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { - $attachments = array(); - foreach($match[2] as $mtch) { - $hash = substr($mtch,0,strpos($mtch,',')); - $rev = intval(substr($mtch,strpos($mtch,','))); - $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev); - if($r['success']) { - $attachments[] = array( - 'href' => z_root() . '/attach/' . $r['data']['hash'], - 'length' => $r['data']['filesize'], - 'type' => $r['data']['filetype'], - 'title' => urlencode($r['data']['filename']), - 'revision' => $r['data']['revision'] - ); + if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { + $attachments = array(); + foreach($match[2] as $mtch) { + $hash = substr($mtch,0,strpos($mtch,',')); + $rev = intval(substr($mtch,strpos($mtch,','))); + $r = attach_by_hash_nodata($hash,get_observer_hash(),$rev); + if($r['success']) { + $attachments[] = array( + 'href' => z_root() . '/attach/' . $r['data']['hash'], + 'length' => $r['data']['filesize'], + 'type' => $r['data']['filetype'], + 'title' => urlencode($r['data']['filename']), + 'revision' => $r['data']['revision'] + ); + } + $body = trim(str_replace($match[1],'',$body)); } - $body = trim(str_replace($match[1],'',$body)); } + echo json_encode(['preview' => zidify_links(smilies(bbcode($body)))]); } - echo json_encode(['preview' => zidify_links(smilies(bbcode($body)))]); killme(); } @@ -102,36 +110,10 @@ class Mail extends \Zotlabs\Web\Controller { } } - // if(feature_enabled(local_channel(),'richtext')) { - // $body = fix_mce_lf($body); - // } - require_once('include/text.php'); linkify_tags($a, $body, local_channel()); - // I don't think this is used any more. - - if($preview) { - $mail = [ - 'mailbox' => 'outbox', - 'id' => 0, - 'mid' => 'M0', - 'from_name' => $channel['xchan_name'], - 'from_url' => $channel['xchan_url'], - 'from_photo' => $channel['xchan_photo_s'], - 'subject' => zidify_links(smilies(bbcode($subject))), - 'body' => zidify_links(smilies(bbcode($body))), - 'attachments' => '', - 'can_recall' => false, - 'is_recalled' => '', - 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c') - ]; - - echo replace_macros(get_markup_template('mail_conv.tpl'), [ '$mail' => $mail ] ); - killme(); - } - if(! $recipient) { notice('No recipient found.'); \App::$argc = 2; @@ -141,7 +123,7 @@ class Mail extends \Zotlabs\Web\Controller { // We have a local_channel, let send_message use the session channel and save a lookup - $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires); + $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires, $mimetype, $raw); if($ret['success']) { xchan_mail_query($ret['mail']); @@ -158,7 +140,7 @@ class Mail extends \Zotlabs\Web\Controller { function get() { $o = ''; - nav_set_selected('messages'); + nav_set_selected(t('Mail')); if(! local_channel()) { notice( t('Permission denied.') . EOL); diff --git a/Zotlabs/Module/Manage.php b/Zotlabs/Module/Manage.php index e541ee077..2d8f39ded 100644 --- a/Zotlabs/Module/Manage.php +++ b/Zotlabs/Module/Manage.php @@ -10,6 +10,8 @@ class Manage extends \Zotlabs\Web\Controller { notice( t('Permission denied.') . EOL); return; } + + nav_set_selected('Manage'); require_once('include/security.php'); diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php new file mode 100644 index 000000000..9af43420d --- /dev/null +++ b/Zotlabs/Module/Moderate.php @@ -0,0 +1,76 @@ +<?php + +namespace Zotlabs\Module; + +require_once('include/conversation.php'); + + +class Moderate extends \Zotlabs\Web\Controller { + + + function get() { + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + + if(argc() > 2) { + $post_id = intval(argv(1)); + if(! $post_id) + goaway(z_root() . '/moderate'); + + $action = argv(2); + + $r = q("select * from item where uid = %d and id = %d and item_blocked = %d limit 1", + intval(local_channel()), + intval($post_id), + intval(ITEM_MODERATED) + ); + + if($r) { + if($action === 'approve') { + q("update item set item_blocked = 0 where uid = %d and id = %d", + intval(local_channel()), + intval($post_id) + ); + notice( t('Comment approved') . EOL); + } + elseif($action === 'drop') { + drop_item($post_id,false); + notice( t('Comment deleted') . EOL); + } + + $r = q("select * from item where id = %d", + intval($post_id) + ); + if($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + build_sync_packet(local_channel(),array('item' => array(encode_item($sync_item[0],true)))); + } + if($action === 'approve') { + \Zotlabs\Daemon\Master::Summon(array('Notifier', 'comment-new', $post_id)); + } + goaway(z_root() . '/moderate'); + } + } + $r = q("select item.id as item_id, item.* from item where item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc limit 60", + intval(local_channel()), + intval(ITEM_MODERATED) + ); + + if($r) { + xchan_query($r); + $items = fetch_post_tags($r,true); + } + else { + $items = array(); + } + + $o = conversation($items,'moderate',false,'traditional'); + return $o; + + } + +}
\ No newline at end of file diff --git a/Zotlabs/Module/Mood.php b/Zotlabs/Module/Mood.php index eeb050040..85c8a3042 100644 --- a/Zotlabs/Module/Mood.php +++ b/Zotlabs/Module/Mood.php @@ -110,17 +110,17 @@ class Mood extends \Zotlabs\Web\Controller { - function get() { + function get() { if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } - + + nav_set_selected(t('Mood')); + $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0'); - - $verbs = get_mood_verbs(); $shortlist = array(); diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 1c7c70019..e5c059af5 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -154,7 +154,7 @@ class Network extends \Zotlabs\Web\Controller { )); } - nav_set_selected('network'); + nav_set_selected(t('Activity')); $channel_acl = array( 'allow_cid' => $channel['channel_allow_cid'], @@ -325,8 +325,8 @@ class Network extends \Zotlabs\Web\Controller { '$xchan' => $xchan, '$order' => $order, '$file' => $file, - '$cats' => $category, - '$tags' => $hashtags, + '$cats' => urlencode($category), + '$tags' => urlencode($hashtags), '$dend' => $datequery, '$mid' => '', '$verb' => $verb, @@ -409,8 +409,9 @@ class Network extends \Zotlabs\Web\Controller { } $abook_uids = " and abook.abook_channel = " . local_channel() . " "; - - if($firehose && (! get_config('system','disable_discover_tab'))) { + + $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false; + if($firehose && (! $disable_discover_tab)) { require_once('include/channel.php'); $sys = get_sys_channel(); $uids = " and item.uid = " . intval($sys['channel_id']) . " "; @@ -551,7 +552,7 @@ class Network extends \Zotlabs\Web\Controller { $mode = (($nouveau) ? 'network-new' : 'network'); - $o .= conversation($a,$items,$mode,$update,$page_mode); + $o .= conversation($items,$mode,$update,$page_mode); if(($items) && (! $update)) $o .= alt_pager($a,count($items)); diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php index 8e6fd1d37..cfd45e909 100644 --- a/Zotlabs/Module/New_channel.php +++ b/Zotlabs/Module/New_channel.php @@ -134,7 +134,7 @@ class New_channel extends \Zotlabs\Web\Controller { $name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'), "*"); $nickhub = '@' . \App::get_hostname(); $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub), "*"); - $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles); + $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/member/member_guide#Account_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles); $o = replace_macros(get_markup_template('new_channel.tpl'), array( '$title' => t('Create Channel'), diff --git a/Zotlabs/Module/Oembed.php b/Zotlabs/Module/Oembed.php index 9394e5942..aee5ea079 100644 --- a/Zotlabs/Module/Oembed.php +++ b/Zotlabs/Module/Oembed.php @@ -22,7 +22,7 @@ class Oembed extends \Zotlabs\Web\Controller { } else { - echo "<html><head><base target=\"_blank\" /></head><body>"; + echo "<html><head><base target=\"_blank\" rel=\"nofollow noopener\" /></head><body>"; $src = base64url_decode(argv(1)); $j = oembed_fetch_url($src); echo $j['html']; diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php index dc0547a42..9c05f5e3f 100644 --- a/Zotlabs/Module/Oep.php +++ b/Zotlabs/Module/Oep.php @@ -108,7 +108,7 @@ class Oep extends \Zotlabs\Web\Controller { $ret['type'] = 'rich'; $w = (($maxwidth) ? $maxwidth : 640); - $h = (($maxheight) ? $maxheight : $w * 2 / 3); + $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); $ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>'; @@ -167,7 +167,7 @@ class Oep extends \Zotlabs\Web\Controller { $ret['type'] = 'rich'; $w = (($maxwidth) ? $maxwidth : 640); - $h = (($maxheight) ? $maxheight : $w * 2 / 3); + $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); $ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>'; diff --git a/Zotlabs/Module/Page.php b/Zotlabs/Module/Page.php index 6ef285dd0..c142afe77 100644 --- a/Zotlabs/Module/Page.php +++ b/Zotlabs/Module/Page.php @@ -3,7 +3,6 @@ namespace Zotlabs\Module; require_once('include/items.php'); require_once('include/conversation.php'); -require_once('include/page_widgets.php'); class Page extends \Zotlabs\Web\Controller { @@ -43,11 +42,31 @@ class Page extends \Zotlabs\Web\Controller { $channel_address = argv(1); + // Always look first for the page name prefixed by the observer language; for instance page/nickname/de/foo + // followed by page/nickname/foo if that is not found. + // If your browser language is de and you want to access the default in this case, + // use page/nickname/-/foo to over-ride the language and access only the page with pagelink of 'foo' + + $page_name = ''; + $ignore_language = false; + + for($x = 2; $x < argc(); $x ++) { + if($page_name === '' && argv($x) === '-') { + $ignore_language = true; + continue; + } + if($page_name) + $page_name .= '/'; + $page_name .= argv($x); + } + + // The page link title was stored in a urlencoded format // php or the browser may/will have decoded it, so re-encode it for our search - $page_id = urlencode(argv(2)); - + $page_id = urlencode($page_name); + $lang_page_id = urlencode(\App::$language . '/' . $page_name); + $u = q("select channel_id from channel where channel_address = '%s' limit 1", dbesc($channel_address) ); @@ -64,16 +83,31 @@ class Page extends \Zotlabs\Web\Controller { require_once('include/security.php'); $sql_options = item_permissions_sql($u[0]['channel_id']); - - $r = q("select item.* from item left join iconfig on item.id = iconfig.iid - where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0 - and (( iconfig.k = 'WEBPAGE' and item_type = %d ) - OR ( iconfig.k = 'PDL' AND item_type = %d )) $sql_options $revision limit 1", - intval($u[0]['channel_id']), - dbesc($page_id), - intval(ITEM_TYPE_WEBPAGE), - intval(ITEM_TYPE_PDL) - ); + + $r = null; + + if(! $ignore_language) { + $r = q("select item.* from item left join iconfig on item.id = iconfig.iid + where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0 + and (( iconfig.k = 'WEBPAGE' and item_type = %d ) + OR ( iconfig.k = 'PDL' AND item_type = %d )) $sql_options $revision limit 1", + intval($u[0]['channel_id']), + dbesc($lang_page_id), + intval(ITEM_TYPE_WEBPAGE), + intval(ITEM_TYPE_PDL) + ); + } + if(! $r) { + $r = q("select item.* from item left join iconfig on item.id = iconfig.iid + where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0 + and (( iconfig.k = 'WEBPAGE' and item_type = %d ) + OR ( iconfig.k = 'PDL' AND item_type = %d )) $sql_options $revision limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_TYPE_WEBPAGE), + intval(ITEM_TYPE_PDL) + ); + } if(! $r) { // Check again with no permissions clause to see if it is a permissions issue diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php index dc4ae670e..8a110f925 100644 --- a/Zotlabs/Module/Photo.php +++ b/Zotlabs/Module/Photo.php @@ -154,7 +154,9 @@ class Photo extends \Zotlabs\Web\Controller { intval($resolution) ); - if($r && $r[0]['photo_usage'] == PHOTO_COVER) + // viewing cover photos is allowed unless a plugin chooses to block it. + + if($r && intval($r[0]['photo_usage']) === PHOTO_COVER && $resolution >= PHOTO_RES_COVER_1200) $allowed = 1; $d = [ 'imgscale' => $resolution, 'resource_id' => $photo, 'photo' => $r, 'allowed' => $allowed ]; diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php index 18d7abc48..0f80f46a5 100644 --- a/Zotlabs/Module/Photos.php +++ b/Zotlabs/Module/Photos.php @@ -554,6 +554,8 @@ class Photos extends \Zotlabs\Web\Controller { $sql_item = item_permissions_sql($owner_uid,get_observer_hash()); $sql_extra = permissions_sql($owner_uid,get_observer_hash(),'photo'); $sql_attach = permissions_sql($owner_uid,get_observer_hash(),'attach'); + + nav_set_selected(t('Photos')); $o = ""; diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php index cf8d83023..0bd1187c7 100644 --- a/Zotlabs/Module/Poke.php +++ b/Zotlabs/Module/Poke.php @@ -41,7 +41,10 @@ class Poke extends \Zotlabs\Web\Controller { $activity = ACTIVITY_POKE . '#' . urlencode($verbs[$verb][0]); $contact_id = intval($_REQUEST['cid']); - if(! $contact_id) + + $xchan = trim($_REQUEST['xchan']); + + if(! ($contact_id || $xchan)) return; $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0); @@ -49,13 +52,20 @@ class Poke extends \Zotlabs\Web\Controller { logger('poke: verb ' . $verb . ' contact ' . $contact_id, LOGGER_DEBUG); - $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1", - intval($contact_id), - intval($uid) - ); - + if($contact_id) { + $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1", + intval($contact_id), + intval($uid) + ); + } + if($xchan) { + $r = q("SELECT * FROM xchan where xchan_hash like ( '%s' ) LIMIT 1", + dbesc($xchan . '%') + ); + } + if(! $r) { - logger('poke: no target ' . $contact_id); + logger('poke: no target.'); return; } @@ -79,7 +89,7 @@ class Poke extends \Zotlabs\Web\Controller { $deny_gid = $r[0]['deny_gid']; } } - else { + elseif($contact_id) { $item_private = ((x($_GET,'private')) ? intval($_GET['private']) : 0); @@ -92,9 +102,11 @@ class Poke extends \Zotlabs\Web\Controller { $arr = array(); + + $arr['item_wall'] = 1; $arr['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $channel['channel_hash']); - $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); + $arr['parent_mid'] = (($parent_mid) ? $parent_mid : ''); $arr['title'] = ''; $arr['allow_cid'] = $allow_cid; $arr['allow_gid'] = $allow_gid; @@ -131,12 +143,14 @@ class Poke extends \Zotlabs\Web\Controller { - function get() { + function get() { if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } + + nav_set_selected(t('Poke')); $name = ''; $id = ''; diff --git a/Zotlabs/Module/Probe.php b/Zotlabs/Module/Probe.php index 7fc0e8ff5..859bed315 100644 --- a/Zotlabs/Module/Probe.php +++ b/Zotlabs/Module/Probe.php @@ -7,7 +7,9 @@ require_once('include/zot.php'); class Probe extends \Zotlabs\Web\Controller { function get() { - + + nav_set_selected(t('Remote Diagnostics')); + $o .= '<h3>Probe Diagnostic</h3>'; $o .= '<form action="probe" method="get">'; diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php index ab349b05d..6930d50ca 100644 --- a/Zotlabs/Module/Profile.php +++ b/Zotlabs/Module/Profile.php @@ -21,6 +21,8 @@ class Profile extends \Zotlabs\Web\Controller { \App::$error = 404; return; } + + nav_set_selected('Profile'); $profile = ''; $channel = \App::get_channel(); diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php index e8f0e5186..47b627015 100644 --- a/Zotlabs/Module/Profile_photo.php +++ b/Zotlabs/Module/Profile_photo.php @@ -190,7 +190,7 @@ class Profile_photo extends \Zotlabs\Web\Controller { build_sync_packet($channel['channel_id'],array('file' => array($sync))); - // Similarly, tell the nav bar to bypass the cache and update the avater image. + // Similarly, tell the nav bar to bypass the cache and update the avatar image. $_SESSION['reload_avatar'] = true; info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php index f6e8b11ed..b1cf9596c 100644 --- a/Zotlabs/Module/Profiles.php +++ b/Zotlabs/Module/Profiles.php @@ -9,7 +9,7 @@ class Profiles extends \Zotlabs\Web\Controller { function init() { - nav_set_selected('profiles'); + nav_set_selected('Profiles'); if(! local_channel()) { return; diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 46210abb1..42aa2b51b 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -16,8 +16,8 @@ class Pubstream extends \Zotlabs\Web\Controller { return login(); } - - if(get_config('system','disable_discover_tab')) + $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false; + if($disable_discover_tab) return; $item_normal = item_normal(); @@ -167,7 +167,7 @@ class Pubstream extends \Zotlabs\Web\Controller { // fake it $mode = ('network'); - $o .= conversation($a,$items,$mode,$update,$page_mode); + $o .= conversation($items,$mode,$update,$page_mode); if(($items) && (! $update)) $o .= alt_pager($a,count($items)); diff --git a/Zotlabs/Module/Randprof.php b/Zotlabs/Module/Randprof.php index dc2e925fe..94ec095cb 100644 --- a/Zotlabs/Module/Randprof.php +++ b/Zotlabs/Module/Randprof.php @@ -8,7 +8,7 @@ class Randprof extends \Zotlabs\Web\Controller { function init() { $x = random_profile(); if($x) - goaway(chanlink_url($x)); + goaway(chanlink_hash($x)); /** FIXME this doesn't work at the moment as a fallback */ goaway(z_root() . '/profile'); diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php index ed4f87e7e..6cd79c952 100644 --- a/Zotlabs/Module/React.php +++ b/Zotlabs/Module/React.php @@ -39,6 +39,10 @@ class React extends \Zotlabs\Web\Controller { $n['author_xchan'] = $channel['channel_hash']; $x = item_store($n); + + if(local_channel()) + retain_item($postid); + if($x['success']) { $nid = $x['item_id']; \Zotlabs\Daemon\Master::Summon(array('Notifier','like',$nid)); diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php index 1d8944d8e..d4573156c 100644 --- a/Zotlabs/Module/Register.php +++ b/Zotlabs/Module/Register.php @@ -151,7 +151,7 @@ class Register extends \Zotlabs\Web\Controller { $new_channel = false; $next_page = 'new_channel'; - if(get_config('system','auto_channel_create') || get_config('system','server_role') == 'basic') { + if(get_config('system','auto_channel_create')) { $new_channel = auto_channel_create($result['account']['account_id']); if($new_channel['success']) { $channel_id = $new_channel['channel']['channel_id']; @@ -237,14 +237,12 @@ class Register extends \Zotlabs\Web\Controller { $name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"')); $nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl')); $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub)); - $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles); + $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' <a href="help/member/member_guide#Account_Permission_Roles" target="_blank">' . t('Read more about roles') . '</a>',$perm_roles); $tos = array('tos', $label_tos, '', '', array(t('no'),t('yes'))); - $server_role = get_config('system','server_role'); - - $auto_create = (($server_role == 'basic') || (get_config('system','auto_channel_create')) ? true : false); - $default_role = (($server_role == 'basic') ? 'social' : get_config('system','default_permissions_role')); + $auto_create = (get_config('system','auto_channel_create') ? true : false); + $default_role = get_config('system','default_permissions_role'); require_once('include/bbcode.php'); diff --git a/Zotlabs/Module/Rpost.php b/Zotlabs/Module/Rpost.php index 1349cd1c5..731eab82e 100644 --- a/Zotlabs/Module/Rpost.php +++ b/Zotlabs/Module/Rpost.php @@ -59,6 +59,8 @@ class Rpost extends \Zotlabs\Web\Controller { } return login(); } + + nav_set_selected(t('Post')); // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php index aacdc88e7..e1d35b879 100644 --- a/Zotlabs/Module/Search.php +++ b/Zotlabs/Module/Search.php @@ -15,14 +15,14 @@ class Search extends \Zotlabs\Web\Controller { if((get_config('system','block_public')) || (get_config('system','block_public_search'))) { if ((! local_channel()) && (! remote_channel())) { notice( t('Public access denied.') . EOL); - return; + return; } } if($load) $_SESSION['loadtime'] = datetime_convert(); - nav_set_selected('search'); + nav_set_selected(t('Search')); require_once("include/bbcode.php"); require_once('include/security.php'); @@ -81,11 +81,12 @@ class Search extends \Zotlabs\Web\Controller { return $o; if($tag) { - $sql_extra = sprintf(" AND item.id IN (select oid from term where otype = %d and ttype in ( %d , %d) and term = '%s') ", + $wildtag = str_replace('*','%',$search); + $sql_extra = sprintf(" AND item.id IN (select oid from term where otype = %d and ttype in ( %d , %d) and term like '%s') ", intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval(TERM_COMMUNITYTAG), - dbesc(protect_sprintf($search)) + dbesc(protect_sprintf($wildtag)) ); } else { @@ -144,7 +145,7 @@ class Search extends \Zotlabs\Web\Controller { } - $item_normal = item_normal(); + $item_normal = item_normal_search(); $pub_sql = public_permissions_sql($observer_hash); require_once('include/channel.php'); @@ -225,7 +226,7 @@ class Search extends \Zotlabs\Web\Controller { else $o .= '<h2>' . sprintf( t('Search results for: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '</h2>'; - $o .= conversation($a,$items,'search',$update,'client'); + $o .= conversation($items,'search',$update,'client'); $o .= '</div>'; diff --git a/Zotlabs/Module/Settings.php b/Zotlabs/Module/Settings.php index 76794e21c..79031c98f 100644 --- a/Zotlabs/Module/Settings.php +++ b/Zotlabs/Module/Settings.php @@ -53,7 +53,7 @@ class Settings extends \Zotlabs\Web\Controller { function get() { - nav_set_selected('settings'); + nav_set_selected('Settings'); if((! local_channel()) || ($_SESSION['delegate'])) { notice( t('Permission denied.') . EOL ); diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php index ec176797d..18890e89f 100644 --- a/Zotlabs/Module/Settings/Account.php +++ b/Zotlabs/Module/Settings/Account.php @@ -16,7 +16,7 @@ class Account { $account = \App::get_account(); if($email != $account['account_email']) { - if(! valid_email($email)) + if(! validate_email($email)) $errs[] = t('Not valid email.'); $adm = trim(get_config('system','admin_email')); if(($adm) && (strcasecmp($email,$adm) == 0)) { diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index 56a7d0d8e..3e6adcf8d 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -324,7 +324,7 @@ class Channel { foreach($global_perms as $k => $perm) { $options = array(); foreach($perm_opts as $opt) { - if((! strstr($k,'view')) && $opt[1] == PERMS_PUBLIC) + if(((! strstr($k,'view')) && $k !== 'post_comments') && $opt[1] == PERMS_PUBLIC) continue; $options[$opt[1]] = $opt[0]; } @@ -489,7 +489,6 @@ class Channel { '$h_prv' => t('Security and Privacy Settings'), '$permissions_set' => $permissions_set, - '$server_role' => \Zotlabs\Lib\System::get_server_role(), '$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), diff --git a/Zotlabs/Module/Settings/Featured.php b/Zotlabs/Module/Settings/Featured.php index 4885abd1d..ebe2996d3 100644 --- a/Zotlabs/Module/Settings/Featured.php +++ b/Zotlabs/Module/Settings/Featured.php @@ -10,14 +10,16 @@ class Featured { call_hooks('feature_settings_post', $_POST); - if(intval($_POST['affinity_cmax'])) { - set_pconfig(local_channel(),'affinity','cmax',intval($_POST['affinity_cmax'])); - } - if(intval($_POST['affinity_cmin'])) { - set_pconfig(local_channel(),'affinity','cmin',intval($_POST['affinity_cmin'])); - } - if(intval($_POST['affinity_cmax']) || intval($_POST['affinity_cmin'])) { - info( t('Affinity Slider settings updated.') . EOL); + if($_POST['affinity_slider-submit']) { + if(intval($_POST['affinity_cmax'])) { + set_pconfig(local_channel(),'affinity','cmax',intval($_POST['affinity_cmax'])); + } + if(intval($_POST['affinity_cmin'])) { + set_pconfig(local_channel(),'affinity','cmin',intval($_POST['affinity_cmin'])); + } + if(intval($_POST['affinity_cmax']) || intval($_POST['affinity_cmin'])) { + info( t('Affinity Slider settings updated.') . EOL); + } } build_sync_packet(); diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php index d4c31fd4e..2134288d6 100644 --- a/Zotlabs/Module/Setup.php +++ b/Zotlabs/Module/Setup.php @@ -73,9 +73,6 @@ class Setup extends \Zotlabs\Web\Controller { $phpath = trim($_POST['phpath']); $adminmail = trim($_POST['adminmail']); $siteurl = trim($_POST['siteurl']); - $server_role = trim($_POST['server_role']); - if(! $server_role) - $server_role = 'standard'; // $siteurl should not have a trailing slash @@ -103,9 +100,6 @@ class Setup extends \Zotlabs\Web\Controller { $timezone = trim($_POST['timezone']); $adminmail = trim($_POST['adminmail']); $siteurl = trim($_POST['siteurl']); - $server_role = trim($_POST['server_role']); - if(! $server_role) - $server_role = 'standard'; if($siteurl != z_root()) { $test = z_fetch_url($siteurl."/setup/testrewrite"); @@ -134,7 +128,7 @@ class Setup extends \Zotlabs\Web\Controller { '$dbpass' => $dbpass, '$dbdata' => $dbdata, '$dbtype' => $dbtype, - '$server_role' => $server_role, + '$server_role' => 'pro', '$timezone' => $timezone, '$siteurl' => $siteurl, '$site_id' => random_string(), @@ -192,14 +186,17 @@ class Setup extends \Zotlabs\Web\Controller { } $db_return_text = ''; if(x(\App::$data, 'db_installed')) { - $txt = '<p style="font-size: 130%;">'; - $txt .= t('Your site database has been installed.') . EOL; + $pass = 'Installation succeeded!'; + $icon = 'check'; + $txt = t('Your site database has been installed.') . EOL; $db_return_text .= $txt; } if(x(\App::$data, 'db_failed')) { + $pass = 'Database install failed!'; + $icon = 'exclamation-triangle'; $txt = t('You may need to import the file "install/schema_xxx.sql" manually using a database client.') . EOL; $txt .= t('Please see the file "install/INSTALL.txt".') . EOL ."<hr>" ; - $txt .= "<pre>".\App::$data['db_failed'] . "</pre>". EOL ; + $txt .= "<pre>" . \App::$data['db_failed'] . "</pre>". EOL ; $db_return_text .= $txt; } if(\DBA::$dba && \DBA::$dba->connected) { @@ -223,8 +220,10 @@ class Setup extends \Zotlabs\Web\Controller { $tpl = get_markup_template('install.tpl'); return replace_macros($tpl, array( '$title' => $install_title, - '$pass' => '', - '$text' => $db_return_text . $this->what_next(), + '$icon' => $icon, + '$pass' => $pass, + '$text' => $db_return_text, + '$what_next' => $this->what_next() )); } @@ -324,11 +323,6 @@ class Setup extends \Zotlabs\Web\Controller { $siteurl = trim($_POST['siteurl']); $timezone = ((x($_POST,'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles'); - $server_roles = [ - 'basic' => t('Basic/Minimal Social Networking'), - 'standard' => t('Standard Configuration (default)'), - 'pro' => t('Professional') - ]; $tpl = get_markup_template('install_settings.tpl'); $o .= replace_macros($tpl, array( @@ -348,8 +342,6 @@ class Setup extends \Zotlabs\Web\Controller { '$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Please use SSL (https) URL if available.')), - '$server_role' => array('server_role', t("Server Configuration/Role"), 'standard','',$server_roles), - '$timezone' => array('timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones()), '$baseurl' => z_root(), @@ -408,7 +400,7 @@ class Setup extends \Zotlabs\Web\Controller { if(!$passed) { $help .= t('Could not find a command line version of PHP in the web server PATH.'). EOL; $help .= t('If you don\'t have a command line version of PHP installed on server, you will not be able to run background polling via cron.') . EOL; - $help .= EOL . EOL ; + $help .= EOL; $tpl = get_markup_template('field_input.tpl'); $help .= replace_macros($tpl, array( '$field' => array('phpath', t('PHP executable path'), $phpath, t('Enter full path to php executable. You can leave this blank to continue the installation.')), @@ -456,7 +448,7 @@ class Setup extends \Zotlabs\Web\Controller { userReadableSize($result['max_upload_filesize']), $result['max_file_uploads'] ); - $help .= '<br>' . t('You can adjust these settings in the server php.ini file.'); + $help .= '<br><br>' . t('You can adjust these settings in the server php.ini file.'); $this->check_add($checks, t('PHP upload limits'), true, false, $help); } @@ -748,12 +740,12 @@ class Setup extends \Zotlabs\Web\Controller { $baseurl = z_root(); return - t('<h1>What next</h1>') - ."<p>".t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.') + t('<h1>What next?</h1>') + ."<div class=\"alert alert-info\">".t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.').EOL .t('Please see the file "install/INSTALL.txt".') - ."</p><p>" + ."</div><div>" .t("Go to your new hub <a href='$baseurl/register'>registration page</a> and register as new member. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.") - ."</p>"; + ."</div>"; } /** diff --git a/Zotlabs/Module/Share.php b/Zotlabs/Module/Share.php index fcc2486ba..5c4811c59 100644 --- a/Zotlabs/Module/Share.php +++ b/Zotlabs/Module/Share.php @@ -76,7 +76,7 @@ class Share extends \Zotlabs\Web\Controller { $observer = \App::get_observer(); $parsed = $observer['xchan_url']; if($parsed) { - $post_url = $parsed['scheme'] . ':' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') + $post_url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') . '/rpost'; /** diff --git a/Zotlabs/Module/Sharedwithme.php b/Zotlabs/Module/Sharedwithme.php index 5d6d0f7da..2c97e9726 100644 --- a/Zotlabs/Module/Sharedwithme.php +++ b/Zotlabs/Module/Sharedwithme.php @@ -4,6 +4,11 @@ require_once('include/conversation.php'); require_once('include/text.php'); +/** + * @file Zotlabs/Module/Sharedwithme.php + * + */ + class Sharedwithme extends \Zotlabs\Web\Controller { function get() { diff --git a/Zotlabs/Module/Siteinfo.php b/Zotlabs/Module/Siteinfo.php index 7c3918425..fafd51f65 100644 --- a/Zotlabs/Module/Siteinfo.php +++ b/Zotlabs/Module/Siteinfo.php @@ -5,14 +5,13 @@ namespace Zotlabs\Module; class Siteinfo extends \Zotlabs\Web\Controller { function init() { - if (argv(1) === 'json') { +logger(print_r($_REQUEST,true)); + if (argv(1) === 'json' || $_REQUEST['module_format'] === 'json') { $data = get_site_info(); json_return_and_die($data); } } - - - + function get() { $siteinfo = replace_macros(get_markup_template('siteinfo.tpl'), diff --git a/Zotlabs/Module/Siteinfo_json.php b/Zotlabs/Module/Siteinfo_json.php deleted file mode 100644 index 99c22610f..000000000 --- a/Zotlabs/Module/Siteinfo_json.php +++ /dev/null @@ -1,14 +0,0 @@ -<?php -namespace Zotlabs\Module; - - -class Siteinfo_json extends \Zotlabs\Web\Controller { - - function init() { - - $data = get_site_info(); - json_return_and_die($data); - - } - -} diff --git a/Zotlabs/Module/Suggest.php b/Zotlabs/Module/Suggest.php index 2a69145ed..c3f4a6d5a 100644 --- a/Zotlabs/Module/Suggest.php +++ b/Zotlabs/Module/Suggest.php @@ -28,6 +28,8 @@ class Suggest extends \Zotlabs\Web\Controller { notice( t('Permission denied.') . EOL); return; } + + nav_set_selected(t('Suggest Channels')); $_SESSION['return_url'] = z_root() . '/' . \App::$cmd; diff --git a/Zotlabs/Module/Token.php b/Zotlabs/Module/Token.php new file mode 100644 index 000000000..e0d9d74d7 --- /dev/null +++ b/Zotlabs/Module/Token.php @@ -0,0 +1,40 @@ +<?php + +namespace Zotlabs\Module; + + +class Token extends \Zotlabs\Web\Controller { + + + function get() { + + + // workaround for HTTP-auth in CGI mode + if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + if (x($_SERVER, 'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; + if(strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + + + + require_once('include/oauth2.php'); + $oauth2_server->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send(); + + killme(); + } + +}
\ No newline at end of file diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php index c6fe7518e..03d4cb37b 100644 --- a/Zotlabs/Module/Wall_attach.php +++ b/Zotlabs/Module/Wall_attach.php @@ -2,16 +2,25 @@ namespace Zotlabs\Module; require_once('include/attach.php'); -require_once('include/channel.php'); require_once('include/photos.php'); - class Wall_attach extends \Zotlabs\Web\Controller { + function init() { + logger('request_method: ' . $_SERVER['REQUEST_METHOD'],LOGGER_DATA,LOG_INFO); + logger('wall_attach: ' . print_r($_REQUEST,true),LOGGER_DEBUG,LOG_INFO); + logger('wall_attach files: ' . print_r($_FILES,true),LOGGER_DEBUG,LOG_INFO); + // for testing without actually storing anything + // http_status_exit(200,'OK'); + } + + function post() { $using_api = false; - + + $result = []; + if($_REQUEST['api_source'] && array_key_exists('media',$_FILES)) { $using_api = true; } @@ -28,7 +37,46 @@ class Wall_attach extends \Zotlabs\Web\Controller { if(! $channel) killme(); - + + $matches = []; + $partial = false; + + $x = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); + if($x) { + // logger('Content-Range: ' . print_r($matches,true)); + $partial = true; + } + + if($partial) { + $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + if($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($result); + } + else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } + else { + if(! array_key_exists('userfile',$_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + $observer = \App::get_observer(); @@ -51,10 +99,11 @@ class Wall_attach extends \Zotlabs\Web\Controller { if($using_api) return $s; - - echo $s; - killme(); - + + $result['message'] = $s; + json_return_and_die($result); + } + } diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php index 5e3091dfa..e449a790f 100644 --- a/Zotlabs/Module/Webpages.php +++ b/Zotlabs/Module/Webpages.php @@ -34,7 +34,9 @@ class Webpages extends \Zotlabs\Web\Controller { \App::$error = 404; return; } - + + nav_set_selected(t('Webpages')); + $which = argv(1); $_SESSION['return_url'] = \App::$query_string; @@ -179,11 +181,8 @@ class Webpages extends \Zotlabs\Web\Controller { // so just list titles and an edit link. - /** @TODO - this should be replaced with pagelist_widget */ - $sql_extra = item_permissions_sql($owner); - $r = q("select * from iconfig left join item on iconfig.iid = item.id where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc", @@ -191,12 +190,6 @@ class Webpages extends \Zotlabs\Web\Controller { intval(ITEM_TYPE_WEBPAGE) ); -// $r = q("select * from item_id left join item on item_id.iid = item.id -// where item_id.uid = %d and service = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc", -// intval($owner), -// intval(ITEM_TYPE_WEBPAGE) -// ); - if(! $r) $x['pagetitle'] = 'home'; @@ -218,13 +211,15 @@ class Webpages extends \Zotlabs\Web\Controller { 'created' => $rr['created'], 'edited' => $rr['edited'], 'mimetype' => $rr['mimetype'], - 'pagetitle' => $rr['v'], + 'pageurl' => str_replace('%2f','/',$rr['v']), + 'pagetitle' => urldecode($rr['v']), 'mid' => $rr['mid'], 'layout_mid' => $rr['layout_mid'] ); $pages[$rr['iid']][] = array( 'url' => $rr['iid'], - 'pagetitle' => $rr['v'], + 'pageurl' => str_replace('%2f','/',$rr['v']), + 'pagetitle' => urldecode($rr['v']), 'title' => $rr['title'], 'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']), 'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']), diff --git a/Zotlabs/Module/Wfinger.php b/Zotlabs/Module/Wfinger.php index 9623a676b..07a7b7735 100644 --- a/Zotlabs/Module/Wfinger.php +++ b/Zotlabs/Module/Wfinger.php @@ -117,7 +117,7 @@ class Wfinger extends \Zotlabs\Web\Controller { [ 'rel' => 'http://ostatus.org/schema/1.0/subscribe', - 'template' => z_root() . '/follow/url={uri}', + 'template' => z_root() . '/follow?f=&url={uri}', ], [ diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php index f879e221a..4dc11c683 100644 --- a/Zotlabs/Module/Wiki.php +++ b/Zotlabs/Module/Wiki.php @@ -42,7 +42,7 @@ class Wiki extends \Zotlabs\Web\Controller { if(! feature_enabled(\App::$profile_uid,'wiki')) { notice( t('Not found') . EOL); - return; + return; } @@ -76,6 +76,8 @@ class Wiki extends \Zotlabs\Web\Controller { $wiki_owner = true; + nav_set_selected(t('Wiki')); + // Obtain the default permission settings of the channel $owner_acl = array( 'allow_cid' => $owner['channel_allow_cid'], @@ -192,6 +194,7 @@ class Wiki extends \Zotlabs\Web\Controller { goaway(z_root() . '/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/Home'); case 4: + default: // GET /wiki/channel/wiki/page // Fetch the wiki info and determine observer permissions @@ -243,9 +246,15 @@ class Wiki extends \Zotlabs\Web\Controller { $wikiheaderPage = urldecode($pageUrlName); $renamePage = (($wikiheaderPage === 'Home') ? '' : t('Rename page')); + $p = []; - $p = Zlib\NativeWikiPage::get_page_content(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName)); - if(! $p['success']) { + if(! $ignore_language) { + $p = Zlib\NativeWikiPage::get_page_content(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $langPageUrlName)); + } + if(! ($p && $p['success'])) { + $p = Zlib\NativeWikiPage::get_page_content(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName)); + } + if(! ($p && $p['success'])) { notice( t('Error retrieving page content') . EOL); goaway(z_root() . '/' . argv(0) . '/' . argv(1) ); } @@ -267,8 +276,8 @@ class Wiki extends \Zotlabs\Web\Controller { } $showPageControls = $wiki_editor; break; - default: // Strip the extraneous URL components - goaway('/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/' . $pageUrlName); +// default: // Strip the extraneous URL components +// goaway('/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/' . $pageUrlName); } @@ -348,6 +357,7 @@ class Wiki extends \Zotlabs\Web\Controller { $html = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))),$wikiURL); } else { + $bb = Zlib\NativeWikiPage::bbcode($content); $x = new ZLib\MarkdownSoap($bb); $md = $x->clean(); diff --git a/Zotlabs/Module/Xrd.php b/Zotlabs/Module/Xrd.php index 7b36576e0..64e5042cb 100644 --- a/Zotlabs/Module/Xrd.php +++ b/Zotlabs/Module/Xrd.php @@ -9,6 +9,7 @@ class Xrd extends \Zotlabs\Web\Controller { function init() { $uri = urldecode(notags(trim($_GET['uri']))); + $subject = $uri; logger('xrd: ' . $uri,LOGGER_DEBUG); $resource = $uri; @@ -30,13 +31,7 @@ class Xrd extends \Zotlabs\Web\Controller { ); if(! $r) killme(); - - $dspr = replace_macros(get_markup_template('xrd_diaspora.tpl'),array( - '$baseurl' => z_root(), - '$dspr_guid' => $r[0]['channel_guid'] . str_replace('.','',\App::get_hostname()), - '$dspr_key' => base64_encode(pemtorsa($r[0]['channel_pubkey'])) - )); - + $salmon_key = salmon_key($r[0]['channel_pubkey']); header('Access-Control-Allow-Origin: *'); @@ -49,11 +44,11 @@ class Xrd extends \Zotlabs\Web\Controller { if($aliases[$x] === $resource) unset($aliases[$x]); } - - + $o = replace_macros(get_markup_template('xrd_person.tpl'), array( '$nick' => $r[0]['channel_address'], '$accturi' => $resource, + '$subject' => $subject, '$aliases' => $aliases, '$profile_url' => z_root() . '/channel/' . $r[0]['channel_address'], '$hcard_url' => z_root() . '/hcard/' . $r[0]['channel_address'], @@ -61,12 +56,8 @@ class Xrd extends \Zotlabs\Web\Controller { '$zot_post' => z_root() . '/post/' . $r[0]['channel_address'], '$poco_url' => z_root() . '/poco/' . $r[0]['channel_address'], '$photo' => z_root() . '/photo/profile/l/' . $r[0]['channel_id'], - '$dspr' => $dspr, - // '$salmon' => z_root() . '/salmon/' . $r[0]['channel_address'], - // '$salmen' => z_root() . '/salmon/' . $r[0]['channel_address'] . '/mention', '$modexp' => 'data:application/magic-public-key,' . $salmon_key, - '$subscribe' => z_root() . '/follow?url={uri}', - '$bigkey' => salmon_key($r[0]['channel_pubkey']) + '$subscribe' => z_root() . '/follow?f=&url={uri}', )); diff --git a/Zotlabs/Storage/BasicAuth.php b/Zotlabs/Storage/BasicAuth.php index 0ff9fad13..ad2582bb2 100644 --- a/Zotlabs/Storage/BasicAuth.php +++ b/Zotlabs/Storage/BasicAuth.php @@ -188,13 +188,10 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic { protected function check_module_access($channel_id) { if($channel_id && \App::$module === 'cdav') { - $x = get_pconfig($channel_id,'cdav','enabled'); - if(! $x) { - $this->module_disabled = true; - return false; - } + return true; } - return true; + $this->module_disabled = true; + return false; } /** diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php index 7162161ef..3af9fcab1 100644 --- a/Zotlabs/Storage/Browser.php +++ b/Zotlabs/Storage/Browser.php @@ -17,6 +17,7 @@ use Sabre\DAV; */ class Browser extends DAV\Browser\Plugin { + public $build_page = false; /** * @see set_writeable() * @see \\Sabre\\DAV\\Auth\\Backend\\BackendInterface @@ -243,6 +244,8 @@ class Browser extends DAV\Browser\Plugin { $a = false; + nav_set_selected(t('Files')); + \App::$page['content'] = $html; load_pdl(); @@ -257,7 +260,7 @@ class Browser extends DAV\Browser\Plugin { } } $this->server->httpResponse->setHeader('Content-Security-Policy', "script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"); - construct_page(); + $this->build_page = true; } /** diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php index 1475241ab..7a102134f 100644 --- a/Zotlabs/Storage/File.php +++ b/Zotlabs/Storage/File.php @@ -265,7 +265,7 @@ class File extends DAV\Node implements DAV\IFile { $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $x; else $f = $x; - return fopen($f, 'rb'); + return @fopen($f, 'rb'); } return dbunescbin($r[0]['content']); } diff --git a/Zotlabs/Widget/Activity.php b/Zotlabs/Widget/Activity.php index 7264a3360..04e9fc4b1 100644 --- a/Zotlabs/Widget/Activity.php +++ b/Zotlabs/Widget/Activity.php @@ -50,7 +50,7 @@ class Activity { $o .= '<h3>' . t('Activity','widget') . '</h3><ul class="nav nav-pills flex-column">'; foreach($arr as $rv) { - $o .= '<li class="nav-item"><a class="nav-link" href="network?f=&xchan=' . urlencode($rv['author_xchan']) . '" ><span class="badge badge-default float-right">' . ((intval($rv['total'])) ? intval($rv['total']) : '') . '</span><img src="' . $rv['author']['xchan_photo_s'] . '" class="menu-img-1" /> ' . $rv['author']['xchan_name'] . '</a></li>'; + $o .= '<li class="nav-item"><a class="nav-link" href="network?f=&xchan=' . urlencode($rv['author_xchan']) . '" ><span class="badge badge-secondary float-right">' . ((intval($rv['total'])) ? intval($rv['total']) : '') . '</span><img src="' . $rv['author']['xchan_photo_s'] . '" class="menu-img-1" /> ' . $rv['author']['xchan_name'] . '</a></li>'; } $o .= '</ul></div>'; } diff --git a/Zotlabs/Widget/Cdav.php b/Zotlabs/Widget/Cdav.php new file mode 100644 index 000000000..60a860f93 --- /dev/null +++ b/Zotlabs/Widget/Cdav.php @@ -0,0 +1,176 @@ +<?php + +namespace Zotlabs\Widget; + + + +class Cdav { + + function widget() { + if(!local_channel()) + return; + + $channel = \App::get_channel(); + $principalUri = 'principals/' . $channel['channel_address']; + + if(!cdav_principal($principalUri)) + return; + + $pdo = \DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + $o = ''; + + if(argc() == 2 && argv(1) === 'calendar') { + + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + + $sabrecals = $caldavBackend->getCalendarsForUser($principalUri); + + //TODO: we should probably also check for permission to send stream here + $local_channels = q("SELECT * FROM channel LEFT JOIN abook ON abook_xchan = channel_hash WHERE channel_system = 0 AND channel_removed = 0 AND channel_hash != '%s' AND abook_channel = %d", + dbesc($channel['channel_hash']), + intval($channel['channel_id']) + ); + + $sharee_options .= '<option value="">' . t('Select Channel') . '</option>' . "\r\n"; + foreach($local_channels as $local_channel) { + $sharee_options .= '<option value="' . $local_channel['channel_hash'] . '">' . $local_channel['channel_name'] . '</option>' . "\r\n"; + } + + $access_options = '<option value="3">' . t('Read-write') . '</option>' . "\r\n"; + $access_options .= '<option value="2">' . t('Read-only') . '</option>' . "\r\n"; + + //list calendars + foreach($sabrecals as $sabrecal) { + if($sabrecal['share-access'] == 1) + $access = ''; + if($sabrecal['share-access'] == 2) + $access = 'read'; + if($sabrecal['share-access'] == 3) + $access = 'read-write'; + + $invites = $caldavBackend->getInvites($sabrecal['id']); + + $json_source = '/cdav/calendar/json/' . $sabrecal['id'][0] . '/' . $sabrecal['id'][1]; + + $switch = get_pconfig(local_channel(), 'cdav_calendar', $sabrecal['id'][0]); + + $color = (($sabrecal['{http://apple.com/ns/ical/}calendar-color']) ? $sabrecal['{http://apple.com/ns/ical/}calendar-color'] : '#3a87ad'); + + $editable = (($sabrecal['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript + + $sharees = []; + $share_displayname = []; + foreach($invites as $invite) { + if(strpos($invite->href, 'mailto:') !== false) { + $sharee = channelx_by_hash(substr($invite->href, 7)); + $sharees[] = [ + 'name' => $sharee['channel_name'], + 'access' => (($invite->access == 3) ? ' (RW)' : ' (R)'), + 'hash' => $sharee['channel_hash'] + ]; + } + } + + if(!$access) { + $my_calendars[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabrecal['uri'], + 'displayname' => $sabrecal['{DAV:}displayname'], + 'calendarid' => $sabrecal['id'][0], + 'instanceid' => $sabrecal['id'][1], + 'json_source' => $json_source, + 'color' => $color, + 'editable' => $editable, + 'switch' => $switch, + 'sharees' => $sharees + ]; + } + else { + $shared_calendars[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabrecal['uri'], + 'displayname' => $sabrecal['{DAV:}displayname'], + 'calendarid' => $sabrecal['id'][0], + 'instanceid' => $sabrecal['id'][1], + 'json_source' => $json_source, + 'color' => $color, + 'editable' => $editable, + 'switch' => $switch, + 'sharer' => $sabrecal['{urn:ietf:params:xml:ns:caldav}calendar-description'], + 'access' => $access + ]; + } + + if(!$access || $access === 'read-write') { + $writable_calendars[] = [ + 'displayname' => ((!$access) ? $sabrecal['{DAV:}displayname'] : $share_displayname[0]), + 'id' => $sabrecal['id'] + ]; + } + } + + $o .= replace_macros(get_markup_template('cdav_widget_calendar.tpl'), [ + '$my_calendars_label' => t('My Calendars'), + '$my_calendars' => $my_calendars, + '$shared_calendars_label' => t('Shared Calendars'), + '$shared_calendars' => $shared_calendars, + '$sharee_options' => $sharee_options, + '$access_options' => $access_options, + '$share_label' => t('Share this calendar'), + '$share' => t('Share'), + '$edit_label' => t('Calendar name and color'), + '$edit' => t('Edit'), + '$create_label' => t('Create new calendar'), + '$create' => t('Create'), + '$create_placeholder' => t('Calendar Name'), + '$tools_label' => t('Calendar Tools'), + '$import_label' => t('Import calendar'), + '$import_placeholder' => t('Select a calendar to import to'), + '$upload' => t('Upload'), + '$writable_calendars' => $writable_calendars + ]); + + return $o; + + } + + if(argc() >= 2 && argv(1) === 'addressbook') { + + $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); + + $sabreabooks = $carddavBackend->getAddressBooksForUser($principalUri); + + //list addressbooks + foreach($sabreabooks as $sabreabook) { + $addressbooks[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabreabook['uri'], + 'displayname' => $sabreabook['{DAV:}displayname'], + 'id' => $sabreabook['id'] + + ]; + } + + $o .= replace_macros(get_markup_template('cdav_widget_addressbook.tpl'), [ + '$addressbooks_label' => t('Addressbooks'), + '$addressbooks' => $addressbooks, + '$edit_label' => t('Addressbook name'), + '$edit' => t('Edit'), + '$create_label' => t('Create new addressbook'), + '$create_placeholder' => t('Addressbook Name'), + '$create' => t('Create'), + '$tools_label' => t('Addressbook Tools'), + '$import_label' => t('Import addressbook'), + '$import_placeholder' => t('Select an addressbook to import to'), + '$upload' => t('Upload') + ]); + + return $o; + + } + + } +}
\ No newline at end of file diff --git a/Zotlabs/Widget/Conversations.php b/Zotlabs/Widget/Conversations.php index 27e517c02..56510750f 100644 --- a/Zotlabs/Widget/Conversations.php +++ b/Zotlabs/Widget/Conversations.php @@ -12,10 +12,6 @@ class Conversations { if(argc() > 1) { switch(argv(1)) { - case 'combined': - $mailbox = 'combined'; - $header = t('Conversations'); - break; case 'inbox': $mailbox = 'inbox'; $header = t('Received Messages'); @@ -44,6 +40,8 @@ class Conversations { foreach($r as $rr) { + $selected = ((argc() == 3) ? intval(argv(2)) == intval($rr['id']) : $r[0]['id'] == $rr['id']); + $messages[] = array( 'mailbox' => $mailbox, 'id' => $rr['id'], @@ -58,7 +56,7 @@ class Conversations { 'body' => $rr['body'], 'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], 'c'), 'seen' => $rr['seen'], - 'selected' => ((argv(2)) ? (argv(2) == $rr['id']) : ($r[0]['id'] == $rr['id'])) + 'selected' => ((argv(1) != 'new') ? $selected : '') ); } @@ -71,4 +69,6 @@ class Conversations { } return $o; } + } + diff --git a/Zotlabs/Widget/Forums.php b/Zotlabs/Widget/Forums.php index 67e498b24..002c0ee21 100644 --- a/Zotlabs/Widget/Forums.php +++ b/Zotlabs/Widget/Forums.php @@ -87,7 +87,7 @@ class Forums { foreach($r1 as $rr) { if($unseen && (! intval($rr['unseen']))) continue; - $o .= '<li class="nav-item"><a class="nav-link" href="network?f=&pf=1&cid=' . $rr['abook_id'] . '" ><span class="badge badge-default float-right">' . ((intval($rr['unseen'])) ? intval($rr['unseen']) : '') . '</span><img class ="menu-img-1" src="' . $rr['xchan_photo_s'] . '" /> ' . $rr['xchan_name'] . '</a></li>'; + $o .= '<li class="nav-item"><a class="nav-link" href="network?f=&pf=1&cid=' . $rr['abook_id'] . '" ><span class="badge badge-secondary float-right">' . ((intval($rr['unseen'])) ? intval($rr['unseen']) : '') . '</span><img class ="menu-img-1" src="' . $rr['xchan_photo_s'] . '" /> ' . $rr['xchan_name'] . '</a></li>'; } $o .= '</ul></div>'; } diff --git a/Zotlabs/Widget/Portfolio.php b/Zotlabs/Widget/Portfolio.php new file mode 100644 index 000000000..216ca952c --- /dev/null +++ b/Zotlabs/Widget/Portfolio.php @@ -0,0 +1,108 @@ +<?php + +namespace Zotlabs\Widget; + +require_once('include/attach.php'); + +class Portfolio { + + function widget($args) { + + + $owner_uid = \App::$profile_uid; + $sql_extra = permissions_sql($owner_uid); + + + if(! perm_is_allowed($owner_uid,get_observer_hash(),'view_storage')) + return ''; + + if($args['album']) + $album = $args['album']; + 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) { + $x = q("select hash from attach where filename = '%s' and uid = %d limit 1", + dbesc($album), + intval($owner_uid) + ); + if($x) { + $y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']); + 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 + ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale) + ORDER BY created $order ", + intval($owner_uid), + dbesc($album), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) + ); + + //edit album name + $album_edit = null; + + $photos = array(); + if($r) { + $twist = 'rotright'; + foreach($r as $rr) { + + if($twist == 'rotright') + $twist = 'rotleft'; + else + $twist = 'rotright'; + + $ext = $phototypes[$rr['mimetype']]; + + $imgalt_e = $rr['filename']; + $desc_e = $rr['description']; + + $imagelink = (z_root() . '/photos/' . \App::$profile['channel_address'] . '/image/' . $rr['resource_id']); + + + $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, + 'fullsrc' => z_root() . '/photo/' . $rr['resource_id'] . '-' . '1' . '.' .$ext, + 'resource_id' => $rr['resource_id'], + 'alt' => $imgalt_e, + 'desc'=> $desc_e, + 'ext' => $ext, + 'hash'=> $rr['resource_id'], + 'unknown' => t('Unknown') + ); + } + } + + + $tpl = get_markup_template('photo_album_portfolio.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, + '$usage' => $usage_message + )); + + return $o; + } +} + diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php index 753390c23..c15ad0980 100644 --- a/Zotlabs/Widget/Settings_menu.php +++ b/Zotlabs/Widget/Settings_menu.php @@ -79,11 +79,13 @@ class Settings_menu { 'selected' => '' ); - $tabs[] = array( - 'label' => t('Connected apps'), - 'url' => z_root() . '/settings/oauth', - 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), - ); + if(get_account_techlevel() > 0) { + $tabs[] = array( + 'label' => t('Connected apps'), + 'url' => z_root() . '/settings/oauth', + 'selected' => ((argv(1) === 'oauth') ? 'active' : ''), + ); + } if(get_account_techlevel() > 2) { $tabs[] = array( diff --git a/Zotlabs/Widget/Tasklist.php b/Zotlabs/Widget/Tasklist.php index 6f7a8aaed..3961eecce 100644 --- a/Zotlabs/Widget/Tasklist.php +++ b/Zotlabs/Widget/Tasklist.php @@ -8,8 +8,8 @@ class Tasklist { function widget($arr) { - if (! local_channel()) - return; + if (! local_channel()) + return; $o .= '<script>var tasksShowAll = 0; $(document).ready(function() { tasksFetch(); $("#tasklist-new-form").submit(function(event) { event.preventDefault(); $.post( "tasks/new", $("#tasklist-new-form").serialize(), function(data) { tasksFetch(); $("#tasklist-new-summary").val(""); } ); return false; } )});</script>'; $o .= '<script>function taskComplete(id) { $.post("tasks/complete/"+id, function(data) { tasksFetch();}); } diff --git a/Zotlabs/Widget/Wiki_pages.php b/Zotlabs/Widget/Wiki_pages.php index 53966b06f..a07c348ff 100644 --- a/Zotlabs/Widget/Wiki_pages.php +++ b/Zotlabs/Widget/Wiki_pages.php @@ -11,14 +11,8 @@ class Wiki_pages { return; if(! $arr['resource_id']) { - - $c = \App::get_channel(); - - if(! $c) - $c = channelx_by_nick(argv(1)); - + $c = channelx_by_nick(argv(1)); $w = \Zotlabs\Lib\NativeWiki::exists_by_name($c['channel_id'],argv(2)); - $arr = array( 'resource_id' => $w['resource_id'], 'channel_id' => $c['channel_id'], @@ -29,6 +23,8 @@ class Wiki_pages { $wikiname = ''; + $wikiname = ''; + $pages = array(); $p = \Zotlabs\Lib\NativeWikiPage::page_list($arr['channel_id'],get_observer_hash(),$arr['resource_id']); diff --git a/Zotlabs/Zot/Auth.php b/Zotlabs/Zot/Auth.php index d4d3bee1d..92b0fff78 100644 --- a/Zotlabs/Zot/Auth.php +++ b/Zotlabs/Zot/Auth.php @@ -176,7 +176,7 @@ class Auth { return false; } - $this->Debug('auth check request returned .' . print_r($j, true)); + $this->Debug('auth check request returned ' . print_r($j, true)); if(! $j['success']) return false; |