aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
authorMario <mario@mariovavti.com>2018-01-09 09:00:20 +0100
committerMario <mario@mariovavti.com>2018-01-09 09:00:20 +0100
commit4f4d0e416eac87121898b8a27b1afa6065ff17a2 (patch)
treeaae7f2582b2b9c6596dcbf87c06a836434140830 /Zotlabs
parent22c89b6c660e185d5c5c6362acf23b145d932d15 (diff)
parent8fde0f01b8472082158b38386046ed606bcfbc49 (diff)
downloadvolse-hubzilla-4f4d0e416eac87121898b8a27b1afa6065ff17a2.tar.gz
volse-hubzilla-4f4d0e416eac87121898b8a27b1afa6065ff17a2.tar.bz2
volse-hubzilla-4f4d0e416eac87121898b8a27b1afa6065ff17a2.zip
Merge branch '3.0RC'3.0
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/Access/PermissionRoles.php128
-rw-r--r--Zotlabs/Access/Permissions.php34
-rw-r--r--Zotlabs/Daemon/Cron.php2
-rw-r--r--Zotlabs/Daemon/Cron_weekly.php15
-rw-r--r--Zotlabs/Daemon/Notifier.php4
-rw-r--r--Zotlabs/Daemon/Queue.php1
-rw-r--r--Zotlabs/Daemon/Ratenotif.php8
-rw-r--r--Zotlabs/Daemon/Thumbnail.php78
-rw-r--r--Zotlabs/Extend/Hook.php18
-rw-r--r--Zotlabs/Lib/ActivityStreams.php124
-rw-r--r--Zotlabs/Lib/Apps.php47
-rw-r--r--Zotlabs/Lib/Chatroom.php40
-rw-r--r--Zotlabs/Lib/Config.php29
-rw-r--r--Zotlabs/Lib/Enotify.php8
-rw-r--r--Zotlabs/Lib/NativeWikiPage.php4
-rw-r--r--Zotlabs/Lib/PConfig.php46
-rw-r--r--Zotlabs/Lib/SConfig.php7
-rw-r--r--Zotlabs/Lib/ThreadItem.php21
-rw-r--r--Zotlabs/Lib/ThreadStream.php17
-rw-r--r--Zotlabs/Lib/XConfig.php33
-rw-r--r--Zotlabs/Module/Acl.php11
-rw-r--r--Zotlabs/Module/Admin/Site.php12
-rw-r--r--Zotlabs/Module/Appman.php6
-rw-r--r--Zotlabs/Module/Apporder.php16
-rw-r--r--Zotlabs/Module/Apps.php5
-rw-r--r--Zotlabs/Module/Article_edit.php138
-rw-r--r--Zotlabs/Module/Articles.php187
-rw-r--r--Zotlabs/Module/Cdav.php2
-rw-r--r--Zotlabs/Module/Channel.php1
-rw-r--r--Zotlabs/Module/Cloud.php43
-rw-r--r--Zotlabs/Module/Cloud_tiles.php21
-rw-r--r--Zotlabs/Module/Connedit.php2
-rw-r--r--Zotlabs/Module/Dav.php2
-rw-r--r--Zotlabs/Module/Defperms.php267
-rw-r--r--Zotlabs/Module/Directory.php9
-rw-r--r--Zotlabs/Module/Display.php175
-rw-r--r--Zotlabs/Module/Embedphotos.php2
-rw-r--r--Zotlabs/Module/Feed.php9
-rw-r--r--Zotlabs/Module/File_upload.php52
-rw-r--r--Zotlabs/Module/Filestorage.php5
-rw-r--r--Zotlabs/Module/Getfile.php57
-rw-r--r--Zotlabs/Module/Hq.php301
-rw-r--r--Zotlabs/Module/Impel.php2
-rw-r--r--Zotlabs/Module/Item.php119
-rw-r--r--Zotlabs/Module/Layouts.php4
-rw-r--r--Zotlabs/Module/Like.php26
-rw-r--r--Zotlabs/Module/Network.php27
-rw-r--r--Zotlabs/Module/Notify.php2
-rw-r--r--Zotlabs/Module/Oep.php85
-rw-r--r--Zotlabs/Module/Ofeed.php9
-rw-r--r--Zotlabs/Module/Page.php24
-rw-r--r--Zotlabs/Module/Pdledit.php8
-rw-r--r--Zotlabs/Module/Photos.php61
-rw-r--r--Zotlabs/Module/Ping.php31
-rw-r--r--Zotlabs/Module/Profile.php2
-rw-r--r--Zotlabs/Module/Profile_photo.php7
-rw-r--r--Zotlabs/Module/Pubstream.php82
-rw-r--r--Zotlabs/Module/React.php25
-rw-r--r--Zotlabs/Module/Register.php6
-rw-r--r--Zotlabs/Module/Search.php4
-rw-r--r--Zotlabs/Module/Settings/Channel.php17
-rw-r--r--Zotlabs/Module/Settings/Display.php3
-rw-r--r--Zotlabs/Module/Settings/Featured.php20
-rw-r--r--Zotlabs/Module/Starred.php2
-rw-r--r--Zotlabs/Module/Subthread.php32
-rw-r--r--Zotlabs/Module/Tagger.php30
-rw-r--r--Zotlabs/Module/Update.php43
-rw-r--r--Zotlabs/Module/Update_cards.php39
-rw-r--r--Zotlabs/Module/Update_channel.php70
-rw-r--r--Zotlabs/Module/Update_display.php32
-rw-r--r--Zotlabs/Module/Update_home.php42
-rw-r--r--Zotlabs/Module/Update_network.php44
-rw-r--r--Zotlabs/Module/Update_pubstream.php42
-rw-r--r--Zotlabs/Module/Update_search.php69
-rw-r--r--Zotlabs/Module/Wall_attach.php10
-rw-r--r--Zotlabs/Module/Wfinger.php150
-rw-r--r--Zotlabs/Module/Wiki.php81
-rw-r--r--Zotlabs/Render/Comanche.php199
-rw-r--r--Zotlabs/Render/Theme.php44
-rw-r--r--Zotlabs/Storage/Browser.php51
-rw-r--r--Zotlabs/Storage/Directory.php33
-rw-r--r--Zotlabs/Storage/File.php22
-rw-r--r--Zotlabs/Thumbs/Epubthumb.php38
-rw-r--r--Zotlabs/Thumbs/Mp3audio.php37
-rw-r--r--Zotlabs/Thumbs/Pdf.php49
-rw-r--r--Zotlabs/Thumbs/Text.php49
-rw-r--r--Zotlabs/Thumbs/Video.php65
-rw-r--r--Zotlabs/Web/HTTPSig.php2
-rw-r--r--Zotlabs/Web/Router.php46
-rw-r--r--Zotlabs/Widget/Affinity.php12
-rw-r--r--Zotlabs/Widget/Appcategories.php1
-rw-r--r--Zotlabs/Widget/Categories.php10
-rw-r--r--Zotlabs/Widget/Conversations.php12
-rw-r--r--Zotlabs/Widget/Forums.php32
-rw-r--r--Zotlabs/Widget/Hq_controls.php26
-rw-r--r--Zotlabs/Widget/Notifications.php18
-rw-r--r--Zotlabs/Widget/Settings_menu.php2
-rw-r--r--Zotlabs/Widget/Wiki_pages.php36
-rw-r--r--Zotlabs/Zot/Verify.php13
99 files changed, 3039 insertions, 995 deletions
diff --git a/Zotlabs/Access/PermissionRoles.php b/Zotlabs/Access/PermissionRoles.php
index 49d478c5c..b335bf825 100644
--- a/Zotlabs/Access/PermissionRoles.php
+++ b/Zotlabs/Access/PermissionRoles.php
@@ -1,12 +1,21 @@
<?php
-
namespace Zotlabs\Access;
-use Zotlabs\Lib as Zlib;
-
+/**
+ * @brief PermissionRoles class.
+ *
+ * @see Permissions
+ */
class PermissionRoles {
+ /**
+ * @brief PermissionRoles version.
+ *
+ * This must match the version in Permissions.php before permission updates can run.
+ *
+ * @return number
+ */
static public function version() {
return 2;
}
@@ -23,12 +32,13 @@ class PermissionRoles {
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = true;
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
- 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
- 'post_mail', 'chat', 'post_like', 'republish' ];
-
+ 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
+ 'post_mail', 'chat', 'post_like', 'republish'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
+
break;
case 'social_restricted':
@@ -36,11 +46,11 @@ class PermissionRoles {
$ret['default_collection'] = true;
$ret['directory_publish'] = true;
$ret['online'] = true;
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
- 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
- 'post_mail', 'chat', 'post_like' ];
-
+ 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
+ 'post_mail', 'chat', 'post_like'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
@@ -50,10 +60,11 @@ class PermissionRoles {
$ret['default_collection'] = true;
$ret['directory_publish'] = false;
$ret['online'] = false;
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
- 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
- 'post_mail', 'post_like' ];
+ 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
+ 'post_mail', 'post_like'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
$ret['limits']['view_storage'] = PERMS_SPECIFIC;
@@ -65,12 +76,13 @@ class PermissionRoles {
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver',
- 'post_mail', 'post_like' , 'republish', 'chat' ];
-
+ 'post_mail', 'post_like' , 'republish', 'chat'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
+
break;
case 'forum_restricted':
@@ -78,11 +90,10 @@ class PermissionRoles {
$ret['default_collection'] = true;
$ret['directory_publish'] = true;
$ret['online'] = false;
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_wall', 'post_comments', 'tag_deliver',
'post_mail', 'post_like' , 'chat' ];
-
$ret['limits'] = PermissionLimits::Std_Limits();
break;
@@ -92,12 +103,11 @@ class PermissionRoles {
$ret['default_collection'] = true;
$ret['directory_publish'] = false;
$ret['online'] = false;
-
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'post_wall', 'post_comments',
- 'post_mail', 'post_like' , 'chat' ];
-
+ 'post_mail', 'post_like' , 'chat'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
$ret['limits']['view_profile'] = PERMS_SPECIFIC;
$ret['limits']['view_contacts'] = PERMS_SPECIFIC;
@@ -112,12 +122,11 @@ class PermissionRoles {
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
-
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
- 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
- 'post_mail', 'post_like' , 'republish' ];
-
+ 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
+ 'post_mail', 'post_like' , 'republish'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
@@ -127,11 +136,11 @@ class PermissionRoles {
$ret['default_collection'] = true;
$ret['directory_publish'] = false;
$ret['online'] = false;
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
- 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
- 'post_mail', 'post_like' , 'republish' ];
-
+ 'view_pages', 'view_wiki', 'send_stream', 'post_wall', 'post_comments',
+ 'post_mail', 'post_like' , 'republish'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
@@ -141,11 +150,10 @@ class PermissionRoles {
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
-
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
- 'view_pages', 'view_wiki', 'post_like' , 'republish' ];
-
+ 'view_pages', 'view_wiki', 'post_like' , 'republish'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
break;
@@ -155,13 +163,13 @@ class PermissionRoles {
$ret['default_collection'] = false;
$ret['directory_publish'] = true;
$ret['online'] = false;
-
- $ret['perms_connect'] = [
+ $ret['perms_connect'] = [
'view_stream', 'view_profile', 'view_contacts', 'view_storage',
'view_pages', 'view_wiki', 'write_storage', 'write_pages', 'post_wall', 'post_comments', 'tag_deliver',
- 'post_mail', 'post_like' , 'republish', 'chat', 'write_wiki' ];
-
+ 'post_mail', 'post_like' , 'republish', 'chat', 'write_wiki'
+ ];
$ret['limits'] = PermissionLimits::Std_Limits();
+
break;
case 'custom':
@@ -170,11 +178,15 @@ class PermissionRoles {
}
$x = get_config('system','role_perms');
- // let system settings over-ride any or all
+ // let system settings over-ride any or all
if($x && is_array($x) && array_key_exists($role,$x))
$ret = array_merge($ret,$x[$role]);
- call_hooks('get_role_perms',$ret);
+ /**
+ * @hooks get_role_perms
+ * * \e array
+ */
+ call_hooks('get_role_perms', $ret);
return $ret;
}
@@ -187,10 +199,10 @@ class PermissionRoles {
// \Zotlabs\Access\PermissionLimits::Set($uid,$perm,1);
if($perm === 'view_wiki')
- \Zotlabs\Access\PermissionLimits::Set($uid,$perm,PERMS_PUBLIC);
+ \Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_PUBLIC);
if($perm === 'write_wiki')
- \Zotlabs\Access\PermissionLimits::Set($uid,$perm,PERMS_SPECIFIC);
+ \Zotlabs\Access\PermissionLimits::Set($uid, $perm, PERMS_SPECIFIC);
// set autoperms here if applicable
@@ -213,8 +225,6 @@ class PermissionRoles {
if($c) {
set_abconfig($uid,$c['channel_hash'],'autoperms',$perm,$value);
}
-
-
}
// now set something for all existing connections.
@@ -242,38 +252,44 @@ class PermissionRoles {
}
}
-
+ /**
+ * @brief Array with translated role names and grouping.
+ *
+ * Return an associative array with grouped role names that can be used
+ * to create select groups like in \e field_select_grouped.tpl.
+ *
+ * @return array
+ */
static public function roles() {
- $roles = [
+ $roles = [
t('Social Networking') => [
- 'social' => t('Social - Mostly Public'),
- 'social_restricted' => t('Social - Restricted'),
+ 'social' => t('Social - Mostly Public'),
+ 'social_restricted' => t('Social - Restricted'),
'social_private' => t('Social - Private')
],
t('Community Forum') => [
- 'forum' => t('Forum - Mostly Public'),
- 'forum_restricted' => t('Forum - Restricted'),
+ 'forum' => t('Forum - Mostly Public'),
+ 'forum_restricted' => t('Forum - Restricted'),
'forum_private' => t('Forum - Private')
],
t('Feed Republish') => [
- 'feed' => t('Feed - Mostly Public'),
+ 'feed' => t('Feed - Mostly Public'),
'feed_restricted' => t('Feed - Restricted')
],
t('Special Purpose') => [
- 'soapbox' => t('Special - Celebrity/Soapbox'),
+ 'soapbox' => t('Special - Celebrity/Soapbox'),
'repository' => t('Special - Group Repository')
],
t('Other') => [
'custom' => t('Custom/Expert Mode')
]
-
];
- return $roles;
+ return $roles;
}
} \ No newline at end of file
diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php
index 62c4af0ff..bca40a9c1 100644
--- a/Zotlabs/Access/Permissions.php
+++ b/Zotlabs/Access/Permissions.php
@@ -33,19 +33,22 @@ use Zotlabs\Lib as Zlib;
*/
class Permissions {
+ /**
+ * @brief Permissions version.
+ *
+ * This must match the version in PermissionRoles.php before permission updates can run.
+ *
+ * @return number
+ */
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.
+ * @param string $filter (optional) only passed to hook permissions_list
+ * @return array Associative array with permissions and short description.
*/
static public function Perms($filter = '') {
@@ -74,6 +77,11 @@ class Permissions {
'permissions' => $perms,
'filter' => $filter
];
+ /**
+ * @hooks permissions_list
+ * * \e array \b permissions
+ * * \e string \b filter
+ */
call_hooks('permissions_list', $x);
return($x['permissions']);
@@ -84,9 +92,7 @@ class Permissions {
*
* e.g. you must be authenticated.
*
- * @hooks write_perms
- * * \e array \b permissions
- * @return Associative array with permissions and short description.
+ * @return array Associative array with permissions and short description.
*/
static public function BlockedAnonPerms() {
@@ -99,6 +105,10 @@ class Permissions {
}
$x = ['permissions' => $res];
+ /**
+ * @hooks write_perms
+ * * \e array \b permissions
+ */
call_hooks('write_perms', $x);
return($x['permissions']);
@@ -117,6 +127,7 @@ class Permissions {
static public function FilledPerms($arr) {
if(is_null($arr)) {
btlogger('FilledPerms: null');
+ $arr = [];
}
$everything = self::Perms();
@@ -138,7 +149,7 @@ class Permissions {
* to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ]
*
* @param array $arr associative perms array 'view_stream' => 1
- * @return Indexed array with elements that look like
+ * @return array 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)
*/
@@ -197,11 +208,10 @@ class Permissions {
* @brief
*
* @param int $channel_id A channel id
- * @return associative array
+ * @return array Associative array with
* * \e array \b perms Permission array
* * \e int \b automatic 0 or 1
*/
-
static public function connect_perms($channel_id) {
$my_perms = [];
diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php
index 65edbedfa..01c43262a 100644
--- a/Zotlabs/Daemon/Cron.php
+++ b/Zotlabs/Daemon/Cron.php
@@ -78,7 +78,7 @@ class Cron {
// channels and sites that quietly vanished and prevent the directory from accumulating stale
// or dead entries.
- $r = q("select channel_id from channel where channel_dirdate < %s - INTERVAL %s",
+ $r = q("select channel_id from channel where channel_dirdate < %s - INTERVAL %s and channel_removed = 0",
db_utcnow(),
db_quoteinterval('30 DAY')
);
diff --git a/Zotlabs/Daemon/Cron_weekly.php b/Zotlabs/Daemon/Cron_weekly.php
index 5b185f475..d44400767 100644
--- a/Zotlabs/Daemon/Cron_weekly.php
+++ b/Zotlabs/Daemon/Cron_weekly.php
@@ -21,6 +21,21 @@ class Cron_weekly {
mark_orphan_hubsxchans();
+ // Find channels that were removed in the last three weeks, but
+ // haven't been finally cleaned up. These should be older than 10
+ // days to ensure that "purgeall" messages have gone out or bounced
+ // or timed out.
+
+ $r = q("select channel_id from channel where channel_removed = 1 and
+ channel_deleted > %s - INTERVAL %s and channel_deleted < %s - INTERVAL %s",
+ db_utcnow(), db_quoteinterval('21 DAY'),
+ db_utcnow(), db_quoteinterval('10 DAY')
+ );
+ if($r) {
+ foreach($r as $rv) {
+ channel_remove_final($rv['channel_id']);
+ }
+ }
// get rid of really old poco records
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index d0175549b..ca6a7c08a 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -426,8 +426,10 @@ class Notifier {
logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG);
stringify_array_elms($recipients);
- if(! $recipients)
+ if(! $recipients) {
+ logger('no recipients');
return;
+ }
// logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG);
diff --git a/Zotlabs/Daemon/Queue.php b/Zotlabs/Daemon/Queue.php
index 11cbe4494..17d150250 100644
--- a/Zotlabs/Daemon/Queue.php
+++ b/Zotlabs/Daemon/Queue.php
@@ -12,6 +12,7 @@ class Queue {
require_once('include/items.php');
require_once('include/bbcode.php');
+
if(argc() > 1)
$queue_id = argv(1);
else
diff --git a/Zotlabs/Daemon/Ratenotif.php b/Zotlabs/Daemon/Ratenotif.php
index a94b89004..c7bf79854 100644
--- a/Zotlabs/Daemon/Ratenotif.php
+++ b/Zotlabs/Daemon/Ratenotif.php
@@ -88,6 +88,14 @@ class Ratenotif {
'msg' => json_encode($encoded_item)
));
+
+ $x = q("select count(outq_hash) as total from outq where outq_delivered = 0");
+ if(intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',300))) {
+ logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO);
+ update_queue_item($hash);
+ continue;
+ }
+
$deliver[] = $hash;
if(count($deliver) >= $deliveries_per_process) {
diff --git a/Zotlabs/Daemon/Thumbnail.php b/Zotlabs/Daemon/Thumbnail.php
new file mode 100644
index 000000000..e1f17c304
--- /dev/null
+++ b/Zotlabs/Daemon/Thumbnail.php
@@ -0,0 +1,78 @@
+<?php /** @file */
+
+namespace Zotlabs\Daemon;
+
+
+class Thumbnail {
+
+ static public function run($argc,$argv) {
+
+ if(! $argc == 2)
+ return;
+
+ $c = q("select * from attach where hash = '%s' ",
+ dbesc($argv[1])
+ );
+
+ if(! $c)
+ return;
+
+ $attach = $c[0];
+
+ $preview_style = intval(get_config('system','thumbnail_security',0));
+ $preview_width = intval(get_config('system','thumbnail_width',300));
+ $preview_height = intval(get_config('system','thumbnail_height',300));
+
+ $p = [
+ 'attach' => $attach,
+ 'preview_style' => $preview_style,
+ 'preview_width' => $preview_width,
+ 'preview_height' => $preview_height,
+ 'thumbnail' => null
+ ];
+
+ /**
+ * @hooks thumbnail
+ * * \e array \b attach
+ * * \e int \b preview_style
+ * * \e int \b preview_width
+ * * \e int \b preview_height
+ * * \e string \b thumbnail
+ */
+
+ call_hooks('thumbnail',$p);
+ if($p['thumbnail']) {
+ return;
+ }
+
+
+ $default_controller = null;
+
+ $files = glob('Zotlabs/Thumbs/*.php');
+ if($files) {
+ foreach($files as $f) {
+ $clsname = '\\Zotlabs\\Thumbs\\' . ucfirst(basename($f,'.php'));
+ if(class_exists($clsname)) {
+ $x = new $clsname();
+ if(method_exists($x,'Match')) {
+ $matched = $x->Match($attach['filetype']);
+ if($matched) {
+ $x->Thumb($attach,$preview_style,$preview_width,$preview_height);
+ }
+ }
+ if(method_exists($x,'MatchDefault')) {
+ $default_matched = $x->MatchDefault(substr($attach['filetype'],0,strpos($attach['filetype'],'/')));
+ if($default_matched) {
+ $default_controller = $x;
+ }
+ }
+ }
+ }
+ }
+ if(($default_controller)
+ && ((! file_exists(dbunescbin($attach['content']) . '.thumb'))
+ || (filectime(dbunescbin($attach['content']) . 'thumb') < (time() - 60)))) {
+ $default_controller->Thumb($attach,$preview_style,$preview_width,$preview_height);
+ }
+ }
+}
diff --git a/Zotlabs/Extend/Hook.php b/Zotlabs/Extend/Hook.php
index c6f9ea850..81260ead6 100644
--- a/Zotlabs/Extend/Hook.php
+++ b/Zotlabs/Extend/Hook.php
@@ -2,7 +2,12 @@
namespace Zotlabs\Extend;
+use App;
+/**
+ * @brief Hook class.
+ *
+ */
class Hook {
static public function register($hook,$file,$function,$version = 1,$priority = 0) {
@@ -64,11 +69,14 @@ class Hook {
return $r;
}
- // unregister all hooks with this file component.
- // Useful for addon upgrades where you want to clean out old interfaces.
-
+ /**
+ * @brief Unregister all hooks with this file component.
+ *
+ * Useful for addon upgrades where you want to clean out old interfaces.
+ *
+ * @param string $file
+ */
static public function unregister_by_file($file) {
-
$r = q("DELETE FROM hook WHERE file = '%s' ",
dbesc($file)
);
@@ -76,7 +84,6 @@ class Hook {
return $r;
}
-
/**
* @brief Inserts a hook into a page request.
*
@@ -98,7 +105,6 @@ class Hook {
* @param int $priority
* currently not implemented in this function, would require the hook array to be resorted
*/
-
static public function insert($hook, $fn, $version = 0, $priority = 0) {
if(is_array($fn)) {
$fn = serialize($fn);
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php
index 379e78a59..2e9bb0703 100644
--- a/Zotlabs/Lib/ActivityStreams.php
+++ b/Zotlabs/Lib/ActivityStreams.php
@@ -2,6 +2,11 @@
namespace Zotlabs\Lib;
+/**
+ * @brief ActivityStreams class.
+ *
+ * Parses an ActivityStream JSON string.
+ */
class ActivityStreams {
public $data;
@@ -19,9 +24,16 @@ class ActivityStreams {
public $recips = null;
public $raw_recips = null;
+ /**
+ * @brief Constructor for ActivityStreams.
+ *
+ * Takes a JSON string as parameter, decodes it and sets up this object.
+ *
+ * @param string $string
+ */
function __construct($string) {
- $this->data = json_decode($string,true);
+ $this->data = json_decode($string, true);
if($this->data) {
$this->valid = true;
}
@@ -50,6 +62,11 @@ class ActivityStreams {
}
}
+ /**
+ * @brief Return if instantiated ActivityStream is valid.
+ *
+ * @return boolean Return true if the JSON string could be decoded.
+ */
function is_valid() {
return $this->valid;
}
@@ -58,18 +75,26 @@ class ActivityStreams {
$this->saved_recips = $arr;
}
- function collect_recips($base = '',$namespace = '') {
+ /**
+ * @brief Collects all recipients.
+ *
+ * @param string $base
+ * @param string $namespace (optional) default empty
+ * @return array
+ */
+ function collect_recips($base = '', $namespace = '') {
$x = [];
- $fields = [ 'to','cc','bto','bcc','audience'];
+ $fields = [ 'to', 'cc', 'bto', 'bcc', 'audience'];
foreach($fields as $f) {
- $y = $this->get_compound_property($f,$base,$namespace);
+ $y = $this->get_compound_property($f, $base, $namespace);
if($y) {
- $x = array_merge($x,$y);
+ $x = array_merge($x, $y);
if(! is_array($this->raw_recips))
$this->raw_recips = [];
+
$this->raw_recips[$f] = $x;
}
- }
+ }
// not yet ready for prime time
// $x = $this->expand($x,$base,$namespace);
return $x;
@@ -96,23 +121,30 @@ class ActivityStreams {
}
}
- // @fixme de-duplicate
+ /// @fixme de-duplicate
return $ret;
}
- function get_namespace($base,$namespace) {
+ /**
+ * @brief
+ *
+ * @param array $base
+ * @param string $namespace if not set return empty string
+ * @return string|NULL
+ */
+ function get_namespace($base, $namespace) {
if(! $namespace)
return '';
$key = null;
-
foreach( [ $this->data, $base ] as $b ) {
if(! $b)
continue;
- if(array_key_exists('@context',$b)) {
+
+ if(array_key_exists('@context', $b)) {
if(is_array($b['@context'])) {
foreach($b['@context'] as $ns) {
if(is_array($ns)) {
@@ -135,19 +167,35 @@ class ActivityStreams {
}
}
}
+
return $key;
}
-
- function get_property_obj($property,$base = '',$namespace = '' ) {
- $prefix = $this->get_namespace($base,$namespace);
+ /**
+ * @brief
+ *
+ * @param string $property
+ * @param array $base (optional)
+ * @param string $namespace (optional) default empty
+ * @return NULL|mixed
+ */
+ function get_property_obj($property, $base = '', $namespace = '') {
+ $prefix = $this->get_namespace($base, $namespace);
if($prefix === null)
- return null;
+ return null;
+
$base = (($base) ? $base : $this->data);
$propname = (($prefix) ? $prefix . ':' : '') . $property;
- return ((array_key_exists($propname,$base)) ? $base[$propname] : null);
+
+ return ((array_key_exists($propname, $base)) ? $base[$propname] : null);
}
+ /**
+ * @brief Fetches a property from an URL.
+ *
+ * @param string $url
+ * @return NULL|mixed
+ */
function fetch_property($url) {
$redirects = 0;
if(! check_siteallowed($url)) {
@@ -155,44 +203,70 @@ class ActivityStreams {
return null;
}
- $x = z_fetch_url($url,true,$redirects,
+ $x = z_fetch_url($url, true, $redirects,
['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json' ]]);
if($x['success'])
- return json_decode($x['body'],true);
+ return json_decode($x['body'], true);
+
return null;
}
- function get_compound_property($property,$base = '',$namespace = '') {
- $x = $this->get_property_obj($property,$base,$namespace);
+ /**
+ * @brief
+ *
+ * @param string $property
+ * @param array $base
+ * @param string $namespace (optional) default empty
+ * @return NULL|mixed
+ */
+ function get_compound_property($property, $base = '', $namespace = '') {
+ $x = $this->get_property_obj($property, $base, $namespace);
if($this->is_url($x)) {
- $x = $this->fetch_property($x);
+ $x = $this->fetch_property($x);
}
+
return $x;
}
+ /**
+ * @brief Check if string starts with http.
+ *
+ * @param string $url
+ * @return boolean
+ */
function is_url($url) {
- if(($url) && (! is_array($url)) && (strpos($url,'http') === 0)) {
+ if(($url) && (! is_array($url)) && (strpos($url, 'http') === 0)) {
return true;
}
+
return false;
}
- function get_primary_type($base = '',$namespace = '') {
+ /**
+ * @brief Gets the type property.
+ *
+ * @param array $base
+ * @param string $namespace (optional) default empty
+ * @return NULL|mixed
+ */
+ function get_primary_type($base = '', $namespace = '') {
if(! $base)
$base = $this->data;
- $x = $this->get_property_obj('type',$base,$namespace);
+
+ $x = $this->get_property_obj('type', $base, $namespace);
if(is_array($x)) {
foreach($x as $y) {
- if(strpos($y,':') === false) {
+ if(strpos($y, ':') === false) {
return $y;
}
}
}
+
return $x;
}
function debug() {
- $x = var_export($this,true);
+ $x = var_export($this, true);
return $x;
}
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index f13fbe362..457b85b62 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -352,7 +352,7 @@ class Apps {
break;
default:
if($config)
- $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true);
+ $unset = ((get_config('system', $require[0]) === $require[1]) ? false : true);
else
$unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true);
if($unset)
@@ -401,11 +401,15 @@ class Apps {
'$undelete' => ((local_channel() && $installed && $mode == 'edit') ? t('Undelete') : ''),
'$deleted' => $papp['deleted'],
'$feature' => (($papp['embed']) ? false : true),
+ '$pin' => (($papp['embed']) ? false : true),
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
+ '$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
'$navapps' => (($mode == 'nav') ? true : false),
'$order' => (($mode == 'nav-order') ? true : false),
'$add' => t('Add to app-tray'),
- '$remove' => t('Remove from app-tray')
+ '$remove' => t('Remove from app-tray'),
+ '$add_nav' => t('Pin to navbar'),
+ '$remove_nav' => t('Unpin from navbar')
));
}
@@ -498,25 +502,27 @@ class Apps {
}
}
- static public function app_feature($uid,$app) {
+ static public function app_feature($uid,$app,$term) {
$r = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($app['guid']),
intval($uid)
);
- $x = q("select * from term where otype = %d and oid = %d and term = 'nav_featured_app' limit 1",
+ $x = q("select * from term where otype = %d and oid = %d and term = '%s' limit 1",
intval(TERM_OBJ_APP),
- intval($r[0]['id'])
+ intval($r[0]['id']),
+ dbesc($term)
);
if($x) {
- q("delete from term where otype = %d and oid = %d and term = 'nav_featured_app'",
+ q("delete from term where otype = %d and oid = %d and term = '%s'",
intval(TERM_OBJ_APP),
- intval($x[0]['oid'])
+ intval($x[0]['oid']),
+ dbesc($term)
);
}
else {
- store_item_tag($uid,$r[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,'nav_featured_app',escape_tags(z_root() . '/apps/?f=&cat=nav_featured_app'));
+ store_item_tag($uid, $r[0]['id'], TERM_OBJ_APP, TERM_CATEGORY, $term, escape_tags(z_root() . '/apps/?f=&cat=' . $term));
}
}
@@ -531,16 +537,27 @@ class Apps {
}
- static public function app_list($uid, $deleted = false, $cat = '') {
+ static public function app_list($uid, $deleted = false, $cats = []) {
if($deleted)
$sql_extra = "";
else
$sql_extra = " and app_deleted = 0 ";
- if($cat) {
- $r = q("select oid from term where otype = %d and term = '%s'",
- intval(TERM_OBJ_APP),
- dbesc($cat)
+ if($cats) {
+
+ $cat_sql_extra = " and ( ";
+
+ foreach($cats as $cat) {
+ if(strpos($cat_sql_extra, 'term'))
+ $cat_sql_extra .= "or ";
+
+ $cat_sql_extra .= "term = '" . dbesc($cat) . "' ";
+ }
+
+ $cat_sql_extra .= ") ";
+
+ $r = q("select oid from term where otype = %d $cat_sql_extra",
+ intval(TERM_OBJ_APP)
);
if(! $r)
return $r;
@@ -616,7 +633,7 @@ class Apps {
static function moveup($uid,$guid) {
$syslist = array();
- $list = self::app_list($uid, false, 'nav_featured_app');
+ $list = self::app_list($uid, false, ['nav_featured_app', 'nav_pinned_app']);
if($list) {
foreach($list as $li) {
$syslist[] = self::app_encode($li);
@@ -657,7 +674,7 @@ class Apps {
static function movedown($uid,$guid) {
$syslist = array();
- $list = self::app_list($uid, false, 'nav_featured_app');
+ $list = self::app_list($uid, false, ['nav_featured_app', 'nav_pinned_app']);
if($list) {
foreach($list as $li) {
$syslist[] = self::app_encode($li);
diff --git a/Zotlabs/Lib/Chatroom.php b/Zotlabs/Lib/Chatroom.php
index e1a9a10b3..e762620ae 100644
--- a/Zotlabs/Lib/Chatroom.php
+++ b/Zotlabs/Lib/Chatroom.php
@@ -2,22 +2,18 @@
namespace Zotlabs\Lib;
/**
- * @brief Chat related functions.
+ * @brief A class with chatroom related static methods.
*/
-
-
-
class Chatroom {
/**
* @brief Creates a chatroom.
*
* @param array $channel
* @param array $arr
- * @return An associative array containing:
- * - success: A boolean
- * - message: (optional) A string
+ * @return array An associative array containing:
+ * * \e boolean \b success - A boolean success status
+ * * \e string \b message - (optional) A string
*/
-
static public function create($channel, $arr) {
$ret = array('success' => false);
@@ -150,8 +146,8 @@ class Chatroom {
}
if(intval($x[0]['cr_expire'])) {
- $r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d",
- db_utcnow(),
+ $r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d",
+ db_utcnow(),
db_quoteinterval( intval($x[0]['cr_expire']) . ' MINUTE' ),
intval($x[0]['cr_id'])
);
@@ -225,10 +221,16 @@ class Chatroom {
}
/**
- * create a chat message via API.
+ * @brief Create a chat message via API.
+ *
* It is the caller's responsibility to enter the room.
- */
-
+ *
+ * @param int $uid
+ * @param int $room_id
+ * @param string $xchan
+ * @param string $text
+ * @return array
+ */
static public function message($uid, $room_id, $xchan, $text) {
$ret = array('success' => false);
@@ -245,12 +247,18 @@ class Chatroom {
if(! $r)
return $ret;
- $arr = array(
+ $arr = [
'chat_room' => $room_id,
'chat_xchan' => $xchan,
'chat_text' => $text
- );
-
+ ];
+ /**
+ * @hooks chat_message
+ * Called to create a chat message.
+ * * \e int \b chat_room
+ * * \e string \b chat_xchan
+ * * \e string \b chat_text
+ */
call_hooks('chat_message', $arr);
$x = q("insert into chat ( chat_room, chat_xchan, created, chat_text )
diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php
index 6e042feba..f9f22ba3a 100644
--- a/Zotlabs/Lib/Config.php
+++ b/Zotlabs/Lib/Config.php
@@ -1,4 +1,4 @@
-<?php /** @file */
+<?php
namespace Zotlabs\Lib;
@@ -14,7 +14,6 @@ class Config {
* @param string $family
* The category of the configuration value
*/
-
static public function Load($family) {
if(! array_key_exists($family, \App::$config))
\App::$config[$family] = array();
@@ -30,7 +29,7 @@ class Config {
}
\App::$config[$family]['config_loaded'] = true;
}
- }
+ }
}
/**
@@ -47,8 +46,7 @@ class Config {
* @return mixed
* Return the set value, or false if the database update failed
*/
-
- static public function Set($family,$key,$value) {
+ static public function Set($family, $key, $value) {
// manage array value
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
@@ -76,8 +74,8 @@ class Config {
\App::$config[$family][$key] = $value;
$ret = $value;
}
- return $ret;
+ return $ret;
}
/**
@@ -88,25 +86,25 @@ class Config {
* $key from a cached storage in App::$config[$family]. If a key is found in the
* DB but does not exist in local config cache, pull it into the cache so we
* do not have to hit the DB again for this item.
- *
+ *
* Returns false if not set.
*
* @param string $family
* The category of the configuration value
* @param string $key
* The configuration key to query
+ * @param string $default (optional) default false
* @return mixed Return value or false on error or if not set
*/
-
- static public function Get($family,$key,$default = false) {
+ static public function Get($family, $key, $default = false) {
if((! array_key_exists($family, \App::$config)) || (! array_key_exists('config_loaded', \App::$config[$family])))
self::Load($family);
if(array_key_exists('config_loaded', \App::$config[$family])) {
if(! array_key_exists($key, \App::$config[$family])) {
- return $default;
+ return $default;
}
- return ((! is_array(\App::$config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$family][$key]))
+ return ((! is_array(\App::$config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$family][$key]))
? unserialize(\App::$config[$family][$key])
: \App::$config[$family][$key]
);
@@ -127,17 +125,18 @@ class Config {
* The configuration key to delete
* @return mixed
*/
-
- static public function Delete($family,$key) {
+ static public function Delete($family, $key) {
$ret = false;
if(array_key_exists($family, \App::$config) && array_key_exists($key, \App::$config[$family]))
unset(\App::$config[$family][$key]);
- $ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
+
+ $ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
dbesc($family),
dbesc($key)
);
+
return $ret;
}
@@ -154,12 +153,12 @@ class Config {
* The configuration key to query
* @return mixed
*/
-
static private function get_from_storage($family,$key) {
$ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1",
dbesc($family),
dbesc($key)
);
+
return $ret;
}
diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php
index 21227893c..a7b4f28e8 100644
--- a/Zotlabs/Lib/Enotify.php
+++ b/Zotlabs/Lib/Enotify.php
@@ -778,10 +778,14 @@ class Enotify {
// Call localize_item to get a one line status for activities.
// This should set $item['localized'] to indicate we have a brief summary.
+ // and perhaps $item['shortlocalized'] for an even briefer summary
localize_item($item);
- if($item['localize']) {
+ if($item['shortlocalize']) {
+ $itemem_text = $item['shortlocalize'];
+ }
+ elseif($item['localize']) {
$itemem_text = $item['localize'];
}
else {
@@ -800,6 +804,8 @@ class Enotify {
'when' => relative_date($item['created']),
'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])),
+ 'notify_id' => 'undefined',
+ 'thread_top' => (($item['item_thread_top']) ? true : false),
'message' => strip_tags(bbcode($itemem_text))
);
diff --git a/Zotlabs/Lib/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php
index 209a5ef3c..919c51276 100644
--- a/Zotlabs/Lib/NativeWikiPage.php
+++ b/Zotlabs/Lib/NativeWikiPage.php
@@ -68,6 +68,9 @@ class NativeWikiPage {
return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
}
+ // backslashes won't work well in the javascript functions
+ $name = str_replace('\\','',$name);
+
// create an empty activity
$arr = [];
@@ -351,6 +354,7 @@ class NativeWikiPage {
// fetch the most recently saved revision.
$item = self::load_page($arr);
+
if(! $item) {
return array('message' => t('Page not found'), 'success' => false);
}
diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php
index 2a0b18aac..ec0792ce1 100644
--- a/Zotlabs/Lib/PConfig.php
+++ b/Zotlabs/Lib/PConfig.php
@@ -1,8 +1,21 @@
-<?php /** @file */
+<?php
namespace Zotlabs\Lib;
-
+/**
+ * @brief Class for handling channel specific configurations.
+ *
+ * <b>PConfig</b> is used for channel specific configurations and takes a
+ * <i>channel_id</i> as identifier. It stores for example which features are
+ * enabled per channel. The storage is of size MEDIUMTEXT.
+ *
+ * @code{.php}$var = Zotlabs\Lib\PConfig::Get('uid', 'category', 'key');
+ * // with default value for non existent key
+ * $var = Zotlabs\Lib\PConfig::Get('uid', 'category', 'unsetkey', 'defaultvalue');@endcode
+ *
+ * The old (deprecated?) way to access a PConfig value is:
+ * @code{.php}$var = get_pconfig(local_channel(), 'category', 'key');@endcode
+ */
class PConfig {
/**
@@ -13,9 +26,8 @@ class PConfig {
*
* @param string $uid
* The channel_id
- * @return void|false Nothing or false if $uid is false
+ * @return void|false Nothing or false if $uid is null or false
*/
-
static public function Load($uid) {
if(is_null($uid) || $uid === false)
return false;
@@ -64,11 +76,11 @@ class PConfig {
* The category of the configuration value
* @param string $key
* The configuration key to query
- * @param boolean $instore (deprecated, without function)
+ * @param mixed $default (optional, default false)
+ * Default value to return if key does not exist
* @return mixed Stored value or false if it does not exist
*/
-
- static public function Get($uid,$family,$key,$default = false) {
+ static public function Get($uid, $family, $key, $default = false) {
if(is_null($uid) || $uid === false)
return $default;
@@ -79,11 +91,10 @@ class PConfig {
if((! array_key_exists($family, \App::$config[$uid])) || (! array_key_exists($key, \App::$config[$uid][$family])))
return $default;
- return ((! is_array(\App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$uid][$family][$key]))
+ return ((! is_array(\App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$uid][$family][$key]))
? unserialize(\App::$config[$uid][$family][$key])
: \App::$config[$uid][$family][$key]
);
-
}
/**
@@ -102,12 +113,11 @@ class PConfig {
* The value to store
* @return mixed Stored $value or false
*/
-
static public function Set($uid, $family, $key, $value) {
- // this catches subtle errors where this function has been called
+ // this catches subtle errors where this function has been called
// with local_channel() when not logged in (which returns false)
- // and throws an error in array_key_exists below.
+ // and throws an error in array_key_exists below.
// we provide a function backtrace in the logs so that we can find
// and fix the calling function.
@@ -132,7 +142,6 @@ class PConfig {
dbesc($key),
dbesc($dbvalue)
);
-
}
else {
@@ -142,7 +151,6 @@ class PConfig {
dbesc($family),
dbesc($key)
);
-
}
// keep a separate copy for all variables which were
@@ -178,7 +186,6 @@ class PConfig {
* The configuration key to delete
* @return mixed
*/
-
static public function Delete($uid, $family, $key) {
if(is_null($uid) || $uid === false)
@@ -186,12 +193,12 @@ class PConfig {
$ret = false;
- if(array_key_exists($uid,\App::$config)
- && is_array(\App::$config['uid'])
- && array_key_exists($family,\App::$config['uid'])
+ if(array_key_exists($uid,\App::$config)
+ && is_array(\App::$config['uid'])
+ && array_key_exists($family,\App::$config['uid'])
&& array_key_exists($key, \App::$config[$uid][$family]))
unset(\App::$config[$uid][$family][$key]);
-
+
$ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
intval($uid),
dbesc($family),
@@ -202,4 +209,3 @@ class PConfig {
}
}
- \ No newline at end of file
diff --git a/Zotlabs/Lib/SConfig.php b/Zotlabs/Lib/SConfig.php
index ca0d133b2..ab6f49025 100644
--- a/Zotlabs/Lib/SConfig.php
+++ b/Zotlabs/Lib/SConfig.php
@@ -2,8 +2,11 @@
namespace Zotlabs\Lib;
-// account configuration storage is built on top of the under-utilised xconfig
-
+/**
+ * @brief Account configuration storage is built on top of the under-utilised xconfig.
+ *
+ * @see XConfig
+ */
class SConfig {
static public function Load($server_id) {
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index 67a507025..748edcdb7 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -38,7 +38,7 @@ class ThreadItem {
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
// Prepare the children
- if(count($data['children'])) {
+ if($data['children']) {
foreach($data['children'] as $item) {
/*
@@ -105,7 +105,17 @@ class ThreadItem {
$mode = $conv->get_mode();
- $edlink = (($item['item_type'] == ITEM_TYPE_CARD) ? 'card_edit' : 'editpost');
+ switch($item['item_type']) {
+ case ITEM_TYPE_CARD:
+ $edlink = 'card_edit';
+ break;
+ case ITEM_TYPE_ARTICLE:
+ $edlink = 'article_edit';
+ break;
+ default:
+ $edlink = 'editpost';
+ break;
+ }
if(local_channel() && $observer['xchan_hash'] === $item['author_xchan'])
$edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit'));
@@ -186,7 +196,7 @@ class ThreadItem {
$like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : '');
$like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : '');
- if (count($like_list) > MAX_LIKERS) {
+ if (($like_list) && (count($like_list) > MAX_LIKERS)) {
$like_list_part = array_slice($like_list, 0, MAX_LIKERS);
array_push($like_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
@@ -198,7 +208,7 @@ class ThreadItem {
$dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : '');
$dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : '');
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
- if (count($dislike_list) > MAX_LIKERS) {
+ if (($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
@@ -303,7 +313,7 @@ class ThreadItem {
$comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children );
$list_unseen_txt = (($unseen_comments) ? sprintf('%d unseen',$unseen_comments) : '');
-
+
@@ -360,6 +370,7 @@ class ThreadItem {
'unverified' => $unverified,
'forged' => $forged,
'location' => $location,
+ 'divider' => get_pconfig($conv->get_profile_owner(),'system','item_divider'),
'attend_label' => t('Attend'),
'attend_title' => t('Attendance Options'),
'vote_label' => t('Vote'),
diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php
index 436723f8c..d0c964149 100644
--- a/Zotlabs/Lib/ThreadStream.php
+++ b/Zotlabs/Lib/ThreadStream.php
@@ -54,6 +54,14 @@ class ThreadStream {
$this->profile_owner = local_channel();
$this->writable = true;
break;
+ case 'pubstream':
+ $this->profile_owner = local_channel();
+ $this->writable = ((local_channel()) ? true : false);
+ break;
+ case 'hq':
+ $this->profile_owner = local_channel();
+ $this->writable = true;
+ break;
case 'channel':
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
@@ -63,6 +71,11 @@ class ThreadStream {
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
$this->reload = $_SESSION['return_url'];
break;
+ case 'articles':
+ $this->profile_owner = \App::$profile['profile_uid'];
+ $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
+ $this->reload = $_SESSION['return_url'];
+ break;
case 'display':
// in this mode we set profile_owner after initialisation (from conversation()) and then
// pull some trickery which allows us to re-invoke this function afterward
@@ -179,6 +192,10 @@ class ThreadStream {
$item->set_commentable(can_comment_on_post($ob_hash,$item->data));
}
}
+ if($this->mode === 'pubstream' && (! local_channel())) {
+ $item->set_commentable(false);
+ }
+
require_once('include/channel.php');
$item->set_conversation($this);
diff --git a/Zotlabs/Lib/XConfig.php b/Zotlabs/Lib/XConfig.php
index bf78c360f..c5a108ac9 100644
--- a/Zotlabs/Lib/XConfig.php
+++ b/Zotlabs/Lib/XConfig.php
@@ -2,7 +2,26 @@
namespace Zotlabs\Lib;
-
+/**
+ * @brief Class for handling observer's config.
+ *
+ * <b>XConfig</b> is comparable to <i>PConfig</i>, except that it uses <i>xchan</i>
+ * (an observer hash) as an identifier.
+ *
+ * <b>XConfig</b> is used for observer specific configurations and takes a
+ * <i>xchan</i> as identifier.
+ * The storage is of size MEDIUMTEXT.
+ *
+ * @code{.php}$var = Zotlabs\Lib\XConfig::Get('xchan', 'category', 'key');
+ * // with default value for non existent key
+ * $var = Zotlabs\Lib\XConfig::Get('xchan', 'category', 'unsetkey', 'defaultvalue');@endcode
+ *
+ * The old (deprecated?) way to access a XConfig value is:
+ * @code{.php}$observer = App::get_observer_hash();
+ * if ($observer) {
+ * $var = get_xconfig($observer, 'category', 'key');
+ * }@endcode
+ */
class XConfig {
/**
@@ -15,7 +34,6 @@ class XConfig {
* The observer's hash
* @return void|false Returns false if xchan is not set
*/
-
static public function Load($xchan) {
if(! $xchan)
@@ -56,9 +74,9 @@ class XConfig {
* The category of the configuration value
* @param string $key
* The configuration key to query
+ * @param boolean $default (optional) default false
* @return mixed Stored $value or false if it does not exist
*/
-
static public function Get($xchan, $family, $key, $default = false) {
if(! $xchan)
@@ -70,7 +88,7 @@ class XConfig {
if((! array_key_exists($family, \App::$config[$xchan])) || (! array_key_exists($key, \App::$config[$xchan][$family])))
return $default;
- return ((! is_array(\App::$config[$xchan][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$xchan][$family][$key]))
+ return ((! is_array(\App::$config[$xchan][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', \App::$config[$xchan][$family][$key]))
? unserialize(\App::$config[$xchan][$family][$key])
: \App::$config[$xchan][$family][$key]
);
@@ -82,7 +100,6 @@ class XConfig {
* Stores a config value ($value) in the category ($family) under the key ($key)
* for the observer's $xchan hash.
*
- *
* @param string $xchan
* The observer's hash
* @param string $family
@@ -93,7 +110,6 @@ class XConfig {
* The value to store
* @return mixed Stored $value or false
*/
-
static public function Set($xchan, $family, $key, $value) {
// manage array value
@@ -106,7 +122,7 @@ class XConfig {
if(! array_key_exists($family, \App::$config[$xchan]))
\App::$config[$xchan][$family] = array();
- $ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' ) ",
+ $ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' )",
dbesc($xchan),
dbesc($family),
dbesc($key),
@@ -126,6 +142,7 @@ class XConfig {
if($ret)
return $value;
+
return $ret;
}
@@ -143,11 +160,11 @@ class XConfig {
* The configuration key to delete
* @return mixed
*/
-
static public function Delete($xchan, $family, $key) {
if(x(\App::$config[$xchan][$family], $key))
unset(\App::$config[$xchan][$family][$key]);
+
$ret = q("DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'",
dbesc($xchan),
dbesc($family),
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php
index e164875e8..ad1c8b8cd 100644
--- a/Zotlabs/Module/Acl.php
+++ b/Zotlabs/Module/Acl.php
@@ -176,11 +176,18 @@ class Acl extends \Zotlabs\Web\Controller {
$extra_channels_sql = " OR (abook_channel IN ($extra_channels_sql)) and abook_hidden = 0 ";
- // Add atokens belonging to the local channel @TODO restrict by search
+ // Add atokens belonging to the local channel
+
+ if($search) {
+ $sql_extra_atoken = "AND ( atoken_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . ") ";
+ }
+ else {
+ $sql_extra_atoken = '';
+ }
$r2 = null;
- $r1 = q("select * from atoken where atoken_uid = %d",
+ $r1 = q("select * from atoken where atoken_uid = %d $sql_extra_atoken",
intval(local_channel())
);
diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php
index d3d058c53..a9db1ad55 100644
--- a/Zotlabs/Module/Admin/Site.php
+++ b/Zotlabs/Module/Admin/Site.php
@@ -61,8 +61,10 @@ class Site {
$maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50);
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
- $techlevel_lock = ((x($_POST,'techlock')) ? intval($_POST['techlock']) : 0);
- $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
+ $techlevel_lock = ((x($_POST,'techlock')) ? intval($_POST['techlock']) : 0);
+ $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
+ $thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0);
+ $force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 300);
$techlevel = null;
if(array_key_exists('techlevel', $_POST))
@@ -84,7 +86,7 @@ class Site {
set_config('system', 'from_email', $from_email);
set_config('system', 'from_email_name' , $from_email_name);
set_config('system', 'imagick_convert_path' , $imagick_path);
-
+ set_config('system', 'thumbnail_security' , $thumbnail_security);
set_config('system', 'techlevel_lock', $techlevel_lock);
@@ -128,6 +130,7 @@ class Site {
set_config('system','allowed_sites', $allowed_sites);
set_config('system','publish_all', $force_publish);
set_config('system','disable_discover_tab', $disable_discover_tab);
+ set_config('system','force_queue_threshold', $force_queue);
if ($global_directory == '') {
del_config('system', 'directory_submit_url');
} else {
@@ -248,6 +251,7 @@ class Site {
);
$discover_tab = get_config('system','disable_discover_tab');
+
// $disable public streams by default
if($discover_tab === false)
$discover_tab = 1;
@@ -318,8 +322,10 @@ class Site {
'$timeout' => array('timeout', t("Network timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), t("Value is in seconds. Set to 0 for unlimited (not recommended).")),
'$delivery_interval' => array('delivery_interval', t("Delivery interval"), (x(get_config('system','delivery_interval'))?get_config('system','delivery_interval'):2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.")),
'$delivery_batch_count' => array('delivery_batch_count', t('Deliveries per process'),(x(get_config('system','delivery_batch_count'))?get_config('system','delivery_batch_count'):1), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.")),
+ '$force_queue' => array('force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',300), t("Always defer immediate delivery if queue contains more than this number of entries.")),
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
'$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
+ '$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$form_security_token' => get_form_security_token("admin_site"),
diff --git a/Zotlabs/Module/Appman.php b/Zotlabs/Module/Appman.php
index 5c0667357..64d4628ae 100644
--- a/Zotlabs/Module/Appman.php
+++ b/Zotlabs/Module/Appman.php
@@ -64,7 +64,11 @@ class Appman extends \Zotlabs\Web\Controller {
}
if($_POST['feature']) {
- Zlib\Apps::app_feature(local_channel(),$papp);
+ Zlib\Apps::app_feature(local_channel(), $papp, $_POST['feature']);
+ }
+
+ if($_POST['pin']) {
+ Zlib\Apps::app_feature(local_channel(), $papp, $_POST['pin']);
}
if($_SESSION['return_url'])
diff --git a/Zotlabs/Module/Apporder.php b/Zotlabs/Module/Apporder.php
index 956548d1f..a9f66ba69 100644
--- a/Zotlabs/Module/Apporder.php
+++ b/Zotlabs/Module/Apporder.php
@@ -18,7 +18,7 @@ class Apporder extends \Zotlabs\Web\Controller {
nav_set_selected('Order Apps');
$syslist = array();
- $list = Zlib\Apps::app_list(local_channel(), false, 'nav_featured_app');
+ $list = Zlib\Apps::app_list(local_channel(), false, ['nav_featured_app', 'nav_pinned_app']);
if($list) {
foreach($list as $li) {
$syslist[] = Zlib\Apps::app_encode($li);
@@ -31,14 +31,20 @@ class Apporder extends \Zotlabs\Web\Controller {
$syslist = Zlib\Apps::app_order(local_channel(),$syslist);
foreach($syslist as $app) {
- $nav_apps[] = Zlib\Apps::app_render($app,'nav-order');
+ if(strpos($app['categories'],'nav_pinned_app') !== false) {
+ $navbar_apps[] = Zlib\Apps::app_render($app,'nav-order');
+ }
+ else {
+ $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
+ '$header' => [t('Change Order of Pinned Navbar Apps'), t('Change Order of App Tray Apps')],
+ '$desc' => [t('Use arrows to move the corresponding app left (top) or right (bottom) in the navbar'), t('Use arrows to move the corresponding app up or down in the app tray')],
+ '$nav_apps' => $nav_apps,
+ '$navbar_apps' => $navbar_apps
]
);
}
diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php
index 2f61f2932..c672ea467 100644
--- a/Zotlabs/Module/Apps.php
+++ b/Zotlabs/Module/Apps.php
@@ -22,7 +22,8 @@ class Apps extends \Zotlabs\Web\Controller {
if(local_channel()) {
Zlib\Apps::import_system_apps();
$syslist = array();
- $list = Zlib\Apps::app_list(local_channel(), (($mode == 'edit') ? true : false), $_GET['cat']);
+ $cat = ((array_key_exists('cat',$_GET) && $_GET['cat']) ? [ escape_tags($_GET['cat']) ] : '');
+ $list = Zlib\Apps::app_list(local_channel(), (($mode == 'edit') ? true : false), $cat);
if($list) {
foreach($list as $x) {
$syslist[] = Zlib\Apps::app_encode($x);
@@ -43,7 +44,7 @@ class Apps extends \Zotlabs\Web\Controller {
return replace_macros(get_markup_template('myapps.tpl'), array(
'$sitename' => get_config('system','sitename'),
- '$cat' => ((array_key_exists('cat',$_GET) && $_GET['cat']) ? escape_tags($_GET['cat']) : ''),
+ '$cat' => $cat,
'$title' => t('Apps'),
'$apps' => $apps,
'$authed' => ((local_channel()) ? true : false),
diff --git a/Zotlabs/Module/Article_edit.php b/Zotlabs/Module/Article_edit.php
new file mode 100644
index 000000000..758c1db2e
--- /dev/null
+++ b/Zotlabs/Module/Article_edit.php
@@ -0,0 +1,138 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/channel.php');
+require_once('include/acl_selectors.php');
+require_once('include/conversation.php');
+
+class Article_edit extends \Zotlabs\Web\Controller {
+
+
+ function get() {
+
+ // Figure out which post we're editing
+ $post_id = ((argc() > 1) ? intval(argv(1)) : 0);
+
+ if(! $post_id) {
+ notice( t('Item not found') . EOL);
+ return;
+ }
+
+ $itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1",
+ intval($post_id),
+ intval(ITEM_TYPE_ARTICLE)
+ );
+ if($itm) {
+ $item_id = q("select * from iconfig where cat = 'system' and k = 'ARTICLE' and iid = %d limit 1",
+ intval($itm[0]['id'])
+ );
+ if($item_id)
+ $card_title = $item_id[0]['v'];
+ }
+ else {
+ notice( t('Item not found') . EOL);
+ return;
+ }
+
+ $owner = $itm[0]['uid'];
+ $uid = local_channel();
+
+ $observer = \App::get_observer();
+
+ $channel = channelx_by_n($owner);
+ if(! $channel) {
+ notice( t('Channel not found.') . EOL);
+ return;
+ }
+
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ if(! perm_is_allowed($owner,$ob_hash,'write_pages')) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ $is_owner = (($uid && $uid == $owner) ? true : false);
+
+ $o = '';
+
+
+
+ $category = '';
+ $catsenabled = ((feature_enabled($owner,'categories')) ? 'categories' : '');
+
+ if ($catsenabled){
+ $itm = fetch_post_tags($itm);
+
+ $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
+
+ foreach ($cats as $cat) {
+ if (strlen($category))
+ $category .= ', ';
+ $category .= $cat['term'];
+ }
+ }
+
+ if($itm[0]['attach']) {
+ $j = json_decode($itm[0]['attach'],true);
+ if($j) {
+ foreach($j as $jj) {
+ $itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n";
+ }
+ }
+ }
+
+
+ $mimetype = $itm[0]['mimetype'];
+
+ $content = $itm[0]['body'];
+
+
+
+ $rp = 'articles/' . $channel['channel_address'];
+
+ $x = array(
+ 'nickname' => $channel['channel_address'],
+ 'bbco_autocomplete'=> 'bbcode',
+ 'return_path' => $rp,
+ 'webpage' => ITEM_TYPE_ARTICLE,
+ 'button' => t('Edit'),
+ 'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'),
+ 'weblink' => t('Insert web link'),
+ 'hide_voting' => false,
+ 'hide_future' => false,
+ 'hide_location' => false,
+ 'hide_expire' => false,
+ 'showacl' => true,
+ 'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
+ 'permissions' => $itm[0],
+ 'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'),
+ 'ptyp' => $itm[0]['type'],
+ 'mimeselect' => false,
+ 'mimetype' => $itm[0]['mimetype'],
+ 'body' => undo_post_tagging($content),
+ 'post_id' => $post_id,
+ 'visitor' => true,
+ 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
+ 'placeholdertitle' => t('Title (optional)'),
+ 'pagetitle' => $card_title,
+ 'profile_uid' => (intval($channel['channel_id'])),
+ 'catsenabled' => $catsenabled,
+ 'category' => $category,
+ 'bbcode' => (($mimetype == 'text/bbcode') ? true : false)
+ );
+
+ $editor = status_editor($a, $x);
+
+ $o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
+ '$title' => t('Edit Article'),
+ '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
+ '$id' => $itm[0]['id'],
+ '$editor' => $editor
+ ));
+
+ return $o;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Articles.php b/Zotlabs/Module/Articles.php
new file mode 100644
index 000000000..25daca81d
--- /dev/null
+++ b/Zotlabs/Module/Articles.php
@@ -0,0 +1,187 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/channel.php');
+require_once('include/conversation.php');
+require_once('include/acl_selectors.php');
+
+
+class Articles extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ if(argc() > 1)
+ $which = argv(1);
+ else
+ return;
+
+ profile_load($which);
+
+ }
+
+ function get($update = 0, $load = false) {
+
+ if(observer_prohibited(true)) {
+ return login();
+ }
+
+ if(! \App::$profile) {
+ notice( t('Requested profile is not available.') . EOL );
+ \App::$error = 404;
+ return;
+ }
+
+ if(! feature_enabled(\App::$profile_uid,'articles')) {
+ return;
+ }
+
+ nav_set_selected(t('Cards'));
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
+
+
+ $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : '');
+
+ if($category) {
+ $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
+ }
+
+
+ $which = argv(1);
+
+ $selected_card = ((argc() > 2) ? argv(2) : '');
+
+ $_SESSION['return_url'] = \App::$query_string;
+
+ $uid = local_channel();
+ $owner = \App::$profile_uid;
+ $observer = \App::get_observer();
+
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ if(! perm_is_allowed($owner,$ob_hash,'view_pages')) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ $is_owner = ($uid && $uid == $owner);
+
+ $channel = channelx_by_n($owner);
+
+ if($channel) {
+ $channel_acl = array(
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
+ );
+ }
+ else {
+ $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
+ }
+
+
+
+ if(perm_is_allowed($owner,$ob_hash,'write_pages')) {
+
+ $x = [
+ 'webpage' => ITEM_TYPE_ARTICLE,
+ 'is_owner' => true,
+ 'content_label' => t('Add Article'),
+ 'button' => t('Create'),
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
+ || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
+ 'acl' => (($is_owner) ? populate_acl($channel_acl, false,
+ \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')) : ''),
+ 'permissions' => $channel_acl,
+ 'showacl' => (($is_owner) ? true : false),
+ 'visitor' => true,
+ 'hide_location' => false,
+ 'hide_voting' => false,
+ 'profile_uid' => intval($owner),
+ 'mimetype' => 'text/bbcode',
+ 'mimeselect' => false,
+ 'layoutselect' => false,
+ 'expanded' => false,
+ 'novoting' => false,
+ 'catsenabled' => feature_enabled($owner,'categories'),
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true
+ ];
+
+ if($_REQUEST['title'])
+ $x['title'] = $_REQUEST['title'];
+ if($_REQUEST['body'])
+ $x['body'] = $_REQUEST['body'];
+ $editor = status_editor($a,$x);
+
+ }
+ else {
+ $editor = '';
+ }
+
+
+ $sql_extra = item_permissions_sql($owner);
+
+ if($selected_card) {
+ $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.v = '%s' limit 1",
+ dbesc($selected_card)
+ );
+ if($r) {
+ $sql_extra .= "and item.id = " . intval($r[0]['iid']) . " ";
+ }
+ }
+
+ $r = q("select * from item
+ where item.uid = %d and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($owner),
+ intval(ITEM_TYPE_ARTICLE)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type in (0,7) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ if($r) {
+
+ $parents_str = ids_to_querystr($r,'id');
+
+ $items = q("SELECT item.*, item.id AS item_id
+ FROM item
+ WHERE item.uid = %d $item_normal
+ AND item.parent IN ( %s )
+ $sql_extra $sql_extra2 ",
+ intval(\App::$profile['profile_uid']),
+ dbesc($parents_str)
+ );
+ if($items) {
+ xchan_query($items);
+ $items = fetch_post_tags($items, true);
+ $items = conv_sort($items,'updated');
+ }
+ else
+ $items = [];
+ }
+
+ $mode = 'articles';
+
+ $content = conversation($items,$mode,false,'traditional');
+
+ $o = replace_macros(get_markup_template('cards.tpl'), [
+ '$title' => t('Articles'),
+ '$editor' => $editor,
+ '$content' => $content,
+ '$pager' => alt_pager($a,count($items))
+ ]);
+
+ return $o;
+ }
+
+}
diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php
index 91d279f7a..6737ac4ee 100644
--- a/Zotlabs/Module/Cdav.php
+++ b/Zotlabs/Module/Cdav.php
@@ -39,7 +39,7 @@ class Cdav extends \Zotlabs\Web\Controller {
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) {
- $keyId = $sigblock['keyId'];
+ $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) {
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
dbesc($keyId)
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index 14d02d873..7c4c900a1 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -332,6 +332,7 @@ class Channel extends \Zotlabs\Web\Controller {
'$tags' => (($hashtags) ? urlencode($hashtags) : ''),
'$mid' => $mid,
'$verb' => '',
+ '$net' => '',
'$dend' => $datequery,
'$dbegin' => $datequery2
));
diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php
index 75191a279..2215507ca 100644
--- a/Zotlabs/Module/Cloud.php
+++ b/Zotlabs/Module/Cloud.php
@@ -57,12 +57,12 @@ class Cloud extends \Zotlabs\Web\Controller {
$auth->observer = $ob_hash;
}
+ // if we arrived at this path with any query parameters in the url, build a clean url without
+ // them and redirect.
- $_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']);
- $_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']);
-
- $_SERVER['REQUEST_URI'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['REQUEST_URI']);
- $_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']);
+ $x = clean_query_string();
+ if($x !== \App::$query_string)
+ goaway(z_root() . '/' . $x);
$rootDirectory = new \Zotlabs\Storage\Directory('/', $auth);
@@ -83,17 +83,42 @@ class Cloud extends \Zotlabs\Web\Controller {
$server->addPlugin($browser);
// Experimental QuotaPlugin
- // require_once('\Zotlabs\Storage/QuotaPlugin.php');
- // $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth));
+ // require_once('\Zotlabs\Storage/QuotaPlugin.php');
+ // $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth));
+
+
+ // over-ride the default XML output on thrown exceptions
+
+ $server->on('exception', [ $this, 'DAVException' ]);
-// ob_start();
// All we need to do now, is to fire up the server
+
$server->exec();
-// ob_end_flush();
if($browser->build_page)
construct_page();
+
+ killme();
+ }
+
+
+ function DAVException($err) {
+
+ if($err instanceof \Sabre\DAV\Exception\NotFound) {
+ notice( t('Not found') . EOL);
+ }
+ elseif($err instanceof \Sabre\DAV\Exception\Forbidden) {
+ notice( t('Permission denied') . EOL);
+ }
+ else {
+ notice( t('Unknown error') . EOL);
+ }
+
+ construct_page();
+
killme();
}
}
+
+
diff --git a/Zotlabs/Module/Cloud_tiles.php b/Zotlabs/Module/Cloud_tiles.php
new file mode 100644
index 000000000..da551904f
--- /dev/null
+++ b/Zotlabs/Module/Cloud_tiles.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Zotlabs\Module;
+
+class Cloud_tiles extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ if(intval($_SESSION['cloud_tiles']))
+ $_SESSION['cloud_tiles'] = 0;
+ else
+ $_SESSION['cloud_tiles'] = 1;
+
+ if(local_channel()) {
+ set_pconfig(local_channel(),'system','cloud_tiles',$_SESSION['cloud_tiles']);
+ }
+
+ goaway(z_root() . '/' . hex2bin(argv(1)));
+
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php
index 23c5282e3..e0511b0d3 100644
--- a/Zotlabs/Module/Connedit.php
+++ b/Zotlabs/Module/Connedit.php
@@ -567,7 +567,7 @@ class Connedit extends \Zotlabs\Web\Controller {
$contact_id = \App::$poi['abook_id'];
$contact = \App::$poi;
- $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 order by xchan_name",
+ $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name",
intval(local_channel())
);
diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php
index d506fe9f5..9f64e2fea 100644
--- a/Zotlabs/Module/Dav.php
+++ b/Zotlabs/Module/Dav.php
@@ -48,7 +48,7 @@ class Dav extends \Zotlabs\Web\Controller {
$sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
if($sigblock) {
- $keyId = $sigblock['keyId'];
+ $keyId = str_replace('acct:','',$sigblock['keyId']);
if($keyId) {
$r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
dbesc($keyId)
diff --git a/Zotlabs/Module/Defperms.php b/Zotlabs/Module/Defperms.php
new file mode 100644
index 000000000..9214331e4
--- /dev/null
+++ b/Zotlabs/Module/Defperms.php
@@ -0,0 +1,267 @@
+<?php
+namespace Zotlabs\Module;
+
+
+require_once('include/socgraph.php');
+require_once('include/selectors.php');
+require_once('include/group.php');
+require_once('include/photos.php');
+
+
+class Defperms extends \Zotlabs\Web\Controller {
+
+ /* @brief Initialize the connection-editor
+ *
+ *
+ */
+
+ function init() {
+
+ if(! local_channel())
+ return;
+
+ $r = q("SELECT abook.*, xchan.*
+ FROM abook left join xchan on abook_xchan = xchan_hash
+ WHERE abook_self = 1 and abook_id = %d LIMIT 1",
+ intval(local_channel())
+ );
+ if($r) {
+ \App::$poi = $r[0];
+ }
+
+ $channel = \App::get_channel();
+ if($channel)
+ head_set_icon($channel['xchan_photo_s']);
+ }
+
+
+ /* @brief Evaluate posted values and set changes
+ *
+ */
+
+ function post() {
+
+ if(! local_channel())
+ return;
+
+ $contact_id = intval(argv(1));
+ if(! $contact_id)
+ return;
+
+ $channel = \App::get_channel();
+
+ $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1",
+ intval($contact_id),
+ intval(local_channel())
+ );
+
+ if(! $orig_record) {
+ notice( t('Could not access contact record.') . EOL);
+ goaway(z_root() . '/connections');
+ return; // NOTREACHED
+ }
+
+
+ if(intval($orig_record[0]['abook_self'])) {
+ $autoperms = intval($_POST['autoperms']);
+ $is_self = true;
+ }
+ else {
+ $autoperms = null;
+ $is_self = false;
+ }
+
+
+ $all_perms = \Zotlabs\Access\Permissions::Perms();
+
+ if($all_perms) {
+ foreach($all_perms as $perm => $desc) {
+
+ $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$perm);
+ $inherited = (($checkinherited & PERMS_SPECIFIC) ? false : true);
+
+ if(array_key_exists('perms_' . $perm, $_POST)) {
+ set_abconfig($channel['channel_id'],$orig_record[0]['abook_xchan'],'my_perms',$perm,
+ intval($_POST['perms_' . $perm]));
+ if($autoperms) {
+ set_pconfig($channel['channel_id'],'autoperms',$perm,intval($_POST['perms_' . $perm]));
+ }
+ }
+ else {
+ set_abconfig($channel['channel_id'],$orig_record[0]['abook_xchan'],'my_perms',$perm,0);
+ if($autoperms) {
+ set_pconfig($channel['channel_id'],'autoperms',$perm,0);
+ }
+ }
+ }
+ }
+
+ if(! is_null($autoperms))
+ set_pconfig($channel['channel_id'],'system','autoperms',$autoperms);
+
+
+ notice( t('Settings updated.') . EOL);
+
+
+ // Refresh the structure in memory with the new data
+
+ $r = q("SELECT abook.*, xchan.*
+ FROM abook left join xchan on abook_xchan = xchan_hash
+ WHERE abook_channel = %d and abook_id = %d LIMIT 1",
+ intval(local_channel()),
+ intval($contact_id)
+ );
+ if($r) {
+ \App::$poi = $r[0];
+ }
+
+
+ $this->defperms_clone($a);
+
+ goaway(z_root() . '/defperms');
+
+ return;
+
+ }
+
+ /* @brief Clone connection
+ *
+ *
+ */
+
+ function defperms_clone(&$a) {
+
+ if(! \App::$poi)
+ return;
+
+ $channel = \App::get_channel();
+
+ $r = q("SELECT abook.*, xchan.*
+ FROM abook left join xchan on abook_xchan = xchan_hash
+ WHERE abook_channel = %d and abook_id = %d LIMIT 1",
+ intval(local_channel()),
+ intval(\App::$poi['abook_id'])
+ );
+ if($r) {
+ \App::$poi = array_shift($r);
+ }
+
+ $clone = \App::$poi;
+
+ unset($clone['abook_id']);
+ unset($clone['abook_account']);
+ unset($clone['abook_channel']);
+
+ $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
+ if($abconfig)
+ $clone['abconfig'] = $abconfig;
+
+ build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
+ }
+
+ /* @brief Generate content of connection default permissions page
+ *
+ *
+ */
+
+ function get() {
+
+ $sort_type = 0;
+ $o = '';
+
+ if(! local_channel()) {
+ notice( t('Permission denied.') . EOL);
+ return login();
+ }
+
+ $section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : '');
+ $channel = \App::get_channel();
+
+ $yes_no = array(t('No'),t('Yes'));
+
+ $connect_perms = \Zotlabs\Access\Permissions::connect_perms(local_channel());
+
+ $o .= "<script>function connectDefaultShare() {
+ \$('.abook-edit-me').each(function() {
+ if(! $(this).is(':disabled'))
+ $(this).prop('checked', false);
+ });\n\n";
+ foreach($connect_perms['perms'] as $p => $v) {
+ if($v) {
+ $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n";
+ }
+ }
+ $o .= " }\n</script>\n";
+
+ if(\App::$poi) {
+
+ $sections = [];
+
+ $self = false;
+
+ $tpl = get_markup_template('defperms.tpl');
+
+
+ $perms = array();
+ $channel = \App::get_channel();
+
+ $contact = \App::$poi;
+
+ $global_perms = \Zotlabs\Access\Permissions::Perms();
+
+ $existing = get_all_perms(local_channel(),$contact['abook_xchan']);
+ $hidden_perms = [];
+
+ foreach($global_perms as $k => $v) {
+ $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k);
+
+ $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k);
+
+ $inherited = (($checkinherited & PERMS_SPECIFIC) ? false : true);
+
+ $perms[] = [ 'perms_' . $k, $v, intval($thisperm), '', $yes_no, (($inherited) ? ' disabled="disabled" ' : '') ];
+ if($inherited) {
+ $hidden_perms[] = [ 'perms_' . $k, intval($thisperm) ];
+ }
+ }
+
+ $pcat = new \Zotlabs\Lib\Permcat(local_channel());
+ $pcatlist = $pcat->listing();
+ $permcats = [];
+ if($pcatlist) {
+ foreach($pcatlist as $pc) {
+ $permcats[$pc['name']] = $pc['localname'];
+ }
+ }
+
+ $o .= replace_macros($tpl, [
+ '$header' => t('Connection Default Permissions'),
+ '$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no),
+ '$permcat' => [ 'permcat', t('Permission role'), '', '',$permcats ],
+ '$permcat_new' => t('Add permission role'),
+ '$permcat_enable' => feature_enabled(local_channel(),'permcats'),
+ '$section' => $section,
+ '$sections' => $sections,
+ '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'),
+ '$autoapprove' => t('Automatic approval settings'),
+ '$unapproved' => $unapproved,
+ '$inherited' => t('inherited'),
+ '$submit' => t('Submit'),
+ '$me' => t('My Settings'),
+ '$perms' => $perms,
+ '$hidden_perms' => $hidden_perms,
+ '$permlbl' => t('Individual Permissions'),
+ '$permnote_self' => t('Some individual permissions may have been preset or locked based on your channel type and privacy settings.'),
+ '$contact_id' => $contact['abook_id'],
+ '$name' => $contact['xchan_name'],
+ ]);
+
+ $arr = array('contact' => $contact,'output' => $o);
+
+ call_hooks('contact_edit', $arr);
+
+ return $arr['output'];
+
+ }
+ }
+}
diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php
index caf0190ae..b1552a694 100644
--- a/Zotlabs/Module/Directory.php
+++ b/Zotlabs/Module/Directory.php
@@ -64,6 +64,11 @@ class Directory extends \Zotlabs\Web\Controller {
return;
}
+ if(get_config('system','block_public_directory',false) && (! get_observer_hash())) {
+ notice( t('Public access denied.') . EOL);
+ return;
+ }
+
$observer = get_observer_hash();
$globaldir = get_directory_setting($observer, 'globaldir');
@@ -102,7 +107,7 @@ class Directory extends \Zotlabs\Web\Controller {
$common = array();
$index = 0;
foreach($r as $rr) {
- $common[$rr['xchan_addr']] = $rr['total'];
+ $common[$rr['xchan_addr']] = ((intval($rr['total']) > 0) ? intval($rr['total']) - 1 : 0);
$addresses[$rr['xchan_addr']] = $index++;
}
@@ -334,7 +339,7 @@ class Directory extends \Zotlabs\Web\Controller {
'ignlink' => $suggest ? z_root() . '/directory?ignore=' . $rr['hash'] : '',
'ignore_label' => t('Don\'t suggest'),
'common_friends' => (($common[$rr['address']]) ? intval($common[$rr['address']]) : ''),
- 'common_label' => t('Common connections:'),
+ 'common_label' => t('Common connections (estimated):'),
'common_count' => intval($common[$rr['address']]),
'safe' => $safe_mode
);
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index d5afdd787..6d895feb5 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -12,6 +12,15 @@ class Display extends \Zotlabs\Web\Controller {
function get($update = 0, $load = false) {
+ $module_format = 'html';
+
+
+ if(argc() > 1) {
+ $module_format = substr(argv(1),strrpos(argv(1),'.') + 1);
+ if(! in_array($module_format,['atom','zot','json']))
+ $module_format = 'html';
+ }
+
$checkjs = new \Zotlabs\Web\CheckJS(1);
if($load)
@@ -22,8 +31,12 @@ class Display extends \Zotlabs\Web\Controller {
return;
}
- if(argc() > 1 && argv(1) !== 'load')
+ if(argc() > 1) {
$item_hash = argv(1);
+ if($module_format !== 'html') {
+ $item_hash = substr($item_hash,0,strrpos($item_hash,'.'));
+ }
+ }
if($_REQUEST['mid'])
$item_hash = $_REQUEST['mid'];
@@ -44,28 +57,28 @@ class Display extends \Zotlabs\Web\Controller {
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
- 'deny_cid' => $channel['channel_deny_cid'],
- 'deny_gid' => $channel['channel_deny_gid']
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
);
$x = array(
- 'is_owner' => true,
- 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
- 'default_location' => $channel['channel_location'],
- 'nickname' => $channel['channel_address'],
- 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
+ 'is_owner' => true,
+ 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
+ 'default_location' => $channel['channel_location'],
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
- 'acl' => populate_acl($channel_acl),
- 'permissions' => $channel_acl,
- 'bang' => '',
- 'visitor' => true,
- 'profile_uid' => local_channel(),
- 'return_path' => 'channel/' . $channel['channel_address'],
- 'expanded' => true,
+ 'acl' => populate_acl($channel_acl),
+ 'permissions' => $channel_acl,
+ 'bang' => '',
+ 'visitor' => true,
+ 'profile_uid' => local_channel(),
+ 'return_path' => 'channel/' . $channel['channel_address'],
+ 'expanded' => true,
'editor_autocomplete' => true,
- 'bbco_autocomplete' => 'bbcode',
- 'bbcode' => true,
- 'jotnets' => true
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true,
+ 'jotnets' => true
);
$o = '<div id="jot-popup">';
@@ -139,10 +152,11 @@ class Display extends \Zotlabs\Web\Controller {
$static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1);
- //if the target item is not a post (eg a like) we want to address its thread parent
+ // if the target item is not a post (eg a like) we want to address its thread parent
+
$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
- //if we got a decoded hash we must encode it again before handing to javascript
+ // if we got a decoded hash we must encode it again before handing to javascript
if($decoded)
$mid = 'b64.' . base64url_encode($mid);
@@ -152,32 +166,33 @@ class Display extends \Zotlabs\Web\Controller {
\App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
'$baseurl' => z_root(),
- '$pgtype' => 'display',
- '$uid' => '0',
- '$gid' => '0',
- '$cid' => '0',
- '$cmin' => '0',
- '$cmax' => '99',
- '$star' => '0',
- '$liked' => '0',
- '$conv' => '0',
- '$spam' => '0',
- '$fh' => '0',
+ '$pgtype' => 'display',
+ '$uid' => '0',
+ '$gid' => '0',
+ '$cid' => '0',
+ '$cmin' => '0',
+ '$cmax' => '99',
+ '$star' => '0',
+ '$liked' => '0',
+ '$conv' => '0',
+ '$spam' => '0',
+ '$fh' => '0',
'$nouveau' => '0',
- '$wall' => '0',
- '$static' => $static,
- '$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
- '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
- '$search' => '',
- '$xchan' => '',
- '$order' => '',
- '$file' => '',
- '$cats' => '',
- '$tags' => '',
- '$dend' => '',
- '$dbegin' => '',
- '$verb' => '',
- '$mid' => $mid
+ '$wall' => '0',
+ '$static' => $static,
+ '$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
+ '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
+ '$search' => '',
+ '$xchan' => '',
+ '$order' => '',
+ '$file' => '',
+ '$cats' => '',
+ '$tags' => '',
+ '$dend' => '',
+ '$dbegin' => '',
+ '$verb' => '',
+ '$net' => '',
+ '$mid' => $mid
));
head_add_link([
@@ -195,11 +210,11 @@ class Display extends \Zotlabs\Web\Controller {
$sql_extra = public_permissions_sql($observer_hash);
- if(($update && $load) || ($checkjs->disabled())) {
+ if(($update && $load) || ($checkjs->disabled()) || ($module_format !== 'html')) {
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']),intval(\App::$pager['start']));
- if($load || ($checkjs->disabled())) {
+ if($load || ($checkjs->disabled()) || ($module_format !== 'html')) {
$r = null;
require_once('include/channel.php');
@@ -246,7 +261,7 @@ class Display extends \Zotlabs\Web\Controller {
elseif($update && !$load) {
$r = null;
-
+
require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
@@ -271,7 +286,6 @@ class Display extends \Zotlabs\Web\Controller {
// make that content unsearchable by ensuring the owner_xchan can't match
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
$sysid = 0;
-
$r = q("SELECT item.parent AS item_id from item
WHERE parent_mid = '%s'
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
@@ -301,7 +315,6 @@ class Display extends \Zotlabs\Web\Controller {
WHERE parent in ( %s ) $item_normal ",
dbesc($parents_str)
);
-
xchan_query($items);
$items = fetch_post_tags($items,true);
$items = conv_sort($items,'created');
@@ -311,13 +324,61 @@ class Display extends \Zotlabs\Web\Controller {
$items = array();
}
- if ($checkjs->disabled()) {
- $o .= conversation($items, 'display', $update, 'traditional');
- if ($items[0]['title'])
- \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title'];
- }
- else {
- $o .= conversation($items, 'display', $update, 'client');
+
+ switch($module_format) {
+
+ case 'html':
+
+ if ($checkjs->disabled()) {
+ $o .= conversation($items, 'display', $update, 'traditional');
+ if ($items[0]['title'])
+ \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title'];
+ }
+ else {
+ $o .= conversation($items, 'display', $update, 'client');
+ }
+
+ break;
+
+ case 'atom':
+
+ $atom = replace_macros(get_markup_template('atom_feed.tpl'), array(
+ '$version' => xmlify(\Zotlabs\Lib\System::get_project_version()),
+ '$red' => xmlify(\Zotlabs\Lib\System::get_platform_name()),
+ '$feed_id' => xmlify(\App::$cmd),
+ '$feed_title' => xmlify(t('Article')),
+ '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)),
+ '$author' => '',
+ '$owner' => '',
+ '$profile_page' => xmlify(z_root() . '/display/' . $target_item['mid']),
+ ));
+
+ $x = [ 'xml' => $atom, 'channel' => $channel, 'observer_hash' => $observer_hash, 'params' => $params ];
+ call_hooks('atom_feed_top',$x);
+
+ $atom = $x['xml'];
+
+ // a much simpler interface
+ call_hooks('atom_feed', $atom);
+
+
+ if($items) {
+ $type = 'html';
+ foreach($items as $item) {
+ if($item['item_private'])
+ continue;
+ $atom .= atom_entry($item, $type, null, '', true, '', false);
+ }
+ }
+
+ call_hooks('atom_feed_end', $atom);
+
+ $atom .= '</feed>' . "\r\n";
+
+ header('Content-type: application/atom+xml');
+ echo $atom;
+ killme();
+
}
if($updateable) {
diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php
index c92af27d6..15cc68d7f 100644
--- a/Zotlabs/Module/Embedphotos.php
+++ b/Zotlabs/Module/Embedphotos.php
@@ -83,7 +83,7 @@ class Embedphotos extends \Zotlabs\Web\Controller {
return '';
if($args['album'])
- $album = $args['album'];
+ $album = (($args['album'] === '/') ? '' : $args['album']);
if($args['title'])
$title = $args['title'];
diff --git a/Zotlabs/Module/Feed.php b/Zotlabs/Module/Feed.php
index 06637b6d2..36869abbe 100644
--- a/Zotlabs/Module/Feed.php
+++ b/Zotlabs/Module/Feed.php
@@ -16,12 +16,15 @@ class Feed extends \Zotlabs\Web\Controller {
$params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
- $params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
- $params['records'] = ((x($params,'records')) ? intval($params['records']) : 40);
- $params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
+ $params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
+ $params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 40);
+ $params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0);
+ if(! in_array($params['direction'],['asc','desc'])) {
+ $params['direction'] = 'desc';
+ }
if(argc() > 1) {
diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php
index 5c4b9a502..4d1cc4cda 100644
--- a/Zotlabs/Module/File_upload.php
+++ b/Zotlabs/Module/File_upload.php
@@ -10,7 +10,8 @@ class File_upload extends \Zotlabs\Web\Controller {
function post() {
- // logger('file upload: ' . print_r($_REQUEST,true));
+ logger('file upload: ' . print_r($_REQUEST,true));
+ logger('file upload: ' . print_r($_FILES,true));
$channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null);
@@ -30,8 +31,8 @@ class File_upload extends \Zotlabs\Web\Controller {
$_REQUEST['allow_cid'] = perms2str($_REQUEST['contact_allow']);
$_REQUEST['allow_gid'] = perms2str($_REQUEST['group_allow']);
- $_REQUEST['deny_cid'] = perms2str($_REQUEST['contact_deny']);
- $_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']);
+ $_REQUEST['deny_cid'] = perms2str($_REQUEST['contact_deny']);
+ $_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']);
if($_REQUEST['filename']) {
$r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
@@ -47,6 +48,51 @@ class File_upload extends \Zotlabs\Web\Controller {
}
}
else {
+
+ $matches = [];
+ $partial = false;
+
+
+
+ if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
+ $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
+ if($pm) {
+ logger('Content-Range: ' . print_r($matches,true));
+ $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']
+ ];
+ }
+ }
+
$r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
if($r['success']) {
$sync = attach_export_data($channel,$r['data']['hash']);
diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php
index 55713027a..5c8557e5a 100644
--- a/Zotlabs/Module/Filestorage.php
+++ b/Zotlabs/Module/Filestorage.php
@@ -103,6 +103,11 @@ class Filestorage extends \Zotlabs\Web\Controller {
attach_delete($owner, $f['hash']);
+ $sync = attach_export_data($channel, $f['hash'], true);
+ if($sync) {
+ build_sync_packet($channel['channel_id'], array('file' => array($sync)));
+ }
+
goaway(dirname($url));
}
diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php
index 413a68e0c..abc9f50d9 100644
--- a/Zotlabs/Module/Getfile.php
+++ b/Zotlabs/Module/Getfile.php
@@ -28,17 +28,51 @@ class Getfile extends \Zotlabs\Web\Controller {
function post() {
- logger('post: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO);
-
+ $header_verified = false;
+
$hash = $_POST['hash'];
$time = $_POST['time'];
$sig = $_POST['signature'];
$resource = $_POST['resource'];
$revision = intval($_POST['revision']);
$resolution = (-1);
-
+
if(! $hash)
killme();
+
+ foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+ if($head !== 'HTTP_AUTHORIZATION') {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
+ continue;
+ }
+
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+
+ if($keyId) {
+ $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
+ where hubloc_addr = '%s' limit 1",
+ dbesc(str_replace('acct:','',$keyId))
+ );
+ if($r) {
+ $hubloc = $r[0];
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
+ if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) {
+ $header_verified = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ logger('post: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO);
+ if($header_verified) {
+ logger('HTTPSig verified');
+ }
$channel = channelx_by_hash($hash);
@@ -59,16 +93,17 @@ class Getfile extends \Zotlabs\Web\Controller {
$d1 = datetime_convert('UTC','UTC',"now + $slop minutes");
$d2 = datetime_convert('UTC','UTC',"now - $slop minutes");
- if(($time > $d1) || ($time < $d2)) {
- logger('time outside allowable range');
- killme();
- }
+ if(! $header_verified) {
+ if(($time > $d1) || ($time < $d2)) {
+ logger('time outside allowable range');
+ killme();
+ }
- if(! rsa_verify($hash . '.' . $time,base64url_decode($sig),$channel['channel_pubkey'])) {
- logger('verify failed.');
- killme();
+ if(! rsa_verify($hash . '.' . $time,base64url_decode($sig),$channel['channel_pubkey'])) {
+ logger('verify failed.');
+ killme();
+ }
}
-
if($resolution > 0) {
$r = q("select * from photo where resource_id = '%s' and uid = %d limit 1",
diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php
new file mode 100644
index 000000000..1e46a6353
--- /dev/null
+++ b/Zotlabs/Module/Hq.php
@@ -0,0 +1,301 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once("include/bbcode.php");
+require_once('include/security.php');
+require_once('include/conversation.php');
+require_once('include/acl_selectors.php');
+require_once('include/items.php');
+
+
+class Hq extends \Zotlabs\Web\Controller {
+
+ function init() {
+ if(! local_channel())
+ return;
+
+ \App::$profile_uid = local_channel();
+ }
+
+ function post() {
+
+ if(!local_channel())
+ return;
+
+ if($_REQUEST['notify_id']) {
+ q("update notify set seen = 1 where id = %d and uid = %d",
+ intval($_REQUEST['notify_id']),
+ intval(local_channel())
+ );
+ }
+
+ }
+
+ function get($update = 0, $load = false) {
+
+ if(!local_channel())
+ return;
+
+ if($load)
+ $_SESSION['loadtime'] = datetime_convert();
+
+ if(argc() > 1 && argv(1) !== 'load') {
+ $item_hash = argv(1);
+ }
+
+ if($_REQUEST['mid'])
+ $item_hash = $_REQUEST['mid'];
+
+ $item_normal = item_normal();
+ $item_normal_update = item_normal_update();
+
+ if(! $item_hash) {
+ $r = q("SELECT mid FROM item
+ WHERE uid = %d
+ AND mid = parent_mid
+ ORDER BY created DESC LIMIT 1",
+ intval(local_channel())
+ );
+
+ if($r[0]['mid']) {
+ $item_hash = 'b64.' . base64url_encode($r[0]['mid']);
+ }
+ }
+
+ if($item_hash) {
+
+ if(strpos($item_hash,'b64.') === 0)
+ $decoded = @base64url_decode(substr($item_hash,4));
+
+ if($decoded)
+ $item_hash = $decoded;
+
+ $target_item = null;
+
+ $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1",
+ dbesc($item_hash . '%')
+ );
+
+ if($r) {
+ $target_item = $r[0];
+ }
+
+ //if the item is to be moderated redirect to /moderate
+ if($target_item['item_blocked'] == ITEM_MODERATED) {
+ goaway(z_root() . '/moderate/' . $target_item['id']);
+ }
+
+ $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
+
+ $simple_update = (($update) ? " AND item_unseen = 1 " : '');
+
+ if($update && $_SESSION['loadtime'])
+ $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
+
+ if($static && $simple_update)
+ $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
+
+ $sys = get_sys_channel();
+ $sql_extra = item_permissions_sql($sys['channel_id']);
+
+ $sys_item = false;
+
+ }
+
+ if(! $update) {
+ $channel = \App::get_channel();
+
+ $channel_acl = [
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
+ ];
+
+ $x = [
+ 'is_owner' => true,
+ 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
+ 'default_location' => $channel['channel_location'],
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
+
+ 'acl' => populate_acl($channel_acl),
+ 'permissions' => $channel_acl,
+ 'bang' => '',
+ 'visitor' => true,
+ 'profile_uid' => local_channel(),
+ 'return_path' => 'hq',
+ 'expanded' => true,
+ 'editor_autocomplete' => true,
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true,
+ 'jotnets' => true
+ ];
+
+ $o = replace_macros(get_markup_template("hq.tpl"),
+ [
+ '$no_messages' => (($target_item) ? false : true),
+ '$no_messages_label' => t('Welcome to hubzilla!')
+ ]
+ );
+
+ $o = '<div id="jot-popup">';
+ $o .= status_editor($a,$x);
+ $o .= '</div>';
+ }
+
+ if(! $update && ! $load) {
+
+ nav_set_selected('HQ');
+
+ $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1);
+
+ if($target_item) {
+ // if the target item is not a post (eg a like) we want to address its thread parent
+ $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
+
+ // if we got a decoded hash we must encode it again before handing to javascript
+ if($decoded)
+ $mid = 'b64.' . base64url_encode($mid);
+ }
+ else {
+ $mid = '';
+ }
+
+ $o .= '<div id="live-hq"></div>' . "\r\n";
+ $o .= "<script> var profile_uid = " . local_channel()
+ . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . ";</script>\r\n";
+
+ \App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),[
+ '$baseurl' => z_root(),
+ '$pgtype' => 'hq',
+ '$uid' => local_channel(),
+ '$gid' => '0',
+ '$cid' => '0',
+ '$cmin' => '0',
+ '$cmax' => '99',
+ '$star' => '0',
+ '$liked' => '0',
+ '$conv' => '0',
+ '$spam' => '0',
+ '$fh' => '0',
+ '$nouveau' => '0',
+ '$wall' => '0',
+ '$static' => $static,
+ '$page' => 1,
+ '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
+ '$search' => '',
+ '$xchan' => '',
+ '$order' => '',
+ '$file' => '',
+ '$cats' => '',
+ '$tags' => '',
+ '$dend' => '',
+ '$dbegin' => '',
+ '$verb' => '',
+ '$net' => '',
+ '$mid' => $mid
+ ]);
+ }
+
+ $updateable = false;
+
+ if($load && $target_item) {
+ $r = null;
+
+ $r = q("SELECT item.id AS item_id FROM item
+ WHERE uid = %d
+ AND mid = '%s'
+ $item_normal
+ LIMIT 1",
+ intval(local_channel()),
+ dbesc($target_item['parent_mid'])
+ );
+
+ if($r) {
+ $updateable = true;
+ }
+
+ if(!$r) {
+ $sys_item = true;
+
+ $r = q("SELECT item.id AS item_id FROM item
+ LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
+ WHERE mid = '%s' AND item.uid = %d $item_normal
+ AND (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra LIMIT 1",
+ dbesc($target_item['parent_mid']),
+ intval($sys['channel_id'])
+ );
+ }
+ }
+ elseif($update && $target_item) {
+ $r = null;
+
+ $r = q("SELECT item.parent AS item_id FROM item
+ WHERE uid = %d
+ AND parent_mid = '%s'
+ $item_normal_update
+ $simple_update
+ LIMIT 1",
+ intval(local_channel()),
+ dbesc($target_item['parent_mid'])
+ );
+
+ if($r) {
+ $updateable = true;
+ }
+
+ if(!$r) {
+ $sys_item = true;
+
+ $r = q("SELECT item.parent AS item_id FROM item
+ LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
+ WHERE mid = '%s' AND item.uid = %d $item_normal_update $simple_update
+ AND (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra LIMIT 1",
+ dbesc($target_item['parent_mid']),
+ intval($sys['channel_id'])
+ );
+ }
+
+ $_SESSION['loadtime'] = datetime_convert();
+ }
+ else {
+ $r = [];
+ }
+
+ if($r) {
+ $parents_str = ids_to_querystr($r,'item_id');
+ if($parents_str) {
+ $items = q("SELECT item.*, item.id AS item_id
+ FROM item
+ WHERE parent IN ( %s ) $item_normal ",
+ dbesc($parents_str)
+ );
+
+ xchan_query($items,true,(($sys_item) ? local_channel() : 0));
+ $items = fetch_post_tags($items,true);
+ $items = conv_sort($items,'created');
+ }
+ }
+ else {
+ $items = [];
+ }
+
+ $o .= conversation($items, 'hq', $update, 'client');
+
+ if($updateable) {
+ $x = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d AND parent = %d ",
+ intval(local_channel()),
+ intval($r[0]['item_id'])
+ );
+ }
+
+ $o .= '<div id="content-complete"></div>';
+
+ return $o;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Impel.php b/Zotlabs/Module/Impel.php
index 77f488d26..0c372bd96 100644
--- a/Zotlabs/Module/Impel.php
+++ b/Zotlabs/Module/Impel.php
@@ -26,6 +26,8 @@ class Impel extends \Zotlabs\Web\Controller {
if(! $j)
json_return_and_die($ret);
+ // logger('element: ' . print_r($j,true));
+
$channel = \App::get_channel();
$arr = array();
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index 9e5dcfaff..6365230f8 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -59,6 +59,7 @@ class Item extends \Zotlabs\Web\Controller {
$profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
require_once('include/channel.php');
+
$sys = get_sys_channel();
if($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) {
$uid = intval($sys['channel_id']);
@@ -155,7 +156,7 @@ class Item extends \Zotlabs\Web\Controller {
if(! x($_REQUEST,'type'))
$_REQUEST['type'] = 'net-comment';
- if($obj_type == ACTIVITY_OBJ_POST)
+ if($obj_type == ACTIVITY_OBJ_NOTE)
$obj_type = ACTIVITY_OBJ_COMMENT;
if($parent) {
@@ -171,7 +172,7 @@ class Item extends \Zotlabs\Web\Controller {
);
}
// if this isn't the real parent of the conversation, find it
- if($r !== false && count($r)) {
+ if($r) {
$parid = $r[0]['parent'];
$parent_mid = $r[0]['mid'];
if($r[0]['id'] != $r[0]['parent']) {
@@ -179,9 +180,16 @@ class Item extends \Zotlabs\Web\Controller {
intval($parid)
);
}
+
+ // if interacting with a pubstream item,
+ // create a copy of the parent in your stream
+
+ if($r[0]['uid'] === $sys['channel_id'] && local_channel()) {
+ $r = [ copy_of_pubitem(\App::get_channel(), $r[0]['mid']) ];
+ }
}
-
- if(($r === false) || (! count($r))) {
+
+ if(! $r) {
notice( t('Unable to locate original post.') . EOL);
if($api_source)
return ( [ 'success' => false, 'message' => 'invalid post id' ] );
@@ -189,15 +197,12 @@ class Item extends \Zotlabs\Web\Controller {
goaway(z_root() . "/" . $return_path );
killme();
}
-
- // can_comment_on_post() needs info from the following xchan_query
- // This may be from the discover tab which means we need to correct the effective uid
- xchan_query($r,true,(($r[0]['uid'] == local_channel()) ? 0 : local_channel()));
-
+ xchan_query($r,true);
+
$parent_item = $r[0];
$parent = $r[0]['id'];
-
+
// multi-level threading - preserve the info but re-parent to our single level threading
$thr_parent = $parent_mid;
@@ -511,48 +516,20 @@ class Item extends \Zotlabs\Web\Controller {
require_once('include/text.php');
- // Markdown doesn't work correctly. Do not re-enable unless you're willing to fix it and support it.
-
- // Sample that will probably give you grief - you must preserve the linebreaks
- // and provide the correct markdown interpretation and you cannot allow unfiltered HTML
-
- // Markdown
- // ========
- //
- // **bold** abcde
- // fghijkl
- // *italic*
- // <img src="javascript:alert('hacked');" />
-
- // if($uid && $uid == $profile_uid && feature_enabled($uid,'markdown')) {
- // require_once('include/markdown.php');
- // $body = escape_tags(trim($body));
- // $body = str_replace("\n",'<br />', $body);
- // $body = preg_replace_callback('/\[share(.*?)\]/ism','\share_shield',$body);
- // $body = markdown_to_bb($body,true);
- // $body = preg_replace_callback('/\[share(.*?)\]/ism','\share_unshield',$body);
- // }
+ if($uid && $uid == $profile_uid && feature_enabled($uid,'markdown')) {
+ require_once('include/markdown.php');
+ $body = preg_replace_callback('/\[share(.*?)\]/ism','\share_shield',$body);
+ $body = markdown_to_bb($body,true,['preserve_lf' => true]);
+ $body = preg_replace_callback('/\[share(.*?)\]/ism','\share_unshield',$body);
+
+ }
// BBCODE alert: the following functions assume bbcode input
// and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
// we may need virtual or template classes to implement the possible alternatives
-
- // Work around doubled linefeeds in Tinymce 3.5b2
- // First figure out if it's a status post that would've been
- // created using tinymce. Otherwise leave it alone.
-
- $plaintext = true;
-
- // $plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true);
- // if((! $parent) && (! $api_source) && (! $plaintext)) {
- // $body = fix_mce_lf($body);
- // }
-
-
-
+
// If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it, if our pconfig is set.
-
-
+
if((! $parent) && (get_pconfig($profile_uid,'system','tagifonlyrecip')) && (substr_count($str_contact_allow,'<') == 1) && ($str_group_allow == '') && ($str_contact_deny == '') && ($str_group_deny == '')) {
$x = q("select abook_id, abconfig.v from abook left join abconfig on abook_xchan = abconfig.xchan and abook_channel = abconfig.chan and cat= 'their_perms' and abconfig.k = 'tag_deliver' and abconfig.v = 1 and abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc(str_replace(array('<','>'),array('',''),$str_contact_allow)),
@@ -605,15 +582,6 @@ class Item extends \Zotlabs\Web\Controller {
* so we'll set the permissions regardless and realise that the media may not be
* referenced in the post.
*
- * What is preventing us from being able to upload photos into comments is dealing with
- * the photo and attachment permissions, since we don't always know who was in the
- * distribution for the top level post.
- *
- * We might be able to provide this functionality with a lot of fiddling:
- * - if the top level post is public (make the photo public)
- * - if the top level post was written by us or a wall post that belongs to us (match the top level post)
- * - if the top level post has privacy mentions, add those to the permissions.
- * - otherwise disallow the photo *or* make the photo public. This is the part that gets messy.
*/
if(! $preview) {
@@ -666,6 +634,9 @@ class Item extends \Zotlabs\Web\Controller {
if($webpage == ITEM_TYPE_CARD) {
$catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat));
}
+ elseif($webpage == ITEM_TYPE_ARTICLE) {
+ $catlink = z_root() . '/articles/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat));
+ }
else {
$catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat));
}
@@ -770,6 +741,18 @@ class Item extends \Zotlabs\Web\Controller {
}
}
+ if($webpage == ITEM_TYPE_ARTICLE) {
+ $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : substr($mid,0,16));
+ }
+ if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_ARTICLE)) {
+ $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.iid = %d limit 1",
+ intval($parent_item['id'])
+ );
+ if($r) {
+ $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . $r[0]['v'];
+ }
+ }
+
if ((! $plink) && ($item_thread_top)) {
$plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid;
}
@@ -1156,7 +1139,29 @@ class Item extends \Zotlabs\Web\Controller {
$ret['message'] = t('Unable to obtain post information from database.');
return $ret;
}
-
+
+ // auto-upgrade beginner (techlevel 0) accounts - if they have at least two friends and ten posts
+ // and have uploaded something (like a profile photo), promote them to level 1.
+
+ $a = q("select account_id, account_level from account where account_id = (select channel_account_id from channel where channel_id = %d limit 1)",
+ intval($channel_id)
+ );
+ if((! intval($a[0]['account_level'])) && intval($r[0]['total']) > 10) {
+ $x = q("select count(abook_id) as total from abook where abook_channel = %d",
+ intval($channel_id)
+ );
+ if($x && intval($x[0]['total']) > 2) {
+ $y = q("select count(id) as total from attach where uid = %d",
+ intval($channel_id)
+ );
+ if($y && intval($y[0]['total']) > 1) {
+ q("update account set account_level = 1 where account_id = %d limit 1",
+ intval($a[0]['account_id'])
+ );
+ }
+ }
+ }
+
if (!$iswebpage) {
$max = engr_units_to_bytes(service_class_fetch($channel_id,'total_items'));
if(! service_class_allows($channel_id,'total_items',$r[0]['total'])) {
diff --git a/Zotlabs/Module/Layouts.php b/Zotlabs/Module/Layouts.php
index 34d754029..19efb37fd 100644
--- a/Zotlabs/Module/Layouts.php
+++ b/Zotlabs/Module/Layouts.php
@@ -162,12 +162,12 @@ class Layouts extends \Zotlabs\Web\Controller {
'created' => $rr['created'],
'edited' => $rr['edited'],
'mimetype' => $rr['mimetype'],
- 'pagetitle' => $rr['sid'],
+ 'pagetitle' => urldecode($rr['v']),
'mid' => $rr['mid']
);
$pages[$rr['iid']][] = array(
'url' => $rr['iid'],
- 'title' => $rr['v'],
+ 'title' => urldecode($rr['v']),
'descr' => $rr['title'],
'mid' => $rr['mid'],
'created' => $rr['created'],
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index b104a5f5f..b07824363 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -12,7 +12,10 @@ class Like extends \Zotlabs\Web\Controller {
function get() {
$o = '';
-
+
+ $sys_channel = get_sys_channel();
+ $sys_channel_id = (($sys_channel) ? $sys_channel['channel_id'] : 0);
+
$observer = \App::get_observer();
$interactive = $_REQUEST['interactive'];
if($interactive) {
@@ -253,20 +256,29 @@ class Like extends \Zotlabs\Web\Controller {
logger('like: verb ' . $verb . ' item ' . $item_id, LOGGER_DEBUG);
// get the item. Allow linked photos (which are normally hidden) to be liked
-
+
$r = q("SELECT * FROM item WHERE id = %d
- and (item_type = 0 or item_type = 6) and item_deleted = 0 and item_unpublished = 0
+ and item_type in (0,6,7) and item_deleted = 0 and item_unpublished = 0
and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1",
intval($item_id)
);
-
+
+ // if interacting with a pubstream item,
+ // create a copy of the parent in your stream. If not the conversation
+ // parent, copy that as well.
+
+ if($r) {
+ if($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) {
+ $r = [ copy_of_pubitem(\App::get_channel(), $r[0]['mid']) ];
+ }
+ }
+
if(! $item_id || (! $r)) {
logger('like: no item ' . $item_id);
killme();
}
-
- xchan_query($r,true,(($r[0]['uid'] == local_channel()) ? 0 : local_channel()));
+ xchan_query($r,true);
$item = $r[0];
@@ -464,6 +476,8 @@ class Like extends \Zotlabs\Web\Controller {
$arr['mid'] = $mid;
$arr['aid'] = (($extended_like) ? $ch[0]['channel_account_id'] : $owner_aid);
$arr['uid'] = $owner_uid;
+
+
$arr['item_flags'] = $item_flags;
$arr['item_wall'] = $item_wall;
$arr['parent_mid'] = (($extended_like) ? $mid : $item['mid']);
diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php
index ee736ff42..a3e1eee88 100644
--- a/Zotlabs/Module/Network.php
+++ b/Zotlabs/Module/Network.php
@@ -35,9 +35,12 @@ class Network extends \Zotlabs\Web\Controller {
return login(false);
}
- if($load)
+ $o = '';
+
+ if($load) {
$_SESSION['loadtime'] = datetime_convert();
-
+ }
+
$arr = array('query' => \App::$query_string);
call_hooks('network_content_init', $arr);
@@ -104,7 +107,6 @@ class Network extends \Zotlabs\Web\Controller {
$def_acl = array('allow_gid' => '<' . $r[0]['hash'] . '>');
}
- $o = '';
// if no tabs are selected, defaults to comments
@@ -119,6 +121,7 @@ class Network extends \Zotlabs\Web\Controller {
$cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99);
$file = ((x($_GET,'file')) ? $_GET['file'] : '');
$xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : '');
+ $net = ((x($_GET,'net')) ? $_GET['net'] : '');
$deftag = '';
@@ -326,7 +329,8 @@ class Network extends \Zotlabs\Web\Controller {
'$tags' => urlencode($hashtags),
'$dend' => $datequery,
'$mid' => '',
- '$verb' => $verb,
+ '$verb' => $verb,
+ '$net' => $net,
'$dbegin' => $datequery2
));
}
@@ -404,7 +408,10 @@ class Network extends \Zotlabs\Web\Controller {
}
-
+
+ $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : '');
+ $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : '');
+
$abook_uids = " and abook.abook_channel = " . local_channel() . " ";
$uids = " and item.uid = " . local_channel() . " ";
@@ -441,10 +448,12 @@ class Network extends \Zotlabs\Web\Controller {
$items = q("SELECT item.*, item.id AS item_id, received FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
+ $net_query
WHERE true $uids $item_normal
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$simple_update
$sql_extra $sql_nets
+ $net_query2
ORDER BY item.received DESC $pager_sql "
);
@@ -469,10 +478,12 @@ class Network extends \Zotlabs\Web\Controller {
$r = q("SELECT distinct item.id AS item_id, $ordering FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
+ $net_query
WHERE true $uids $item_normal
AND item.parent = item.id
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra3 $sql_extra $sql_nets
+ $net_query2
ORDER BY $ordering DESC $pager_sql "
);
@@ -482,9 +493,10 @@ class Network extends \Zotlabs\Web\Controller {
// this is an update
$r = q("SELECT item.parent AS item_id FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
+ $net_query
WHERE true $uids $item_normal_update $simple_update
and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets "
+ $sql_extra3 $sql_extra $sql_nets $net_query2"
);
$_SESSION['loadtime'] = datetime_convert();
}
@@ -523,13 +535,12 @@ class Network extends \Zotlabs\Web\Controller {
if($parents_str) {
$update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
- $update_unseen .= " AND obj_type != '" . dbesc(ACTIVITY_OBJ_FILE) . "'";
$update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
}
}
else {
if($parents_str) {
- $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " ) AND obj_type != '" . dbesc(ACTIVITY_OBJ_FILE) . "'";
+ $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
}
}
}
diff --git a/Zotlabs/Module/Notify.php b/Zotlabs/Module/Notify.php
index 3d6e1c2e7..cffcc8099 100644
--- a/Zotlabs/Module/Notify.php
+++ b/Zotlabs/Module/Notify.php
@@ -34,7 +34,7 @@ class Notify extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
if(! local_channel())
return login();
diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php
index 5e06d3540..bb3a13b56 100644
--- a/Zotlabs/Module/Oep.php
+++ b/Zotlabs/Module/Oep.php
@@ -45,6 +45,8 @@ class Oep extends \Zotlabs\Web\Controller {
$arr = $this->oep_profile_reply($_REQUEST);
elseif(fnmatch('*/cards/*',$url))
$arr = $this->oep_cards_reply($_REQUEST);
+ elseif(fnmatch('*/articles/*',$url))
+ $arr = $this->oep_articles_reply($_REQUEST);
if($arr) {
if($html) {
@@ -232,6 +234,89 @@ class Oep extends \Zotlabs\Web\Controller {
}
+ function oep_articles_reply($args) {
+
+ $ret = [];
+ $url = $args['url'];
+ $maxwidth = intval($args['maxwidth']);
+ $maxheight = intval($args['maxheight']);
+
+ if(preg_match('#//(.*?)/articles/(.*?)/(.*?)(&|\?|$)#',$url,$matches)) {
+ $nick = $matches[2];
+ $res = $matches[3];
+ }
+ if(! ($nick && $res))
+ return $ret;
+
+ $channel = channelx_by_nick($nick);
+
+ if(! $channel)
+ return $ret;
+
+
+ if(! perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_pages'))
+ return $ret;
+
+ $sql_extra = item_permissions_sql($channel['channel_id'],get_observer_hash());
+
+ $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.v = '%s' limit 1",
+ dbesc($res)
+ );
+ if($r) {
+ $sql_extra = "and item.id = " . intval($r[0]['iid']) . " ";
+ }
+ else {
+ return $ret;
+ }
+
+ $r = q("select * from item
+ where item.uid = %d and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($channel['channel_id']),
+ intval(ITEM_TYPE_ARTICLE)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type in (0,7) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ if($r) {
+ xchan_query($r);
+ $p = fetch_post_tags($r, true);
+ }
+
+ $x = '2eGriplW^*Jmf4';
+
+
+ $o = "[share author='".urlencode($p[0]['author']['xchan_name']).
+ "' profile='".$p[0]['author']['xchan_url'] .
+ "' avatar='".$p[0]['author']['xchan_photo_s'].
+ "' link='".$p[0]['plink'].
+ "' posted='".$p[0]['created'].
+ "' message_id='".$p[0]['mid']."']";
+ if($p[0]['title'])
+ $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
+
+ $o .= $x;
+ $o .= "[/share]";
+ $o = bbcode($o);
+
+ $o = str_replace($x,bbcode($p[0]['body']),$o);
+
+ $ret['type'] = 'rich';
+
+ $w = (($maxwidth) ? $maxwidth : 640);
+ $h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
+
+ $ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
+
+ $ret['width'] = $w;
+ $ret['height'] = $h;
+
+ return $ret;
+
+ }
+
function oep_mid_reply($args) {
diff --git a/Zotlabs/Module/Ofeed.php b/Zotlabs/Module/Ofeed.php
index 58488d4af..d18a43ae5 100644
--- a/Zotlabs/Module/Ofeed.php
+++ b/Zotlabs/Module/Ofeed.php
@@ -17,12 +17,15 @@ class Ofeed extends \Zotlabs\Web\Controller {
$params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml');
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
- $params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
- $params['records'] = ((x($params,'records')) ? intval($params['records']) : 10);
- $params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
+ $params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0);
+ $params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 10);
+ $params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 1);
+ if(! in_array($params['direction'],['asc','desc'])) {
+ $params['direction'] = 'desc';
+ }
if(argc() > 1) {
diff --git a/Zotlabs/Module/Page.php b/Zotlabs/Module/Page.php
index c142afe77..5fdd32825 100644
--- a/Zotlabs/Module/Page.php
+++ b/Zotlabs/Module/Page.php
@@ -89,22 +89,30 @@ class Page extends \Zotlabs\Web\Controller {
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",
+ and iconfig.k = 'WEBPAGE' 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)
+ intval(ITEM_TYPE_WEBPAGE)
+ );
+ }
+ 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
+ $sql_options $revision limit 1",
+ intval($u[0]['channel_id']),
+ dbesc($page_id),
+ intval(ITEM_TYPE_WEBPAGE)
);
}
if(! $r) {
+ // no webpage by that name, but we do allow you to load/preview a layout using this module. Try that.
$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",
+ and 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)
);
}
@@ -129,7 +137,7 @@ class Page extends \Zotlabs\Web\Controller {
}
return;
}
-
+
if($r[0]['title'])
\App::$page['title'] = escape_tags($r[0]['title']);
diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php
index f8af470ac..9b86b599b 100644
--- a/Zotlabs/Module/Pdledit.php
+++ b/Zotlabs/Module/Pdledit.php
@@ -77,8 +77,10 @@ class Pdledit extends \Zotlabs\Web\Controller {
}
$t = get_pconfig(local_channel(),'system',$module);
- if(! $t)
- $t = file_get_contents(theme_include($module));
+ $s = file_get_contents(theme_include($module));
+ if(! $t) {
+ $t = $s;
+ }
if(! $t) {
notice( t('Layout not found.') . EOL);
return '';
@@ -89,7 +91,9 @@ class Pdledit extends \Zotlabs\Web\Controller {
'$mname' => t('Module Name:'),
'$help' => t('Layout Help'),
'$another' => t('Edit another layout'),
+ '$original' => t('System layout'),
'$module' => argv(1),
+ '$src' => $s,
'$content' => htmlspecialchars($t,ENT_COMPAT,'UTF-8'),
'$submit' => t('Submit')
));
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index caef45d98..81af607ec 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -202,6 +202,11 @@ class Photos extends \Zotlabs\Web\Controller {
);
if(($m) && ($m[0]['folder'] != $_POST['move_to_album'])) {
attach_move($page_owner_uid,argv(2),$_POST['move_to_album']);
+
+ $sync = attach_export_data(\App::$data['channel'],argv(2),true);
+ if($sync)
+ build_sync_packet($page_owner_uid,array('file' => array($sync)));
+
if(! ($_POST['desc'] && $_POST['newtag']))
goaway(z_root() . '/' . $_SESSION['photo_return']);
}
@@ -465,6 +470,51 @@ class Photos extends \Zotlabs\Web\Controller {
$_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']);
}
+
+ $matches = [];
+ $partial = false;
+
+
+
+ if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
+ $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
+ if($pm) {
+ logger('Content-Range: ' . print_r($matches,true));
+ $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']
+ ];
+ }
+ }
+
$r = attach_store($channel,get_observer_hash(), '', $_REQUEST);
if(! $r['success']) {
@@ -557,8 +607,11 @@ class Photos extends \Zotlabs\Web\Controller {
nav_set_selected('Photos');
- $o = "";
-
+ $o = '<script src="library/blueimp_upload/js/vendor/jquery.ui.widget.js"></script>
+ <script src="library/blueimp_upload/js/jquery.iframe-transport.js"></script>
+ <script src="library/blueimp_upload/js/jquery.fileupload.js"></script>';
+
+
$o .= "<script> var profile_uid = " . \App::$profile['profile_uid']
. "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n";
@@ -656,7 +709,7 @@ class Photos extends \Zotlabs\Web\Controller {
'$uploader' => $ret['addon_text'],
'$default' => (($ret['default_upload']) ? true : false),
'$uploadurl' => $ret['post_url'],
- '$submit' => t('Submit')
+ '$submit' => t('Upload')
));
@@ -1052,7 +1105,7 @@ class Photos extends \Zotlabs\Web\Controller {
}
$comments = '';
- if(! count($r)) {
+ if(! $r) {
if($observer && ($can_post || $can_comment)) {
$commentbox = replace_macros($cmnt_tpl,array(
'$return_path' => '',
diff --git a/Zotlabs/Module/Ping.php b/Zotlabs/Module/Ping.php
index cda42f426..a3f6cdfec 100644
--- a/Zotlabs/Module/Ping.php
+++ b/Zotlabs/Module/Ping.php
@@ -140,7 +140,7 @@ class Ping extends \Zotlabs\Web\Controller {
db_utcnow(), db_quoteinterval('3 MINUTE')
);
- $discover_tab_on = ((get_config('system','disable_discover_tab') != 1) ? true : false);
+ $discover_tab_on = ((get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false) ? false : true);
$notify_pubs = ((local_channel()) ? ($vnotify & VNOTIFY_PUBS) && $discover_tab_on : $discover_tab_on);
if($notify_pubs) {
@@ -169,15 +169,13 @@ class Ping extends \Zotlabs\Web\Controller {
$r = q("SELECT * FROM item
WHERE uid = %d
AND author_xchan != '%s'
- AND obj_type != '%s'
AND item_unseen = 1
AND created > '" . datetime_convert('UTC','UTC',$_SESSION['static_loadtime']) . "'
$item_normal
ORDER BY created DESC
LIMIT 300",
intval($sys['channel_id']),
- dbesc(get_observer_hash()),
- dbesc(ACTIVITY_OBJ_FILE)
+ dbesc(get_observer_hash())
);
if($r) {
@@ -264,6 +262,16 @@ class Ping extends \Zotlabs\Web\Controller {
if($t) {
foreach($t as $tt) {
+ $message = trim(strip_tags(bbcode($tt['msg'])));
+
+ if(strpos($message, $tt['xname']) === 0)
+ $message = substr($message, strlen($tt['xname']) + 1);
+
+
+ $mid = basename($tt['link']);
+
+ $b64mid = ((strpos($mid, 'b64.' === 0)) ? $mid : 'b64.' . base64url_encode($mid));
+
$notifs[] = array(
'notify_link' => z_root() . '/notify/view/' . $tt['id'],
'name' => $tt['xname'],
@@ -271,7 +279,9 @@ class Ping extends \Zotlabs\Web\Controller {
'photo' => $tt['photo'],
'when' => relative_date($tt['created']),
'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
- 'message' => strip_tags(bbcode($tt['msg']))
+ 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'),
+ 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'),
+ 'message' => $message
);
}
}
@@ -313,11 +323,9 @@ class Ping extends \Zotlabs\Web\Controller {
$r = q("SELECT * FROM item
WHERE item_unseen = 1 and uid = %d $item_normal
AND author_xchan != '%s'
- AND obj_type != '%s'
ORDER BY created DESC limit 300",
intval(local_channel()),
- dbesc($ob_hash),
- dbesc(ACTIVITY_OBJ_FILE)
+ dbesc($ob_hash)
);
if($r) {
@@ -484,14 +492,13 @@ class Ping extends \Zotlabs\Web\Controller {
$t3 = dba_timer();
if($vnotify & (VNOTIFY_NETWORK|VNOTIFY_CHANNEL)) {
+
$r = q("SELECT id, item_wall FROM item
WHERE item_unseen = 1 and uid = %d
$item_normal
- AND author_xchan != '%s'
- AND obj_type != '%s'",
+ AND author_xchan != '%s'",
intval(local_channel()),
- dbesc($ob_hash),
- dbesc(ACTIVITY_OBJ_FILE)
+ dbesc($ob_hash)
);
if($r) {
diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php
index 43106e3af..4235f0b97 100644
--- a/Zotlabs/Module/Profile.php
+++ b/Zotlabs/Module/Profile.php
@@ -109,7 +109,7 @@ class Profile extends \Zotlabs\Web\Controller {
'title' => 'oembed'
]);
- $o .= advanced_profile($a);
+ $o .= advanced_profile();
call_hooks('profile_advanced',$o);
return $o;
diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php
index 411518c61..45a606d5f 100644
--- a/Zotlabs/Module/Profile_photo.php
+++ b/Zotlabs/Module/Profile_photo.php
@@ -179,7 +179,10 @@ class Profile_photo extends \Zotlabs\Web\Controller {
);
}
- profiles_build_sync(local_channel());
+ // set $send to false in profiles_build_sync() to return the data
+ // so that we only send one sync packet.
+
+ $sync_profiles = profiles_build_sync(local_channel(),false);
// We'll set the updated profile-photo timestamp even if it isn't the default profile,
// so that browsers will do a cache update unconditionally
@@ -201,7 +204,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$sync = attach_export_data($channel,$base_image['resource_id']);
if($sync)
- build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles));
// Similarly, tell the nav bar to bypass the cache and update the avatar image.
diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php
index 15e2d8a74..c469a0eca 100644
--- a/Zotlabs/Module/Pubstream.php
+++ b/Zotlabs/Module/Pubstream.php
@@ -2,6 +2,7 @@
namespace Zotlabs\Module;
require_once('include/conversation.php');
+require_once('include/acl_selectors.php');
class Pubstream extends \Zotlabs\Web\Controller {
@@ -31,6 +32,48 @@ class Pubstream extends \Zotlabs\Web\Controller {
$item_normal_update = item_normal_update();
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
+ $net = ((array_key_exists('net',$_REQUEST)) ? escape_tags($_REQUEST['net']) : '');
+
+
+ if(local_channel() && (! $update)) {
+
+ $channel = \App::get_channel();
+
+ $channel_acl = array(
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
+ );
+
+ $x = array(
+ 'is_owner' => true,
+ 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
+ 'default_location' => $channel['channel_location'],
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
+
+ 'acl' => populate_acl($channel_acl),
+ 'permissions' => $channel_acl,
+ 'bang' => '',
+ 'visitor' => true,
+ 'profile_uid' => local_channel(),
+ 'return_path' => 'channel/' . $channel['channel_address'],
+ 'expanded' => true,
+ 'editor_autocomplete' => true,
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true,
+ 'jotnets' => true
+ );
+
+ $o = '<div id="jot-popup">';
+ $o .= status_editor($a,$x);
+ $o .= '</div>';
+ }
+
+
+
+
if(! $update && !$load) {
@@ -81,7 +124,8 @@ class Pubstream extends \Zotlabs\Web\Controller {
'$tags' => '',
'$dend' => '',
'$mid' => $mid,
- '$verb' => '',
+ '$verb' => '',
+ '$net' => $net,
'$dbegin' => ''
));
}
@@ -112,20 +156,22 @@ class Pubstream extends \Zotlabs\Web\Controller {
$page_mode = 'list';
else
$page_mode = 'client';
+
+
+ $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : '');
+ $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : '');
- $simple_update = (($update) ? " and item.item_unseen = 1 " : '');
+ $simple_update = (($_SESSION['loadtime']) ? " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' " : '');
- if($update && $_SESSION['loadtime'])
- $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
if($load)
$simple_update = '';
if($static && $simple_update)
- $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
+ $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
//logger('update: ' . $update . ' load: ' . $load);
-
+
if($update) {
$ordering = "commented";
@@ -134,9 +180,10 @@ class Pubstream extends \Zotlabs\Web\Controller {
if($mid) {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
+ $net_query
WHERE mid like '%s' $uids $item_normal
and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets LIMIT 1",
+ $sql_extra3 $sql_extra $sql_nets $net_query2 LIMIT 1",
dbesc($mid . '%')
);
}
@@ -144,10 +191,11 @@ class Pubstream extends \Zotlabs\Web\Controller {
// Fetch a page full of parent items for this page
$r = q("SELECT distinct item.id AS item_id, $ordering FROM item
left join abook on item.author_xchan = abook.abook_xchan
+ $net_query
WHERE true $uids $item_normal
AND item.parent = item.id
and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets
+ $sql_extra3 $sql_extra $sql_nets $net_query2
ORDER BY $ordering DESC $pager_sql "
);
}
@@ -156,23 +204,26 @@ class Pubstream extends \Zotlabs\Web\Controller {
if($mid) {
$r = q("SELECT parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
+ $net_query
WHERE mid like '%s' $uids $item_normal_update $simple_update
and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets LIMIT 1",
+ $sql_extra3 $sql_extra $sql_nets $net_query2 LIMIT 1",
dbesc($mid . '%')
);
}
else {
- $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
+ $r = q("SELECT distinct parent AS item_id, $ordering FROM item
left join abook on item.author_xchan = abook.abook_xchan
+ $net_query
WHERE true $uids $item_normal_update
- AND item.parent = item.id $simple_update
+ $simple_update
and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets"
+ $sql_extra3 $sql_extra $sql_nets $net_query2"
);
}
$_SESSION['loadtime'] = datetime_convert();
}
+
// Then fetch all the children of the parents that are on this page
$parents_str = '';
$update_unseen = '';
@@ -188,7 +239,10 @@ class Pubstream extends \Zotlabs\Web\Controller {
dbesc($parents_str)
);
- xchan_query($items,true,(-1));
+ // use effective_uid param of xchan_query to help sort out comment permission
+ // for sys_channel owned items.
+
+ xchan_query($items,true,(($sys) ? local_channel() : 0));
$items = fetch_post_tags($items,true);
$items = conv_sort($items,$ordering);
}
@@ -199,7 +253,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
}
// fake it
- $mode = ('network');
+ $mode = ('pubstream');
$o .= conversation($items,$mode,$update,$page_mode);
diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php
index 6cd79c952..6473317c7 100644
--- a/Zotlabs/Module/React.php
+++ b/Zotlabs/Module/React.php
@@ -6,15 +6,21 @@ namespace Zotlabs\Module;
class React extends \Zotlabs\Web\Controller {
function get() {
+
if(! local_channel())
return;
+ $sys = get_sys_channel();
+ $channel = \App::get_channel();
+
$postid = $_REQUEST['postid'];
if(! $postid)
return;
$emoji = $_REQUEST['emoji'];
+
+
if($_REQUEST['emoji']) {
$i = q("select * from item where id = %d and uid = %d",
@@ -22,10 +28,22 @@ class React extends \Zotlabs\Web\Controller {
intval(local_channel())
);
- if(! $i)
+ if(! $i) {
+ $i = q("select * from item where id = %d and uid = %d",
+ intval($postid),
+ intval($sys['channel_id'])
+ );
+
+ if($i) {
+ $i = [ copy_of_pubitem($channel, $i[0]['mid']) ];
+ $postid = (($i) ? $i[0]['id'] : 0);
+ }
+ }
+
+ if(! $i) {
return;
+ }
- $channel = \App::get_channel();
$n = array();
$n['aid'] = $channel['channel_account_id'];
@@ -40,8 +58,7 @@ class React extends \Zotlabs\Web\Controller {
$x = item_store($n);
- if(local_channel())
- retain_item($postid);
+ retain_item($postid);
if($x['success']) {
$nid = $x['item_id'];
diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php
index 95e3ca96f..deaee31bf 100644
--- a/Zotlabs/Module/Register.php
+++ b/Zotlabs/Module/Register.php
@@ -234,7 +234,11 @@ class Register extends \Zotlabs\Web\Controller {
if(get_config('system','no_age_restriction'))
$label_tos = sprintf( t('I accept the %s for this website'), $toslink);
else
- $label_tos = sprintf( t('I am over 13 years of age and accept the %s for this website'), $toslink);
+ $age = get_config('system','minimum_age');
+ if(!$age) {
+ $age = 13;
+ }
+ $label_tos = sprintf( t('I am over %s years of age and accept the %s for this website'), $age, $toslink);
$enable_tos = 1 - intval(get_config('system','no_termsofservice'));
diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php
index 37e9a336f..a572a5a42 100644
--- a/Zotlabs/Module/Search.php
+++ b/Zotlabs/Module/Search.php
@@ -56,8 +56,7 @@ class Search extends \Zotlabs\Web\Controller {
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
- if((! local_channel()) || (! feature_enabled(local_channel(),'savedsearch')))
- $o .= search($search,'search-box','/search',((local_channel()) ? true : false));
+ $o .= search($search,'search-box','/search',((local_channel()) ? true : false));
if(strpos($search,'#') === 0) {
$tag = true;
@@ -138,6 +137,7 @@ class Search extends \Zotlabs\Web\Controller {
'$tags' => '',
'$mid' => '',
'$verb' => '',
+ '$net' => '',
'$dend' => '',
'$dbegin' => ''
));
diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php
index 41e23b717..5e9e88a6d 100644
--- a/Zotlabs/Module/Settings/Channel.php
+++ b/Zotlabs/Module/Settings/Channel.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Module\Settings;
+require_once('include/selectors.php');
+
class Channel {
@@ -148,6 +150,9 @@ class Channel {
$defpermcat = ((x($_POST,'defpermcat')) ? notags(trim($_POST['defpermcat'])) : 'default');
$cal_first_day = (((x($_POST,'first_day')) && (intval($_POST['first_day']) == 1)) ? 1: 0);
+ $mailhost = ((array_key_exists('mailhost',$_POST)) ? notags(trim($_POST['mailhost'])) : '');
+ $profile_assign = ((x($_POST,'profile_assign')) ? notags(trim($_POST['profile_assign'])) : '');
+
$pageflags = $channel['channel_pageflags'];
$existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0);
@@ -201,7 +206,7 @@ class Channel {
$vnotify += intval($_POST['vnotify11']);
if(x($_POST,'vnotify12'))
$vnotify += intval($_POST['vnotify12']);
- if(x($_POST,'vnotify13') && (get_config('system', 'disable_discover_tab') != 1))
+ if(x($_POST,'vnotify13'))
$vnotify += intval($_POST['vnotify13']);
$always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0;
@@ -239,6 +244,8 @@ class Channel {
set_pconfig(local_channel(),'system','attach_path',$attach_path);
set_pconfig(local_channel(),'system','cal_first_day',$cal_first_day);
set_pconfig(local_channel(),'system','default_permcat',$defpermcat);
+ set_pconfig(local_channel(),'system','email_notify_host',$mailhost);
+ set_pconfig(local_channel(),'system','profile_assign',$profile_assign);
$r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d",
dbesc($username),
@@ -474,6 +481,8 @@ class Channel {
$plugin = [ 'basic' => '', 'security' => '', 'notify' => '', 'misc' => '' ];
call_hooks('channel_settings',$plugin);
+ $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
+
$o .= replace_macros($stpl,array(
'$ptitle' => t('Channel Settings'),
@@ -512,6 +521,9 @@ class Channel {
'$permissions' => t('Default Privacy Group'),
'$permdesc' => t("\x28click to open/close\x29"),
'$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))),
+ '$profseltxt' => t('Profile to assign new connections'),
+ '$profselect' => ((feature_enabled(local_channel(),'multi_profiles')) ? contact_profile_assign(get_pconfig(local_channel(),'system','profile_assign','')) : ''),
+
'$allow_cid' => acl2json($perm_defaults['allow_cid']),
'$allow_gid' => acl2json($perm_defaults['allow_gid']),
'$deny_cid' => acl2json($perm_defaults['deny_cid']),
@@ -560,7 +572,8 @@ class Channel {
'$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no),
'$vnotify11' => array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no),
'$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no),
- '$vnotify13' => ((get_config('system', 'disable_discover_tab') != 1) ? array('vnotify13', t('Unseen public activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no) : array()),
+ '$vnotify13' => (($disable_discover_tab) ? array() : array('vnotify13', t('Unseen public activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no)),
+ '$mailhost' => [ 'mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(),'system','email_notify_host',\App::get_hostname()), sprintf( t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'),\App::get_hostname()) ],
'$always_show_in_notices' => array('always_show_in_notices', t('Also show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no),
'$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')),
diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php
index a444d28a2..e1ea0e3e5 100644
--- a/Zotlabs/Module/Settings/Display.php
+++ b/Zotlabs/Module/Settings/Display.php
@@ -23,6 +23,7 @@ class Display {
$mobile_theme = ((x($_POST,'mobile_theme')) ? notags(trim($_POST['mobile_theme'])) : '');
$preload_images = ((x($_POST,'preload_images')) ? intval($_POST['preload_images']) : 0);
+ $channel_menu = ((x($_POST,'channel_menu')) ? intval($_POST['channel_menu']) : 0);
$user_scalable = ((x($_POST,'user_scalable')) ? intval($_POST['user_scalable']) : 0);
$nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0);
$title_tosource = ((x($_POST,'title_tosource')) ? intval($_POST['title_tosource']) : 0);
@@ -63,6 +64,7 @@ class Display {
set_pconfig(local_channel(),'system','channel_divmore_height', $channel_divmore_height);
set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height);
set_pconfig(local_channel(),'system','manual_conversation_update', $manual_update);
+ set_pconfig(local_channel(),'system','channel_menu', $channel_menu);
$newschema = '';
if($theme){
@@ -217,6 +219,7 @@ class Display {
'$ajaxint' => array('browser_update', t("Update browser every xx seconds"), $browser_update, t('Minimum of 10 seconds, no maximum')),
'$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 100 items')),
'$nosmile' => array('nosmile', t("Show emoticons (smilies) as images"), 1-intval($nosmile), '', $yes_no),
+ '$channel_menu' => [ 'channel_menu', t('Provide channel menu in navigation bar'), get_pconfig(local_channel(),'system','channel_menu',get_config('system','channel_menu',0)), t('Default: channel menu located in app menu'),$yes_no ],
'$manual_update' => array('manual_update', t('Manual conversation updates'), channel_manual_conv_update(local_channel()), t('Default is on, turning this off may increase screen jumping'), $yes_no),
'$title_tosource' => array('title_tosource', t("Link post titles to source"), $title_tosource, '', $yes_no),
'$layout_editor' => t('System Page Layout Editor - (advanced)'),
diff --git a/Zotlabs/Module/Settings/Featured.php b/Zotlabs/Module/Settings/Featured.php
index ebe2996d3..6a8d10b2d 100644
--- a/Zotlabs/Module/Settings/Featured.php
+++ b/Zotlabs/Module/Settings/Featured.php
@@ -11,15 +11,21 @@ class Featured {
call_hooks('feature_settings_post', $_POST);
if($_POST['affinity_slider-submit']) {
- if(intval($_POST['affinity_cmax'])) {
- set_pconfig(local_channel(),'affinity','cmax',intval($_POST['affinity_cmax']));
+ $cmax = intval($_POST['affinity_cmax']);
+ if($cmax < 0 || $cmax > 99)
+ $cmax = 99;
+ $cmin = intval($_POST['affinity_cmin']);
+ if($cmin < 0 || $cmin > 99)
+ $cmin = 0;
+ if($cmin !== 0 || $cmax !== 99) {
+ set_pconfig(local_channel(),'system','network_page_default','cmin=' . $cmin . '&cmax=' . $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);
+ else {
+ set_pconfig(local_channel(),'system','network_page_default','');
}
+
+ info( t('Affinity Slider settings updated.') . EOL);
+
}
build_sync_packet();
diff --git a/Zotlabs/Module/Starred.php b/Zotlabs/Module/Starred.php
index 4f1d99ec6..8349ae25c 100644
--- a/Zotlabs/Module/Starred.php
+++ b/Zotlabs/Module/Starred.php
@@ -16,7 +16,7 @@ class Starred extends \Zotlabs\Web\Controller {
if(! $message_id)
killme();
- $r = q("SELECT item_flags FROM item WHERE uid = %d AND id = %d LIMIT 1",
+ $r = q("SELECT item_starred FROM item WHERE uid = %d AND id = %d LIMIT 1",
intval(local_channel()),
intval($message_id)
);
diff --git a/Zotlabs/Module/Subthread.php b/Zotlabs/Module/Subthread.php
index dae8bf020..1a9caff6c 100644
--- a/Zotlabs/Module/Subthread.php
+++ b/Zotlabs/Module/Subthread.php
@@ -11,10 +11,13 @@ class Subthread extends \Zotlabs\Web\Controller {
function get() {
- if((! local_channel()) && (! remote_channel())) {
+ if(! local_channel()) {
return;
}
+ $sys = get_sys_channel();
+ $channel = \App::get_channel();
+
$item_id = ((argc() > 2) ? notags(trim(argv(2))) : 0);
if(argv(1) === 'sub')
@@ -23,10 +26,31 @@ class Subthread extends \Zotlabs\Web\Controller {
$activity = ACTIVITY_UNFOLLOW;
- $r = q("SELECT parent FROM item WHERE id = '%s'",
- dbesc($item_id)
+ $i = q("select * from item where id = %d and uid = %d",
+ intval($item_id),
+ intval(local_channel())
);
-
+
+ if(! $i) {
+ $i = q("select * from item where id = %d and uid = %d",
+ intval($postid),
+ intval($sys['channel_id'])
+ );
+
+ if($i) {
+ $i = [ copy_of_pubitem($channel, $i[0]['mid']) ];
+ $item_id = (($i) ? $i[0]['id'] : 0);
+ }
+ }
+
+ if(! $i) {
+ return;
+ }
+
+ $r = q("SELECT parent FROM item WHERE id = %d",
+ intval($item_id)
+ );
+
if($r) {
$r = q("select * from item where id = parent and id = %d limit 1",
dbesc($r[0]['parent'])
diff --git a/Zotlabs/Module/Tagger.php b/Zotlabs/Module/Tagger.php
index 98e901965..603a95f2b 100644
--- a/Zotlabs/Module/Tagger.php
+++ b/Zotlabs/Module/Tagger.php
@@ -11,10 +11,12 @@ class Tagger extends \Zotlabs\Web\Controller {
function get() {
- if(! local_channel() && ! remote_channel()) {
+ if(! local_channel()) {
return;
}
+ $sys = get_sys_channel();
+
$observer_hash = get_observer_hash();
//strip html-tags
$term = notags(trim($_GET['term']));
@@ -26,9 +28,29 @@ class Tagger extends \Zotlabs\Web\Controller {
logger('tagger: tag ' . $term . ' item ' . $item_id);
-
- $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = '%s' and uid = %d LIMIT 1",
- dbesc($item_id),
+ $r = q("select * from item where id = %d and uid = %d limit 1",
+ intval($item_id),
+ intval(local_channel())
+ );
+
+ if(! $r) {
+ $r = q("select * from item where id = %d and uid = %d limit 1",
+ intval($item_id),
+ intval($sys['channel_id'])
+ );
+ if($r) {
+ $r = [ copy_of_pubitem($channel, $i[0]['mid']) ];
+ $item_id = (($r) ? $r[0]['id'] : 0);
+ }
+ }
+
+ if(! $r) {
+ notice( t('Post not found.') . EOL);
+ return;
+ }
+
+ $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = %d and uid = %d LIMIT 1",
+ intval($item_id),
intval(local_channel())
);
diff --git a/Zotlabs/Module/Update.php b/Zotlabs/Module/Update.php
new file mode 100644
index 000000000..b3252f8b9
--- /dev/null
+++ b/Zotlabs/Module/Update.php
@@ -0,0 +1,43 @@
+<?php
+namespace Zotlabs\Module;
+
+
+class Update extends \Zotlabs\Web\Controller {
+
+ function get() {
+
+ $profile_uid = intval($_GET['p']);
+
+ // it's probably safe to do this for all modules and not just a limited subset,
+ // but it needs to be verified.
+
+ if((! $profile_uid) && in_array(argv(1),['display','search','pubstream','home']))
+ $profile_uid = (-1);
+
+ if(argc() < 2) {
+ killme();
+ }
+
+ // These modules don't have a completely working liveUpdate implementation currently
+
+ if(in_array(strtolower(argv(1)),['articles','cards']))
+ killme();
+
+ $module = "\\Zotlabs\\Module\\" . ucfirst(argv(1));
+ $load = (((argc() > 2) && (argv(2) == 'load')) ? 1 : 0);
+
+ $mod = new $module;
+
+ header("Content-type: text/html");
+
+ \App::$argv = [ argv(1) ];
+ \App::$argc = 1;
+
+ echo "<!DOCTYPE html><html><body><section>\r\n";
+ echo $mod->get($profile_uid, $load);
+ echo "</section></body></html>\r\n";
+
+ killme();
+
+ }
+}
diff --git a/Zotlabs/Module/Update_cards.php b/Zotlabs/Module/Update_cards.php
deleted file mode 100644
index bb87357e8..000000000
--- a/Zotlabs/Module/Update_cards.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-namespace Zotlabs\Module;
-
-/**
- * Module: update_profile
- * Purpose: AJAX synchronisation of profile page
- *
- */
-
-
-class Update_cards extends \Zotlabs\Web\Controller {
-
-function get() {
-
- $profile_uid = intval($_GET['p']);
- $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
-
- header("Content-type: text/html");
- echo "<!DOCTYPE html><html><body><section></section></body></html>\r\n";
-
- killme();
-
-
- $mod = new Cards();
-
- $text = $mod->get($profile_uid,$load);
-
- /**
- * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well
- */
-
- echo str_replace("\t",' ',$text);
- echo (($_GET['msie'] == 1) ? '</div>' : '</section>');
- echo "</body></html>\r\n";
- killme();
-
-}
-}
diff --git a/Zotlabs/Module/Update_channel.php b/Zotlabs/Module/Update_channel.php
deleted file mode 100644
index 46ad19805..000000000
--- a/Zotlabs/Module/Update_channel.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-namespace Zotlabs\Module;
-
-/**
- * Module: update_profile
- * Purpose: AJAX synchronisation of profile page
- *
- */
-
-
-class Update_channel extends \Zotlabs\Web\Controller {
-
-function get() {
-
- $profile_uid = intval($_GET['p']);
- $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
-
- header("Content-type: text/html");
- echo "<!DOCTYPE html><html><body>\r\n";
-
- /**
- * We can remove this hack once Internet Explorer recognises HTML5 natively
- */
-
- echo (($_GET['msie'] == 1) ? '<div>' : '<section>');
-
- /**
- *
- * Grab the page inner contents by calling the content function from the profile module directly,
- * but move any image src attributes to another attribute name. This is because
- * some browsers will prefetch all the images for the page even if we don't need them.
- * The only ones we need to fetch are those for new page additions, which we'll discover
- * on the client side and then swap the image back.
- *
- */
-
- $mod = new Channel();
-
- $text = $mod->get($profile_uid,$load);
-
- $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
- $replace = "<img\${1} dst=\"\${2}\"";
-// $text = preg_replace($pattern, $replace, $text);
-
-/*
- if(! $load) {
- $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />';
- $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i";
- $text = preg_replace($pattern, $replace, $text);
- }
-*/
-
- /**
- * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well
- */
-
- echo str_replace("\t",' ',$text);
- echo (($_GET['msie'] == 1) ? '</div>' : '</section>');
- echo "</body></html>\r\n";
- killme();
-
-}
-}
diff --git a/Zotlabs/Module/Update_display.php b/Zotlabs/Module/Update_display.php
deleted file mode 100644
index b2c6a56f5..000000000
--- a/Zotlabs/Module/Update_display.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-// See update_profile.php for documentation
-
-require_once('include/group.php');
-
-
-class Update_display extends \Zotlabs\Web\Controller {
-
- function get() {
-
- $profile_uid = intval($_GET['p']);
- if(! $profile_uid)
- $profile_uid = (-1);
- $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
- header("Content-type: text/html");
- echo "<!DOCTYPE html><html><body>\r\n";
- echo (($_GET['msie'] == 1) ? '<div>' : '<section>');
-
- $mod = new Display();
- $text = $mod->get($profile_uid, $load);
-
- echo str_replace("\t",' ',$text);
- echo (($_GET['msie'] == 1) ? '</div>' : '</section>');
- echo "</body></html>\r\n";
-
- killme();
-
- }
-
-}
diff --git a/Zotlabs/Module/Update_home.php b/Zotlabs/Module/Update_home.php
deleted file mode 100644
index 0f699482e..000000000
--- a/Zotlabs/Module/Update_home.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-// See update_profile.php for documentation
-
-class Update_home extends \Zotlabs\Web\Controller {
-
- function get() {
-
- $profile_uid = ((intval($_GET['p'])) ? intval($_GET['p']) : (-1));
- $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
- header("Content-type: text/html");
- echo "<!DOCTYPE html><html><body>\r\n";
- echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '<div>' : '<section>');
-
- $mod = new Home();
- $text = $mod->get($profile_uid, $load);
-
- $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
- $replace = "<img\${1} dst=\"\${2}\"";
- // $text = preg_replace($pattern, $replace, $text);
- /*
- if(! $load) {
- $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />';
- $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i";
- $text = preg_replace($pattern, $replace, $text);
- }
- */
- echo str_replace("\t",' ',$text);
- echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '</div>' : '</section>');
- echo "</body></html>\r\n";
- // logger('update_home: ' . $text);
- killme();
-
- }
-}
diff --git a/Zotlabs/Module/Update_network.php b/Zotlabs/Module/Update_network.php
deleted file mode 100644
index c27b7614a..000000000
--- a/Zotlabs/Module/Update_network.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-// See update_profile.php for documentation
-
-require_once('include/group.php');
-
-class Update_network extends \Zotlabs\Web\Controller {
-
- function get() {
-
- $profile_uid = intval($_GET['p']);
- $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
- header("Content-type: text/html");
- echo "<!DOCTYPE html><html><body>\r\n";
- echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '<div>' : '<section>');
-
- $mod = new Network();
- $text = $mod->get($profile_uid, $load);
-
- $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
- $replace = "<img\${1} dst=\"\${2}\"";
- // $text = preg_replace($pattern, $replace, $text);
- /*
- if(! $load) {
- $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />';
- $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i";
- $text = preg_replace($pattern, $replace, $text);
- }
- */
- echo str_replace("\t",' ',$text);
- echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '</div>' : '</section>');
- echo "</body></html>\r\n";
- // logger('update_network: ' . $text);
- killme();
-
- }
-}
diff --git a/Zotlabs/Module/Update_pubstream.php b/Zotlabs/Module/Update_pubstream.php
deleted file mode 100644
index 952b48df3..000000000
--- a/Zotlabs/Module/Update_pubstream.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-// See update_profile.php for documentation
-
-
-class Update_pubstream extends \Zotlabs\Web\Controller {
-
- function get() {
-
- $profile_uid = ((intval($_GET['p'])) ? intval($_GET['p']) : (-1));
- $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
- header("Content-type: text/html");
- echo "<!DOCTYPE html><html><body>\r\n";
- echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '<div>' : '<section>');
-
- $mod = new Pubstream();
- $text = $mod->get($profile_uid, $load);
-
- $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
- $replace = "<img\${1} dst=\"\${2}\"";
- // $text = preg_replace($pattern, $replace, $text);
- /*
- if(! $load) {
- $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />';
- $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i";
- $text = preg_replace($pattern, $replace, $text);
- }
- */
- echo str_replace("\t",' ',$text);
- echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '</div>' : '</section>');
- echo "</body></html>\r\n";
- killme();
-
- }
-}
diff --git a/Zotlabs/Module/Update_search.php b/Zotlabs/Module/Update_search.php
deleted file mode 100644
index 4491f40f4..000000000
--- a/Zotlabs/Module/Update_search.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-/**
- * Module: update_profile
- * Purpose: AJAX synchronisation of search page
- *
- */
-
-
-class Update_search extends \Zotlabs\Web\Controller {
-
- function get() {
-
- $profile_uid = intval($_GET['p']);
- if(! $profile_uid)
- $profile_uid = (-1);
-
- $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
-
- header("Content-type: text/html");
- echo "<!DOCTYPE html><html><body>\r\n";
-
- /**
- * We can remove this hack once Internet Explorer recognises HTML5 natively
- */
-
- echo (($_GET['msie'] == 1) ? '<div>' : '<section>');
-
- /**
- *
- * Grab the page inner contents by calling the content function from the profile module directly,
- * but move any image src attributes to another attribute name. This is because
- * some browsers will prefetch all the images for the page even if we don't need them.
- * The only ones we need to fetch are those for new page additions, which we'll discover
- * on the client side and then swap the image back.
- *
- */
-
- $mod = new Search();
- $text = $mod->get($profile_uid,$load);
-
- $pattern = "/<img([^>]*) src=\"([^\"]*)\"/";
- $replace = "<img\${1} dst=\"\${2}\"";
- // $text = preg_replace($pattern, $replace, $text);
- /*
- if(! $load) {
- $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />';
- $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i";
- $text = preg_replace($pattern, $replace, $text);
- $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i";
- $text = preg_replace($pattern, $replace, $text);
- }
- */
- /**
- * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well
- */
-
- echo str_replace("\t",' ',$text);
- echo (($_GET['msie'] == 1) ? '</div>' : '</section>');
- echo "</body></html>\r\n";
- killme();
-
- }
-}
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php
index e001ad929..2250e6e44 100644
--- a/Zotlabs/Module/Wall_attach.php
+++ b/Zotlabs/Module/Wall_attach.php
@@ -41,10 +41,12 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$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(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
+ $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
+ if($pm) {
+ // logger('Content-Range: ' . print_r($matches,true));
+ $partial = true;
+ }
}
if($partial) {
diff --git a/Zotlabs/Module/Wfinger.php b/Zotlabs/Module/Wfinger.php
index 2e9307196..753721d27 100644
--- a/Zotlabs/Module/Wfinger.php
+++ b/Zotlabs/Module/Wfinger.php
@@ -32,6 +32,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
$root_resource = false;
+ $pchan = false;
if(strcasecmp(rtrim($resource,'/'),z_root()) === 0)
$root_resource = true;
@@ -57,11 +58,24 @@ class Wfinger extends \Zotlabs\Web\Controller {
$channel = str_replace('~','',basename($resource));
}
- $r = q("select * from channel left join xchan on channel_hash = xchan_hash
- where channel_address = '%s' limit 1",
- dbesc($channel)
- );
-
+ if(substr($channel,0,1) === '[' ) {
+ $channel = substr($channel,1);
+ $channel = substr($channel,0,-1);
+ $pchan = true;
+ $r = q("select * from pchan left join xchan on pchan_hash = xchan_hash
+ where pchan_guid = '%s' limit 1",
+ dbesc($channel)
+ );
+ if($r) {
+ $r[0] = pchan_to_chan($r[0]);
+ }
+ }
+ else {
+ $r = q("select * from channel left join xchan on channel_hash = xchan_hash
+ where channel_address = '%s' limit 1",
+ dbesc($channel)
+ );
+ }
}
header('Access-Control-Allow-Origin: *');
@@ -94,7 +108,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
$result['subject'] = $resource;
$aliases = array(
- z_root() . '/channel/' . $r[0]['channel_address'],
+ z_root() . (($pchan) ? '/pchan/' : '/channel/') . $r[0]['channel_address'],
z_root() . '/~' . $r[0]['channel_address']
);
@@ -116,59 +130,87 @@ class Wfinger extends \Zotlabs\Web\Controller {
if($alias != $resource)
$result['aliases'][] = $alias;
- $result['links'] = [
+
+ if($pchan) {
+ $result['links'] = [
- [
- 'rel' => 'http://webfinger.net/rel/avatar',
- 'type' => $r[0]['xchan_photo_mimetype'],
- 'href' => $r[0]['xchan_photo_l']
- ],
+ [
+ 'rel' => 'http://webfinger.net/rel/avatar',
+ 'type' => $r[0]['xchan_photo_mimetype'],
+ 'href' => $r[0]['xchan_photo_l']
+ ],
+
+ [
+ 'rel' => 'http://webfinger.net/rel/profile-page',
+ 'href' => $r[0]['xchan_url'],
+ ],
- [
- 'rel' => 'http://microformats.org/profile/hcard',
- 'type' => 'text/html',
- 'href' => z_root() . '/hcard/' . $r[0]['channel_address']
- ],
+ [
+ 'rel' => 'magic-public-key',
+ 'href' => 'data:application/magic-public-key,' . salmon_key($r[0]['channel_pubkey']),
+ ]
- [
- 'rel' => 'http://webfinger.net/rel/profile-page',
- 'href' => z_root() . '/profile/' . $r[0]['channel_address'],
- ],
-
- [
- 'rel' => 'http://schemas.google.com/g/2010#updates-from',
- 'type' => 'application/atom+xml',
- 'href' => z_root() . '/ofeed/' . $r[0]['channel_address']
- ],
+ ];
- [
- 'rel' => 'http://webfinger.net/rel/blog',
- 'href' => z_root() . '/channel/' . $r[0]['channel_address'],
- ],
-
- [
- 'rel' => 'http://ostatus.org/schema/1.0/subscribe',
- 'template' => z_root() . '/follow?f=&url={uri}',
- ],
-
- [
- 'rel' => 'http://purl.org/zot/protocol',
- 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
- ],
- [
- 'rel' => 'http://purl.org/openwebauth/v1',
- 'type' => 'application/x-zot+json',
- 'href' => z_root() . '/owa',
- ],
+ }
+ else {
+
+ $result['links'] = [
+
+ [
+ 'rel' => 'http://webfinger.net/rel/avatar',
+ 'type' => $r[0]['xchan_photo_mimetype'],
+ 'href' => $r[0]['xchan_photo_l']
+ ],
+
+ [
+ 'rel' => 'http://microformats.org/profile/hcard',
+ 'type' => 'text/html',
+ 'href' => z_root() . '/hcard/' . $r[0]['channel_address']
+ ],
+
+
+ [
+ 'rel' => 'http://webfinger.net/rel/profile-page',
+ 'href' => z_root() . '/profile/' . $r[0]['channel_address'],
+ ],
+
+ [
+ 'rel' => 'http://schemas.google.com/g/2010#updates-from',
+ 'type' => 'application/atom+xml',
+ 'href' => z_root() . '/ofeed/' . $r[0]['channel_address']
+ ],
+
+ [
+ 'rel' => 'http://webfinger.net/rel/blog',
+ 'href' => z_root() . '/channel/' . $r[0]['channel_address'],
+ ],
+
+ [
+ 'rel' => 'http://ostatus.org/schema/1.0/subscribe',
+ 'template' => z_root() . '/follow?f=&url={uri}',
+ ],
+
+ [
+ 'rel' => 'http://purl.org/zot/protocol',
+ 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
+ ],
+
+ [
+ 'rel' => 'http://purl.org/openwebauth/v1',
+ 'type' => 'application/x-zot+json',
+ 'href' => z_root() . '/owa',
+ ],
+
+
+ [
+ 'rel' => 'magic-public-key',
+ 'href' => 'data:application/magic-public-key,' . salmon_key($r[0]['channel_pubkey']),
+ ]
+ ];
+ }
-
- [
- 'rel' => 'magic-public-key',
- 'href' => 'data:application/magic-public-key,' . salmon_key($r[0]['channel_pubkey']),
- ]
- ];
-
if($zot) {
// get a zotinfo packet and return it with webfinger
$result['zot'] = zotinfo( [ 'address' => $r[0]['xchan_addr'] ]);
@@ -180,7 +222,7 @@ class Wfinger extends \Zotlabs\Web\Controller {
killme();
}
- $arr = [ 'channel' => $r[0], 'request' => $_REQUEST, 'result' => $result ];
+ $arr = [ 'channel' => $r[0], 'pchan' => $pchan, 'request' => $_REQUEST, 'result' => $result ];
call_hooks('webfinger',$arr);
diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php
index 2d2d8e2b7..ae543eb98 100644
--- a/Zotlabs/Module/Wiki.php
+++ b/Zotlabs/Module/Wiki.php
@@ -293,31 +293,43 @@ class Wiki extends \Zotlabs\Web\Controller {
$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'])) {
+ $x = new \Zotlabs\Widget\Wiki_pages();
+
+ $html = $x->create_missing_page([
+ 'resource_id' => $resource_id,
+ 'channel_id' => $owner['channel_id'],
+ 'channel_address' => $owner['channel_address'],
+ 'refresh' => true
+ ]);
+ //json_return_and_die(array('pages' => $page_list_html, 'message' => '', 'success' => true));
notice( t('Error retrieving page content') . EOL);
- goaway(z_root() . '/' . argv(0) . '/' . argv(1) );
+ //goaway(z_root() . '/' . argv(0) . '/' . argv(1) );
+ $renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
+ $showPageControls = $wiki_editor;
}
-
- $mimeType = $p['pageMimeType'];
-
- $sampleContent = (($mimeType == 'text/bbcode') ? '[h3]' . t('New page') . '[/h3]' : '### ' . t('New page'));
- if($mimeType === 'text/plain')
- $sampleContent = t('New page');
-
- $content = (($p['content'] == '') ? $sampleContent : $p['content']);
-
- // Render the Markdown-formatted page content in HTML
- if($mimeType == 'text/bbcode') {
- $renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
- }
- elseif($mimeType === 'text/plain') {
- $renderedContent = str_replace(["\n",' ',"\t"],[EOL,'&nbsp;','&nbsp;&nbsp;&nbsp;&nbsp;'],htmlentities($content,ENT_COMPAT,'UTF-8',false));
- }
- elseif($mimeType === 'text/markdown') {
- $content = Zlib\MarkdownSoap::unescape($content);
- $html = Zlib\NativeWikiPage::generate_toc(zidify_text(MarkdownExtra::defaultTransform(Zlib\NativeWikiPage::bbcode($content))));
- $renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
- }
- $showPageControls = $wiki_editor;
+ else {
+ $mimeType = $p['pageMimeType'];
+
+ $sampleContent = (($mimeType == 'text/bbcode') ? '[h3]' . t('New page') . '[/h3]' : '### ' . t('New page'));
+ if($mimeType === 'text/plain')
+ $sampleContent = t('New page');
+
+ $content = (($p['content'] == '') ? $sampleContent : $p['content']);
+
+ // Render the Markdown-formatted page content in HTML
+ if($mimeType == 'text/bbcode') {
+ $renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
+ }
+ elseif($mimeType === 'text/plain') {
+ $renderedContent = str_replace(["\n",' ',"\t"],[EOL,'&nbsp;','&nbsp;&nbsp;&nbsp;&nbsp;'],htmlentities($content,ENT_COMPAT,'UTF-8',false));
+ }
+ elseif($mimeType === 'text/markdown') {
+ $content = Zlib\MarkdownSoap::unescape($content);
+ $html = Zlib\NativeWikiPage::generate_toc(zidify_text(MarkdownExtra::defaultTransform(Zlib\NativeWikiPage::bbcode($content))));
+ $renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
+ }
+ $showPageControls = $wiki_editor;
+ }
break;
// default: // Strip the extraneous URL components
// goaway('/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/' . $pageUrlName);
@@ -430,11 +442,15 @@ class Wiki extends \Zotlabs\Web\Controller {
goaway('/' . argv(0) . '/' . $nick . '/');
}
$wiki = array();
+
+ // backslashes won't work well in the javascript functions
+ $name = str_replace('\\','',$_POST['wikiName']);
+
// Generate new wiki info from input name
$wiki['postVisible'] = ((intval($_POST['postVisible'])) ? 1 : 0);
- $wiki['rawName'] = $_POST['wikiName'];
- $wiki['htmlName'] = escape_tags($_POST['wikiName']);
- $wiki['urlName'] = urlencode(urlencode($_POST['wikiName']));
+ $wiki['rawName'] = $name;
+ $wiki['htmlName'] = escape_tags($name);
+ $wiki['urlName'] = urlencode(urlencode($name));
$wiki['mimeType'] = $_POST['mimeType'];
$wiki['typelock'] = $_POST['typelock'];
@@ -555,9 +571,14 @@ class Wiki extends \Zotlabs\Web\Controller {
}
$name = $_POST['pageName']; //Get new page name
- if(urlencode(escape_tags($_POST['pageName'])) === '') {
- json_return_and_die(array('message' => 'Error creating page. Invalid name.', 'success' => false));
+
+ // backslashes won't work well in the javascript functions
+ $name = str_replace('\\','',$name);
+
+ if(urlencode(escape_tags($name)) === '') {
+ json_return_and_die(array('message' => 'Error creating page. Invalid name (' . print_r($_POST,true) . ').', 'success' => false));
}
+
$page = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id, $mimetype);
if($page['item_id']) {
@@ -626,7 +647,7 @@ class Wiki extends \Zotlabs\Web\Controller {
logger('Wiki write permission denied. ' . EOL);
json_return_and_die(array('success' => false));
}
-
+
$saved = Zlib\NativeWikiPage::save_page(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName, 'content' => $content));
if($saved['success']) {
@@ -758,7 +779,7 @@ class Wiki extends \Zotlabs\Web\Controller {
if ((argc() === 4) && (argv(2) === 'rename') && (argv(3) === 'page')) {
$resource_id = $_POST['resource_id'];
$pageUrlName = $_POST['oldName'];
- $pageNewName = $_POST['newName'];
+ $pageNewName = str_replace('\\','',$_POST['newName']);
if ($pageUrlName === 'Home') {
json_return_and_die(array('message' => 'Cannot rename Home','success' => false));
}
diff --git a/Zotlabs/Render/Comanche.php b/Zotlabs/Render/Comanche.php
index 8831bd117..fb400b6fe 100644
--- a/Zotlabs/Render/Comanche.php
+++ b/Zotlabs/Render/Comanche.php
@@ -5,10 +5,20 @@ namespace Zotlabs\Render;
require_once('include/security.php');
require_once('include/menu.php');
-
+/**
+ * @brief Comanche Page Description Language.
+ *
+ * Comanche is a markup language similar to bbcode with which to create elaborate
+ * and complex web pages by assembling them from a series of components - some of
+ * which are pre-built and others which can be defined on the fly. Comanche uses
+ * a Page Decription Language to create these pages.
+ *
+ * Comanche primarily chooses what content will appear in various regions of the
+ * page. The various regions have names and these names can change depending on
+ * what layout template you choose.
+ */
class Comanche {
-
function parse($s, $pass = 0) {
$matches = array();
@@ -18,13 +28,13 @@ class Comanche {
$s = str_replace($mtch[0], '', $s);
}
}
-
+
/*
- * This section supports the "switch" statement of the form given by the following
- * example. The [default][/default] block must be the last in the arbitrary
+ * This section supports the "switch" statement of the form given by the following
+ * example. The [default][/default] block must be the last in the arbitrary
* list of cases. The first case that matches the switch variable is used
* and the rest are not evaluated.
- *
+ *
* [switch observer.language]
* [case de]
* [block]german-content[/block]
@@ -37,7 +47,7 @@ class Comanche {
* [/default]
* [/switch]
*/
-
+
$cnt = preg_match_all("/\[switch (.*?)\](.*?)\[default\](.*?)\[\/default\]\s*\[\/switch\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
@@ -60,7 +70,7 @@ class Comanche {
}
}
}
-
+
$cnt = preg_match_all("/\[if (.*?)\](.*?)\[else\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
@@ -89,7 +99,6 @@ class Comanche {
$this->parse_pass0($s);
else
$this->parse_pass1($s);
-
}
function parse_pass0($s) {
@@ -103,7 +112,7 @@ class Comanche {
$cnt = preg_match("/\[template=(.*?)\](.*?)\[\/template\]/ism", $s, $matches);
if($cnt) {
\App::$page['template'] = trim($matches[2]);
- \App::$page['template_style'] = trim($matches[2]) . '_' . $matches[1];
+ \App::$page['template_style'] = trim($matches[2]) . '_' . $matches[1];
}
$cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $s, $matches);
@@ -145,20 +154,23 @@ class Comanche {
}
/**
+ * @brief Replace conditional variables with real values.
+ *
* Currently supported condition variables:
+ * * $config.xxx.yyy - get_config with cat = xxx and k = yyy
+ * * $request - request uri for this page
+ * * $observer.language - viewer's preferred language (closest match)
+ * * $observer.address - xchan_addr or false
+ * * $observer.name - xchan_name or false
+ * * $observer - xchan_hash of observer or empty string
+ * * $local_channel - logged in channel_id or false
*
- * $config.xxx.yyy - get_config with cat = xxx and k = yyy
- * $request - request uri for this page
- * $observer.language - viewer's preferred language (closest match)
- * $observer.address - xchan_addr or false
- * $observer.name - xchan_name or false
- * $observer - xchan_hash of observer or empty string
- * $local_channel - logged in channel_id or false
+ * @param string $v The conditional variable name
+ * @return string|boolean
*/
-
function get_condition_var($v) {
if($v) {
- $x = explode('.',$v);
+ $x = explode('.', $v);
if($x[0] == 'config')
return get_config($x[1],$x[2]);
elseif($x[0] === 'request')
@@ -179,6 +191,7 @@ class Comanche {
return $y['xchan_name'];
elseif($x[1] == 'webname')
return substr($y['xchan_addr'],0,strpos($y['xchan_addr'],'@'));
+
return false;
}
return get_observer_hash();
@@ -186,30 +199,39 @@ class Comanche {
else
return false;
}
+
return false;
}
+ /**
+ * @brief Test for Conditional Execution conditions.
+ *
+ * This is extensible. The first version of variable testing supports tests of the forms:
+ *
+ * - [if $config.system.foo ~= baz] which will check if get_config('system','foo') contains the string 'baz';
+ * - [if $config.system.foo == baz] which will check if get_config('system','foo') is the string 'baz';
+ * - [if $config.system.foo != baz] which will check if get_config('system','foo') is not the string 'baz';
+ * - [if $config.system.foo >= 3] which will check if get_config('system','foo') is greater than or equal to 3;
+ * - [if $config.system.foo > 3] which will check if get_config('system','foo') is greater than 3;
+ * - [if $config.system.foo <= 3] which will check if get_config('system','foo') is less than or equal to 3;
+ * - [if $config.system.foo < 3] which will check if get_config('system','foo') is less than 3;
+ *
+ * - [if $config.system.foo {} baz] which will check if 'baz' is an array element in get_config('system','foo')
+ * - [if $config.system.foo {*} baz] which will check if 'baz' is an array key in get_config('system','foo')
+ * - [if $config.system.foo] which will check for a return of a true condition for get_config('system','foo');
+ *
+ * The values 0, '', an empty array, and an unset value will all evaluate to false.
+ *
+ * @param int|string $s
+ * @return boolean
+ */
function test_condition($s) {
- // This is extensible. The first version of variable testing supports tests of the forms:
-
- // [if $config.system.foo ~= baz] which will check if get_config('system','foo') contains the string 'baz';
- // [if $config.system.foo == baz] which will check if get_config('system','foo') is the string 'baz';
- // [if $config.system.foo != baz] which will check if get_config('system','foo') is not the string 'baz';
- // [if $config.system.foo >= 3] which will check if get_config('system','foo') is greater than or equal to 3;
- // [if $config.system.foo > 3] which will check if get_config('system','foo') is greater than 3;
-
- // [if $config.system.foo <= 3] which will check if get_config('system','foo') is less than or equal to 3;
- // [if $config.system.foo < 3] which will check if get_config('system','foo') is less than 3;
-
- // [if $config.system.foo {} baz] which will check if 'baz' is an array element in get_config('system','foo')
- // [if $config.system.foo {*} baz] which will check if 'baz' is an array key in get_config('system','foo')
- // [if $config.system.foo] which will check for a return of a true condition for get_config('system','foo');
- // The values 0, '', an empty array, and an unset value will all evaluate to false.
if(preg_match('/[\$](.*?)\s\~\=\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]);
if(stripos($x,trim($matches[2])) !== false)
return true;
+
return false;
}
@@ -217,6 +239,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]);
if($x == trim($matches[2]))
return true;
+
return false;
}
@@ -224,6 +247,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]);
if($x != trim($matches[2]))
return true;
+
return false;
}
@@ -231,24 +255,31 @@ class Comanche {
$x = $this->get_condition_var($matches[1]);
if($x >= trim($matches[2]))
return true;
+
return false;
}
+
if(preg_match('/[\$](.*?)\s\<\=\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]);
if($x <= trim($matches[2]))
return true;
+
return false;
}
+
if(preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]);
if($x > trim($matches[2]))
return true;
+
return false;
}
+
if(preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) {
$x = $this->get_condition_var($matches[1]);
if($x < trim($matches[2]))
return true;
+
return false;
}
@@ -256,6 +287,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]);
if(is_array($x) && in_array(trim($matches[2]),$x))
return true;
+
return false;
}
@@ -263,6 +295,7 @@ class Comanche {
$x = $this->get_condition_var($matches[1]);
if(is_array($x) && array_key_exists(trim($matches[2]),$x))
return true;
+
return false;
}
@@ -270,13 +303,21 @@ class Comanche {
$x = $this->get_condition_var($matches[1]);
if($x)
return true;
+
return false;
}
- return false;
+ return false;
}
-
+ /**
+ * @brief Return rendered menu for current channel_id.
+ *
+ * @see menu_render()
+ * @param string $s
+ * @param string $class (optional) default empty
+ * @return string
+ */
function menu($s, $class = '') {
$channel_id = $this->get_channel_id();
@@ -291,7 +332,7 @@ class Comanche {
}
if($channel_id) {
- $m = menu_fetch($name,$channel_id, get_observer_hash());
+ $m = menu_fetch($name, $channel_id, get_observer_hash());
return menu_render($m, $class, $edit = false, $var);
}
}
@@ -309,9 +350,8 @@ class Comanche {
* Returns the channel_id of the profile owner of the page, or the local_channel
* if there is no profile owner. Otherwise returns 0.
*
- * @return channel_id
+ * @return int channel_id
*/
-
function get_channel_id() {
$channel_id = ((is_array(\App::$profile)) ? \App::$profile['profile_uid'] : 0);
@@ -321,6 +361,13 @@ class Comanche {
return $channel_id;
}
+ /**
+ * @brief Returns a parsed block.
+ *
+ * @param string $s
+ * @param string $class (optional) default empty
+ * @return string parsed HTML of block
+ */
function block($s, $class = '') {
$var = array();
$matches = array();
@@ -339,7 +386,7 @@ class Comanche {
$channel_id = $this->get_channel_id();
if($channel_id) {
- $r = q("select * from item inner join iconfig on iconfig.iid = item.id and item.uid = %d
+ $r = q("select * from item inner join iconfig on iconfig.iid = item.id and item.uid = %d
and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' and iconfig.v = '%s' limit 1",
intval($channel_id),
dbesc($name)
@@ -381,6 +428,12 @@ class Comanche {
return $o;
}
+ /**
+ * @brief Include JS depending on framework.
+ *
+ * @param string $s
+ * @return string
+ */
function js($s) {
switch($s) {
@@ -401,9 +454,14 @@ class Comanche {
$ret .= $init;
return $ret;
-
}
+ /**
+ * @brief Include CSS depending on framework.
+ *
+ * @param string $s
+ * @return string
+ */
function css($s) {
switch($s) {
@@ -418,17 +476,22 @@ class Comanche {
$ret = '<link rel="stylesheet" href="' . z_root() . '/' . $path . '" type="text/css" media="screen">';
return $ret;
-
}
- // This doesn't really belong in Comanche, but it could also be argued that it is the perfect place.
- // We need to be able to select what kind of template and decoration to use for the webpage at the heart of our content.
- // For now we'll allow an '[authored]' element which defaults to name and date, or 'none' to remove these, and perhaps
- // 'full' to provide a social network style profile photo.
- // But leave it open to have richer templating options and perhaps ultimately discard this one, once we have a better idea
- // of what template and webpage options we might desire.
-
- function webpage(&$a,$s) {
+ /**
+ * This doesn't really belong in Comanche, but it could also be argued that it is the perfect place.
+ * We need to be able to select what kind of template and decoration to use for the webpage at the heart of our content.
+ * For now we'll allow an '[authored]' element which defaults to name and date, or 'none' to remove these, and perhaps
+ * 'full' to provide a social network style profile photo.
+ *
+ * But leave it open to have richer templating options and perhaps ultimately discard this one, once we have a better idea
+ * of what template and webpage options we might desire.
+ *
+ * @param[in,out] array $a
+ * @param string $s
+ * @return array
+ */
+ function webpage(&$a, $s) {
$ret = array();
$matches = array();
@@ -438,22 +501,20 @@ class Comanche {
$ret['authored'] = $mtch[1];
}
}
+
return $ret;
}
-
/**
- * Render a widget
+ * @brief Render a widget.
*
* @param string $name
* @param string $text
*/
-
function widget($name, $text) {
$vars = array();
$matches = array();
-
$cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $text, $matches, PREG_SET_ORDER);
if ($cnt) {
foreach ($matches as $mtch) {
@@ -469,15 +530,23 @@ class Comanche {
if(file_exists('Zotlabs/SiteWidget/' . $clsname . '.php'))
require_once('Zotlabs/SiteWidget/' . $clsname . '.php');
+ elseif(file_exists('widget/' . $clsname . '/' . $clsname . '.php'))
+ require_once('widget/' . $clsname . '/' . $clsname . '.php');
elseif(file_exists('Zotlabs/Widget/' . $clsname . '.php'))
require_once('Zotlabs/Widget/' . $clsname . '.php');
+ else {
+ $pth = theme_include($clsname . '.php');
+ if($pth) {
+ require_once($pth);
+ }
+ }
if(class_exists($nsname)) {
$x = new $nsname;
$f = 'widget';
if(method_exists($x,$f)) {
return $x->$f($vars);
}
- }
+ }
$func = 'widget_' . trim($name);
@@ -486,11 +555,13 @@ class Comanche {
require_once('widget/' . trim($name) . '.php');
elseif(file_exists('widget/' . trim($name) . '/' . trim($name) . '.php'))
require_once('widget/' . trim($name) . '/' . trim($name) . '.php');
- }
- else {
- $theme_widget = $func . '.php';
- if((! function_exists($func)) && theme_include($theme_widget))
- require_once(theme_include($theme_widget));
+
+ if(! function_exists($func)) {
+ $theme_widget = $func . '.php';
+ if(theme_include($theme_widget)) {
+ require_once(theme_include($theme_widget));
+ }
+ }
}
if(function_exists($func))
@@ -560,9 +631,9 @@ class Comanche {
}
- /*
- * @function register_page_template($arr)
- * Registers a page template/variant for use by Comanche selectors
+ /**
+ * @brief Registers a page template/variant for use by Comanche selectors.
+ *
* @param array $arr
* 'template' => template name
* 'variant' => array(
@@ -574,8 +645,6 @@ class Comanche {
* )
* )
*/
-
-
function register_page_template($arr) {
\App::$page_layouts[$arr['template']] = array($arr['variant']);
return;
diff --git a/Zotlabs/Render/Theme.php b/Zotlabs/Render/Theme.php
index 3a0116abe..09cc7a4d4 100644
--- a/Zotlabs/Render/Theme.php
+++ b/Zotlabs/Render/Theme.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Render;
+use App;
+
class Theme {
@@ -11,17 +13,28 @@ class Theme {
static $session_theme = null;
static $session_mobile_theme = null;
- static $base_themes = array('redbasic');
+ /**
+ * @brief Array with base or fallback themes.
+ */
+ static $base_themes = array('redbasic');
+
+ /**
+ * @brief Figure out the best matching theme and return it.
+ *
+ * The theme will depend on channel settings, mobile, session, core compatibility, etc.
+ *
+ * @return array
+ */
static public function current(){
- self::$system_theme = ((isset(\App::$config['system']['theme']))
+ self::$system_theme = ((isset(\App::$config['system']['theme']))
? \App::$config['system']['theme'] : '');
- self::$session_theme = ((isset($_SESSION) && x($_SESSION,'theme'))
+ self::$session_theme = ((isset($_SESSION) && x($_SESSION, 'theme'))
? $_SESSION['theme'] : self::$system_theme);
- self::$system_mobile_theme = ((isset(\App::$config['system']['mobile_theme']))
+ self::$system_mobile_theme = ((isset(\App::$config['system']['mobile_theme']))
? \App::$config['system']['mobile_theme'] : '');
- self::$session_mobile_theme = ((isset($_SESSION) && x($_SESSION,'mobile_theme'))
+ self::$session_mobile_theme = ((isset($_SESSION) && x($_SESSION, 'mobile_theme'))
? $_SESSION['mobile_theme'] : self::$system_mobile_theme);
$page_theme = null;
@@ -66,7 +79,7 @@ class Theme {
$chosen_theme = $page_theme;
}
}
- if(array_key_exists('theme_preview',$_GET))
+ if(array_key_exists('theme_preview', $_GET))
$chosen_theme = $_GET['theme_preview'];
// Allow theme selection of the form 'theme_name:schema_name'
@@ -91,14 +104,12 @@ class Theme {
}
// Worst case scenario, the default base theme or themes don't exist; perhaps somebody renamed it/them.
-
- // Find any theme at all and use it.
-
- $fallback = array_merge(glob('view/theme/*/css/style.css'),glob('view/theme/*/php/style.php'));
- if(count($fallback))
- return(array(str_replace('view/theme/','', substr($fallback[0],0,-14))));
+ // Find any theme at all and use it.
+ $fallback = array_merge(glob('view/theme/*/css/style.css'), glob('view/theme/*/php/style.php'));
+ if(count($fallback))
+ return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14))));
}
@@ -107,12 +118,11 @@ class Theme {
*
* Provide a sane default if nothing is chosen or the specified theme does not exist.
*
- * @param bool $installing default false
+ * @param bool $installing (optional) default false, if true return the name of the first base theme
*
* @return string
*/
-
- function url($installing = false) {
+ static public function url($installing = false) {
if($installing)
return self::$base_themes[0];
@@ -125,9 +135,10 @@ class Theme {
$opts = '';
$opts = ((\App::$profile_uid) ? '?f=&puid=' . \App::$profile_uid : '');
- $schema_str = ((x(\App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
+ $schema_str = ((x(\App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
if(($s) && (! $schema_str))
$schema_str = '&schema=' . $s;
+
$opts .= $schema_str;
if(file_exists('view/theme/' . $t . '/php/style.php'))
@@ -139,7 +150,6 @@ class Theme {
function debug() {
logger('system_theme: ' . self::$system_theme);
logger('session_theme: ' . self::$session_theme);
-
}
}
diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php
index 6f6f4a292..c21b68971 100644
--- a/Zotlabs/Storage/Browser.php
+++ b/Zotlabs/Storage/Browser.php
@@ -12,7 +12,7 @@ use Sabre\DAV;
*
* @extends \\Sabre\\DAV\\Browser\\Plugin
*
- * @link http://github.com/friendica/red
+ * @link http://github.com/redmatrix/hubzilla
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
*/
class Browser extends DAV\Browser\Plugin {
@@ -173,6 +173,7 @@ class Browser extends DAV\Browser\Plugin {
$displayName = $this->escapeHTML($displayName);
$type = $this->escapeHTML($type);
+
$icon = '';
if ($this->enableAssets) {
@@ -196,12 +197,53 @@ class Browser extends DAV\Browser\Plugin {
}
}
+
+ // generate preview icons for tile view.
+ // Currently we only handle images, but this could potentially be extended with plugins
+ // to provide document and video thumbnails. SVG, PDF and office documents have some
+ // security concerns and should only be allowed on single-user sites with tightly controlled
+ // upload access. system.thumbnail_security should be set to 1 if you want to include these
+ // types
+
+ $photo_icon = '';
+ $preview_style = intval(get_config('system','thumbnail_security',0));
+
+ $r = q("select content from attach where hash = '%s' and uid = %d limit 1",
+ dbesc($attachHash),
+ intval($owner)
+ );
+
+ if($r && file_exists(dbunescbin($r[0]['content']) . '.thumb')) {
+ $photo_icon = 'data:image/jpeg;base64,' . base64_encode(file_get_contents(dbunescbin($r[0]['content']) . '.thumb'));
+// logger('found thumb: ' . $photo_icon);
+ }
+
+ if(strpos($type,'image/') === 0 && $attachHash) {
+ $r = q("select resource_id, imgscale from photo where resource_id = '%s' and imgscale in ( %d, %d ) order by imgscale asc limit 1",
+ dbesc($attachHash),
+ intval(PHOTO_RES_320),
+ intval(PHOTO_RES_PROFILE_80)
+ );
+ if($r) {
+ $photo_icon = 'photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale'];
+ }
+ if($type === 'image/svg+xml' && $preview_style > 0) {
+ $photo_icon = $fullPath;
+ }
+ }
+
+ $g = [ 'resource_id' => $attachHash, 'thumbnail' => $photo_icon, 'security' => $preview_style ];
+ call_hooks('file_thumbnail', $g);
+ $photo_icon = $g['thumbnail'];
+
+
$attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"fa fa-arrow-circle-o-down\"></i></a>";
// put the array for this file together
$ft['attachId'] = $this->findAttachIdByHash($attachHash);
$ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser();
$ft['icon'] = $icon;
+ $ft['photo_icon'] = $photo_icon;
$ft['attachIcon'] = (($size) ? $attachIcon : '');
// @todo Should this be an item value, not a global one?
$ft['is_owner'] = $is_owner;
@@ -216,11 +258,13 @@ class Browser extends DAV\Browser\Plugin {
$f[] = $ft;
}
+
$output = '';
if ($this->enablePost) {
$this->server->emit('onHTMLActionsPanel', array($parent, &$output, $path));
}
+
$html .= replace_macros(get_markup_template('cloud.tpl'), array(
'$header' => t('Files') . ": " . $this->escapeHTML($path) . "/",
'$total' => t('Total'),
@@ -230,6 +274,8 @@ class Browser extends DAV\Browser\Plugin {
'$upload' => t('Upload'),
'$is_owner' => $is_owner,
'$parentpath' => $parentpath,
+ '$cpath' => bin2hex(\App::$query_string),
+ '$tiles' => intval($_SESSION['cloud_tiles']),
'$entries' => $f,
'$name' => t('Name'),
'$type' => t('Type'),
@@ -327,8 +373,6 @@ class Browser extends DAV\Browser\Plugin {
if(strpos($path,$special) === 0)
$path = trim(substr($path,$count),'/');
- $info = t('Please use DAV to upload large (video, audio) files.<br>See <a class="zrl" href="help/member/member_guide#Cloud_Desktop_Clients">Cloud Desktop Clients</a>');
-
$output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array(
'$folder_header' => t('Create new folder'),
@@ -336,7 +380,6 @@ class Browser extends DAV\Browser\Plugin {
'$upload_header' => t('Upload file'),
'$upload_submit' => t('Upload'),
'$quota' => $quota,
- '$info' => $info,
'$channick' => $this->auth->owner_nick,
'$aclselect' => $aclselect,
'$allow_cid' => acl2json($channel_acl['allow_cid']),
diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php
index 0ed7a3c68..510d463c1 100644
--- a/Zotlabs/Storage/Directory.php
+++ b/Zotlabs/Storage/Directory.php
@@ -16,7 +16,7 @@ use Sabre\DAV;
* @link http://github.com/friendica/red
* @license http://opensource.org/licenses/mit-license.php The MIT License (MIT)
*/
-class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
+class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMoveTarget {
/**
* @brief The path inside /cloud
@@ -299,6 +299,17 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$is_photo = 1;
}
+ // If we know it's a photo, over-ride the type in case the source system could not determine what it was
+
+ if($is_photo) {
+ q("update attach set filetype = '%s' where hash = '%s' and uid = %d",
+ dbesc($gis['mime']),
+ dbesc($hash),
+ intval($c[0]['channel_id'])
+ );
+ }
+
+
// updates entry with filesize and timestamp
$d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d",
dbesc($size),
@@ -351,6 +362,8 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$args = array( 'resource_id' => $hash, 'album' => $album, 'os_syspath' => $f, 'os_path' => $xpath['os_path'], 'display_path' => $xpath['path'], 'filename' => $name, 'getimagesize' => $gis, 'directory' => $direct);
$p = photo_upload($c[0], \App::get_observer(), $args);
}
+
+ \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $this->folder_hash ]);
$sync = attach_export_data($c[0], $hash);
@@ -444,6 +457,22 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
return false;
}
+
+ public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) {
+
+ if(! $this->auth->owner_id) {
+ return false;
+ }
+
+ if(! ($sourceNode->data && $sourceNode->data->hash)) {
+ return false;
+ }
+
+ return attach_move($this->auth->owner_id, $sourceNode->data->hash, $this->folder_hash);
+
+ }
+
+
/**
* @todo add description of what this function does.
*
@@ -662,7 +691,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
}
$prefix = '';
- $suffix = '';
+ $suffix = ' order by is_dir desc, filename asc ';
$r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix",
dbesc($folder),
diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php
index 947a9fde3..53d5d3476 100644
--- a/Zotlabs/Storage/File.php
+++ b/Zotlabs/Storage/File.php
@@ -129,12 +129,16 @@ class File extends DAV\Node implements DAV\IFile {
$album = '';
$os_path = '';
- $r = q("SELECT flags, folder, os_storage, os_path, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
+ $r = q("SELECT flags, folder, os_storage, os_path, display_path, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
dbesc($this->data['hash']),
intval($c[0]['channel_id'])
);
if ($r) {
+
$os_path = $r[0]['os_path'];
+ $display_path = $r[0]['display_path'];
+ $filename = $r[0]['filename'];
+
if (intval($r[0]['os_storage'])) {
$d = q("select folder, content from attach where hash = '%s' and uid = %d limit 1",
@@ -168,6 +172,17 @@ class File extends DAV\Node implements DAV\IFile {
if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) {
$is_photo = 1;
}
+
+ // If we know it's a photo, over-ride the type in case the source system could not determine what it was
+
+ if($is_photo) {
+ q("update attach set filetype = '%s' where hash = '%s' and uid = %d",
+ dbesc($gis['mime']),
+ dbesc($this->data['hash']),
+ intval($this->data['uid'])
+ );
+ }
+
}
else {
// this shouldn't happen any more
@@ -199,7 +214,7 @@ class File extends DAV\Node implements DAV\IFile {
if($is_photo) {
require_once('include/photos.php');
- $args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_syspath' => $f, 'os_path' => $os_path, 'filename' => $r[0]['filename'], 'getimagesize' => $gis, 'directory' => $direct );
+ $args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_syspath' => $f, 'os_path' => $os_path, 'display_path' => $display_path, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct );
$p = photo_upload($c[0],\App::get_observer(),$args);
}
@@ -233,6 +248,9 @@ class File extends DAV\Node implements DAV\IFile {
}
}
+ \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $this->data['hash'] ]);
+
+
$sync = attach_export_data($c[0],$this->data['hash']);
if($sync)
diff --git a/Zotlabs/Thumbs/Epubthumb.php b/Zotlabs/Thumbs/Epubthumb.php
new file mode 100644
index 000000000..4213b5267
--- /dev/null
+++ b/Zotlabs/Thumbs/Epubthumb.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Zotlabs\Thumbs;
+
+require_once('library/epub-meta/epub.php');
+
+class Epubthumb {
+
+ function Match($type) {
+ return(($type === 'application/epub+zip') ? true : false );
+ }
+
+ function Thumb($attach,$preview_style,$height = 300, $width = 300) {
+
+ $photo = false;
+
+ $ep = new \Epub(dbunescbin($attach['content']));
+ $data = $ep->Cover();
+
+ if($data['found']) {
+ $photo = $data['data'];
+ }
+
+ if($photo) {
+ $image = imagecreatefromstring($photo);
+ $dest = imagecreatetruecolor( $width, $height );
+ $srcwidth = imagesx($image);
+ $srcheight = imagesy($image);
+
+ imagealphablending($dest, false);
+ imagesavealpha($dest, true);
+ imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight);
+ imagedestroy($image);
+ imagejpeg($dest,dbunescbin($attach['content']) . '.thumb');
+ }
+ }
+}
+
diff --git a/Zotlabs/Thumbs/Mp3audio.php b/Zotlabs/Thumbs/Mp3audio.php
new file mode 100644
index 000000000..000d65b22
--- /dev/null
+++ b/Zotlabs/Thumbs/Mp3audio.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Zotlabs\Thumbs;
+
+use \ID3Parser\ID3Parser;
+
+class Mp3audio {
+
+ function Match($type) {
+ return(($type === 'audio/mpeg') ? true : false );
+ }
+
+ function Thumb($attach,$preview_style,$height = 300, $width = 300) {
+ $p = new ID3Parser();
+
+ $id = $p->analyze(dbunescbin($attach['content']));
+
+ $photo = isset($id['id3v2']['APIC'][0]['data']) ? $id['id3v2']['APIC'][0]['data'] : null;
+ if(is_null($photo) && isset($id['id3v2']['PIC'][0]['data'])) {
+ $photo = $id['id3v2']['PIC'][0]['data'];
+ }
+
+ if($photo) {
+ $image = imagecreatefromstring($photo);
+ $dest = imagecreatetruecolor( $width, $height );
+ $srcwidth = imagesx($image);
+ $srcheight = imagesy($image);
+
+ imagealphablending($dest, false);
+ imagesavealpha($dest, true);
+ imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight);
+ imagedestroy($image);
+ imagejpeg($dest,dbunescbin($attach['content']) . '.thumb');
+ }
+ }
+}
+
diff --git a/Zotlabs/Thumbs/Pdf.php b/Zotlabs/Thumbs/Pdf.php
new file mode 100644
index 000000000..98bcf11b5
--- /dev/null
+++ b/Zotlabs/Thumbs/Pdf.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Zotlabs\Thumbs;
+
+
+class Pdf {
+
+ function Match($type) {
+ return(($type === 'application/pdf') ? true : false );
+ }
+
+ function Thumb($attach,$preview_style,$height = 300, $width = 300) {
+
+ $photo = false;
+
+ $file = dbunescbin($attach['content']);
+ $tmpfile = $file . '.pdf';
+ $outfile = $file . '.jpg';
+
+ $istream = fopen($file,'rb');
+ $ostream = fopen($tmpfile,'wb');
+ if($istream && $ostream) {
+ pipe_streams($istream,$ostream);
+ fclose($istream);
+ fclose($ostream);
+ }
+
+ $imagick_path = get_config('system','imagick_convert_path');
+ if($imagick_path && @file_exists($imagick_path)) {
+ $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -thumbnail ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile);
+ // logger('imagick thumbnail command: ' . $cmd);
+ for($x = 0; $x < 4; $x ++) {
+ exec($cmd);
+ if(! file_exists($outfile)) {
+ logger('imagick scale failed. Retrying.');
+ continue;
+ }
+ }
+ if(! file_exists($outfile)) {
+ logger('imagick scale failed.');
+ }
+ else {
+ @rename($outfile,$file . '.thumb');
+ }
+ }
+ @unlink($tmpfile);
+ }
+}
+
diff --git a/Zotlabs/Thumbs/Text.php b/Zotlabs/Thumbs/Text.php
new file mode 100644
index 000000000..3ee7819bd
--- /dev/null
+++ b/Zotlabs/Thumbs/Text.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Zotlabs\Thumbs;
+
+
+class Text {
+
+ function MatchDefault($type) {
+ return(($type === 'text') ? true : false );
+ }
+
+ function Thumb($attach,$preview_style,$height = 300, $width = 300) {
+
+ $stream = @fopen(dbunescbin($attach['content']),'rb');
+ if($stream) {
+ $content = trim(stream_get_contents($stream,4096));
+ $content = str_replace("\r",'',$content);
+ $content_a = explode("\n",$content);
+ }
+ if($content_a) {
+ $fsize = 4;
+ $lsize = 8;
+ $image = imagecreate($width,$height);
+ imagecolorallocate($image,255,255,255);
+ $colour = imagecolorallocate($image,0,0,0);
+ $border = imagecolorallocate($image,208,208,208);
+
+ $x1 = 0;
+ $y1 = 0;
+ $x2 = ImageSX($image) - 1;
+ $y2 = ImageSY($image) - 1;
+
+ for($i = 0; $i < 2; $i++) {
+ ImageRectangle($image, $x1++, $y1++, $x2--, $y2--, $border);
+ }
+
+ foreach($content_a as $l => $t) {
+ $l = $l + 1;
+ $x = 3;
+ $y = ($l * $lsize) + 3 - $fsize;
+ imagestring($image,1,$x,$y,$t,$colour);
+ if(($l * $lsize) >= $height) {
+ break;
+ }
+ }
+ imagejpeg($image,dbunescbin($attach['content']) . '.thumb');
+ }
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Thumbs/Video.php b/Zotlabs/Thumbs/Video.php
new file mode 100644
index 000000000..05127355e
--- /dev/null
+++ b/Zotlabs/Thumbs/Video.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Zotlabs\Thumbs;
+
+
+class Video {
+
+ function MatchDefault($type) {
+ return(($type === 'video') ? true : false );
+ }
+
+ function Thumb($attach,$preview_style,$height = 300, $width = 300) {
+
+ $photo = false;
+
+ $t = explode('/',$attach['filetype']);
+ if($t[1])
+ $extension = '.' . $t[1];
+ else
+ return;
+
+
+ $file = dbunescbin($attach['content']);
+ $tmpfile = $file . $extension;
+ $outfile = $file . '.jpg';
+
+ $istream = fopen($file,'rb');
+ $ostream = fopen($tmpfile,'wb');
+ if($istream && $ostream) {
+ pipe_streams($istream,$ostream);
+ fclose($istream);
+ fclose($ostream);
+ }
+
+ /*
+ * Note: imagick convert may try to call 'ffmpeg' (or other conversion utilities) under
+ * the covers for this particular operation. If this is not installed or not in the path
+ * for the web server user, errors may be reported in the web server logs.
+ */
+
+
+ $ffmpeg = trim(shell_exec('which ffmpeg'));
+ if($ffmpeg) {
+ logger('ffmpeg not found in path. Video thumbnails may fail.');
+ }
+
+ $imagick_path = get_config('system','imagick_convert_path');
+ if($imagick_path && @file_exists($imagick_path)) {
+ $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -thumbnail ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile);
+ // logger('imagick thumbnail command: ' . $cmd);
+
+ @exec($cmd);
+
+ if(! file_exists($outfile)) {
+ logger('imagick scale failed.');
+ }
+ else {
+ @rename($outfile,$file . '.thumb');
+ }
+ }
+
+ @unlink($tmpfile);
+ }
+}
+
diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php
index 1c66b8cf4..9a8c23a9b 100644
--- a/Zotlabs/Web/HTTPSig.php
+++ b/Zotlabs/Web/HTTPSig.php
@@ -237,7 +237,7 @@ class HTTPSig {
$fields = '(request-target)';
}
- if(head) {
+ if($head) {
foreach($head as $k => $v) {
$headers .= strtolower($k) . ': ' . trim($v) . "\n";
if($fields)
diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php
index 9486130cb..a6b780cdc 100644
--- a/Zotlabs/Web/Router.php
+++ b/Zotlabs/Web/Router.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Web;
+use Exception;
+
/**
*
* We have already parsed the server path into App::$argc and App::$argv
@@ -34,7 +36,7 @@ class Router {
private $controller = null;
/**
- * @brief Router constructor
+ * @brief Router constructor.
*
* @param[in,out] App &$a
* @throws Exception module not found
@@ -98,15 +100,23 @@ class Router {
}
}
- /*
- * This provides a place for plugins to register module handlers which don't otherwise exist
- * on the system, or to completely over-ride an existing module.
- * If the plugin sets 'installed' to true we won't throw a 404 error for the specified module even if
- * there is no specific module file or matching plugin name.
- * The plugin should catch at least one of the module hooks for this URL.
+ $x = [
+ 'module' => $module,
+ 'installed' => \App::$module_loaded,
+ 'controller' => $this->controller
+ ];
+ /**
+ * @hooks module_loaded
+ * Called when a module has been successfully locate to server a URL request.
+ * This provides a place for plugins to register module handlers which don't otherwise exist
+ * on the system, or to completely over-ride an existing module.
+ * If the plugin sets 'installed' to true we won't throw a 404 error for the specified module even if
+ * there is no specific module file or matching plugin name.
+ * The plugin should catch at least one of the module hooks for this URL.
+ * * \e string \b module
+ * * \e boolean \b installed
+ * * \e mixed \b controller - The initialized module object
*/
-
- $x = array('module' => $module, 'installed' => \App::$module_loaded, 'controller' => $this->controller);
call_hooks('module_loaded', $x);
if($x['installed']) {
\App::$module_loaded = true;
@@ -131,14 +141,14 @@ class Router {
}
}
- $x = [
- 'module' => $module,
- 'installed' => \App::$module_loaded,
+ $x = [
+ 'module' => $module,
+ 'installed' => \App::$module_loaded,
'controller' => $this->controller
];
call_hooks('page_not_found',$x);
- // Stupid browser tried to pre-fetch our Javascript img template.
+ // Stupid browser tried to pre-fetch our Javascript img template.
// Don't log the event or return anything - just quietly exit.
if((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
@@ -147,8 +157,8 @@ class Router {
if(get_config('system','log_404',true)) {
logger("Module {$module} not found.", LOGGER_DEBUG, LOG_WARNING);
- logger('index.php: page not found: ' . $_SERVER['REQUEST_URI']
- . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: '
+ logger('index.php: page not found: ' . $_SERVER['REQUEST_URI']
+ . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: '
. $_SERVER['QUERY_STRING'], LOGGER_DEBUG);
}
@@ -255,7 +265,7 @@ class Router {
if(! \App::$error) {
$arr = array('content' => \App::$page['content'], 'replace' => false);
call_hooks(\App::$module . '_mod_content', $arr);
- \App::$page['content'] = $arr['content'];
+
if(! $arr['replace']) {
if($this->controller && method_exists($this->controller,'get')) {
$arr = array('content' => $this->controller->get());
@@ -266,8 +276,8 @@ class Router {
}
}
call_hooks(\App::$module . '_mod_aftercontent', $arr);
- \App::$page['content'] .= $arr['content'];
+ \App::$page['content'] = (($arr['replace']) ? $arr['content'] : \App::$page['content'] . $arr['content']);
}
}
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Widget/Affinity.php b/Zotlabs/Widget/Affinity.php
index 439ba1f33..a3e5b5c07 100644
--- a/Zotlabs/Widget/Affinity.php
+++ b/Zotlabs/Widget/Affinity.php
@@ -9,15 +9,9 @@ class Affinity {
if(! local_channel())
return '';
- // Get default cmin value from pconfig, but allow GET parameter to override
- $cmin = intval(get_pconfig(local_channel(),'affinity','cmin'));
- $cmin = (($cmin) ? $cmin : 0);
- $cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $cmin);
-
- // Get default cmax value from pconfig, but allow GET parameter to override
- $cmax = intval(get_pconfig(local_channel(),'affinity','cmax'));
- $cmax = (($cmax) ? $cmax : 99);
- $cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $cmax);
+
+ $cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : 0);
+ $cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : 99);
if(feature_enabled(local_channel(),'affinity')) {
diff --git a/Zotlabs/Widget/Appcategories.php b/Zotlabs/Widget/Appcategories.php
index 490ec1abc..8ff14230f 100644
--- a/Zotlabs/Widget/Appcategories.php
+++ b/Zotlabs/Widget/Appcategories.php
@@ -26,6 +26,7 @@ class Appcategories {
and term.uid = app_channel
and term.otype = %d
and term.term != 'nav_featured_app'
+ and term.term != 'nav_pinned_app'
order by term.term asc",
intval(local_channel()),
intval(TERM_OBJ_APP)
diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php
index 305869706..9bfa9742a 100644
--- a/Zotlabs/Widget/Categories.php
+++ b/Zotlabs/Widget/Categories.php
@@ -13,8 +13,14 @@ class Categories {
if(($cards) && (! feature_enabled(\App::$profile['profile_uid'],'cards')))
return '';
+ $articles = ((array_key_exists('articles',$arr) && $arr['articles']) ? true : false);
+
+ if(($articles) && (! feature_enabled(\App::$profile['profile_uid'],'articles')))
+ return '';
+
+
if((! \App::$profile['profile_uid'])
- || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),(($cards) ? 'view_pages' : 'view_stream')))) {
+ || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),(($cards || $articles) ? 'view_pages' : 'view_stream')))) {
return '';
}
@@ -25,6 +31,8 @@ class Categories {
if($cards)
return cardcategories_widget($srchurl, $cat);
+ elseif($articles)
+ return articlecategories_widget($srchurl, $cat);
else
return categories_widget($srchurl, $cat);
diff --git a/Zotlabs/Widget/Conversations.php b/Zotlabs/Widget/Conversations.php
index 56510750f..267d50fa0 100644
--- a/Zotlabs/Widget/Conversations.php
+++ b/Zotlabs/Widget/Conversations.php
@@ -28,6 +28,8 @@ class Conversations {
require_once('include/message.php');
+ $o = '';
+
// private_messages_list() can do other more complicated stuff, for now keep it simple
$r = private_messages_list(local_channel(), $mailbox, \App::$pager['start'], \App::$pager['itemspage']);
@@ -36,13 +38,13 @@ class Conversations {
return $o;
}
- $messages = array();
+ $messages = [];
foreach($r as $rr) {
$selected = ((argc() == 3) ? intval(argv(2)) == intval($rr['id']) : $r[0]['id'] == $rr['id']);
- $messages[] = array(
+ $messages[] = [
'mailbox' => $mailbox,
'id' => $rr['id'],
'from_name' => $rr['from']['xchan_name'],
@@ -57,14 +59,14 @@ class Conversations {
'date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], 'c'),
'seen' => $rr['seen'],
'selected' => ((argv(1) != 'new') ? $selected : '')
- );
+ ];
}
$tpl = get_markup_template('mail_head.tpl');
- $o .= replace_macros($tpl, array(
+ $o .= replace_macros($tpl, [
'$header' => $header,
'$messages' => $messages
- ));
+ ]);
}
return $o;
diff --git a/Zotlabs/Widget/Forums.php b/Zotlabs/Widget/Forums.php
index 002c0ee21..91b987746 100644
--- a/Zotlabs/Widget/Forums.php
+++ b/Zotlabs/Widget/Forums.php
@@ -29,18 +29,32 @@ class Forums {
);
if($x1) {
$xc = ids_to_querystr($x1,'xchan',true);
+
$x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = '1' and xchan in (" . $xc . ") ",
intval(local_channel())
);
- if($x2)
+
+ if($x2) {
$xf = ids_to_querystr($x2,'xchan',true);
+
+ // private forums
+ $x3 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'post_wall' and v = '1' and xchan in (" . $xc . ") and not xchan in (" . $xf . ") ",
+ intval(local_channel())
+ );
+ if($x3) {
+ $xf = ids_to_querystr(array_merge($x2,$x3),'xchan',true);
+ }
+ }
}
$sql_extra = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 ");
- $r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d $sql_extra order by xchan_name $limit ",
+
+
+ $r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d and abook_pending = 0 and abook_ignored = 0 and abook_blocked = 0 $sql_extra order by xchan_name $limit ",
intval(local_channel())
);
+
if(! $r1)
return $o;
@@ -85,9 +99,21 @@ class Forums {
$o .= '<h3>' . t('Forums') . '</h3><ul class="nav nav-pills flex-column">';
foreach($r1 as $rr) {
+
+ $link = 'network?f=&pf=1&cid=' . $rr['abook_id'];
+ if($x3) {
+ foreach($x3 as $xx) {
+ if($rr['xchan_hash'] == $xx['xchan']) {
+ $link = zid($rr['xchan_url']);
+ }
+ }
+ }
+
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-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 .= '<li class="nav-item"><a class="nav-link" href="' . $link . '" ><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/Hq_controls.php b/Zotlabs/Widget/Hq_controls.php
new file mode 100644
index 000000000..0caa54a1a
--- /dev/null
+++ b/Zotlabs/Widget/Hq_controls.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Hq_controls {
+
+ function widget($arr) {
+
+ if (! local_channel())
+ return;
+
+ return replace_macros(get_markup_template('hq_controls.tpl'),
+ [
+ '$title' => t('HQ Control Panel'),
+ '$menu' => [
+ 'create' => [
+ 'label' => t('Create a new post'),
+ 'id' => 'jot-toggle',
+ 'href' => '#',
+ 'class' => ''
+ ]
+ ]
+ ]
+ );
+ }
+}
diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php
index 191f2afb6..5a0c1f3d5 100644
--- a/Zotlabs/Widget/Notifications.php
+++ b/Zotlabs/Widget/Notifications.php
@@ -20,8 +20,10 @@ class Notifications {
'label' => t('View your network activity')
],
'markall' => [
- 'url' => '#',
'label' => t('Mark all notifications read')
+ ],
+ 'filter' => [
+ 'label' => t('Show new posts only')
]
];
@@ -36,8 +38,10 @@ class Notifications {
'label' => t('View your home activity')
],
'markall' => [
- 'url' => '#',
'label' => t('Mark all notifications seen')
+ ],
+ 'filter' => [
+ 'label' => t('Show new posts only')
]
];
@@ -52,7 +56,6 @@ class Notifications {
'label' => t('View your private mails')
],
'markall' => [
- 'url' => '#',
'label' => t('Mark all messages seen')
]
];
@@ -68,7 +71,6 @@ class Notifications {
'label' => t('View events')
],
'markall' => [
- 'url' => '#',
'label' => t('Mark all events seen')
]
];
@@ -104,7 +106,6 @@ class Notifications {
'label' => t('View all notices')
],
'markall' => [
- 'url' => '#',
'label' => t('Mark all notices seen')
]
];
@@ -132,8 +133,10 @@ class Notifications {
'label' => t('View the public stream')
],
'markall' => [
- 'url' => '#',
'label' => t('Mark all notifications seen')
+ ],
+ 'filter' => [
+ 'label' => t('Show new posts only')
]
];
}
@@ -141,7 +144,8 @@ class Notifications {
$o = replace_macros(get_markup_template('notifications_widget.tpl'), array(
'$module' => \App::$module,
'$notifications' => $notifications,
- '$loading' => t('Loading...')
+ '$no_notifications' => t('Sorry, you have got no notifications at the moment'),
+ '$loading' => t('Loading')
));
return $o;
diff --git a/Zotlabs/Widget/Settings_menu.php b/Zotlabs/Widget/Settings_menu.php
index c15ad0980..e15ed96a5 100644
--- a/Zotlabs/Widget/Settings_menu.php
+++ b/Zotlabs/Widget/Settings_menu.php
@@ -107,7 +107,7 @@ class Settings_menu {
if($role === false || $role === 'custom') {
$tabs[] = array(
'label' => t('Connection Default Permissions'),
- 'url' => z_root() . '/connedit/' . $abook_self_id,
+ 'url' => z_root() . '/defperms',
'selected' => ''
);
}
diff --git a/Zotlabs/Widget/Wiki_pages.php b/Zotlabs/Widget/Wiki_pages.php
index 2aad8008f..06b32b5f5 100644
--- a/Zotlabs/Widget/Wiki_pages.php
+++ b/Zotlabs/Widget/Wiki_pages.php
@@ -5,6 +5,42 @@ namespace Zotlabs\Widget;
class Wiki_pages {
+ function create_missing_page($arr) {
+ if(argc() < 4)
+ return;
+
+ $c = channelx_by_nick(argv(1));
+ $w = \Zotlabs\Lib\NativeWiki::exists_by_name($c['channel_id'],urldecode(argv(2)));
+ $arr = array(
+ 'resource_id' => $w['resource_id'],
+ 'channel_id' => $c['channel_id'],
+ 'channel_address' => $c['channel_address'],
+ 'refresh' => false
+ );
+
+ $can_create = perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'write_wiki');
+
+ $can_delete = ((local_channel() && (local_channel() == \App::$profile['uid'])) ? true : false);
+ $pageName = addslashes(escape_tags(urldecode(argv(3))));
+
+ return replace_macros(get_markup_template('wiki_page_not_found.tpl'), array(
+ '$resource_id' => $arr['resource_id'],
+ '$channel_address' => $arr['channel_address'],
+ '$wikiname' => $wikiname,
+ '$canadd' => $can_create,
+ '$candel' => $can_delete,
+ '$addnew' => t('Add new page'),
+ '$typelock' => $typelock,
+ '$lockedtype' => $w['mimeType'],
+ '$mimetype' => mimetype_select(0,$w['mimeType'],
+ [ 'text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]),
+ '$pageName' => array('missingPageName', 'Create Page' , $pageName),
+ '$refresh' => $arr['refresh'],
+ '$options' => t('Options'),
+ '$submit' => t('Submit')
+ ));
+ }
+
function widget($arr) {
if(argc() < 3)
diff --git a/Zotlabs/Zot/Verify.php b/Zotlabs/Zot/Verify.php
index 1d9e6de3f..7abe38d17 100644
--- a/Zotlabs/Zot/Verify.php
+++ b/Zotlabs/Zot/Verify.php
@@ -26,12 +26,11 @@ class Verify {
q("delete from verify where id = %d",
intval($r[0]['id'])
);
- return true;
+ return true;
}
return false;
}
-
function get_meta($type,$channel_id,$token) {
$r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1",
dbesc($type),
@@ -42,12 +41,18 @@ class Verify {
q("delete from verify where id = %d",
intval($r[0]['id'])
);
- return $r[0]['meta'];
+ return $r[0]['meta'];
}
return false;
}
- function purge($type,$interval) {
+ /**
+ * @brief Purge entries of a verify-type older than interval.
+ *
+ * @param string $type Verify type
+ * @param string $interval SQL compatible time interval
+ */
+ function purge($type, $interval) {
q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s",
dbesc($type),
db_utcnow(),