diff --git a/CHANGELOG b/CHANGELOG
index 67077b767..53d8a0f2e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,89 @@
+Hubzilla 1.14 (2016-10-13)
+ - New hook bbcode_filter
+ - Unify the various mail sending instance to enotify::send() and z_mail()
+ - Provide ability for admin to change account password
+ - Replace deprecated Sabre functions
+ - Add plugin hook for 'get_profile_photo'
+ - Convert NULL_DATE to a legal date for compatibility with MySQL strict mode
+ - Allow a site to over-ride the help table-of-contents files
+ - Autoscroll to target post/comment when in single-thread mode
+ - Indicator for own response verb activity
+ - Add server role documentation
+ - Pro: remove 'Additional Features' link for techlevel 0
+ - Upgrade fullcalendar library to version 3
+ - Whitelist button tag in htmlpurifier
+ - Upgrade justifiedGallery library to version 3.6.3
+ - Pubsites improvements
+ - Upgrade foundation library to version 6.2.3
+ - Ability to move photos to another album
+ - Submodules for settings page
+ - Submodules for admin page
+ - Remove chatroom suggestions
+ - Revamped and improved theme select backend
+ - Theme preview
+ - Implement techlevels for pro server role
+ - BBcode checklist
+ - Improve save to folder modal dialog
+ - Case insensitive sort apps
+ - Add authors to post distribution
+ - Redirect to plugin page after enabling to show configuration settings if applicable
+ - Move allowed email domains to admin->security page
+ - Display text around the searched query in documentation search
+ - Comanche observer conditionals
+ - Remove ratings
+ - Context help for /connedit
+ - Provide configurable sidebar table-of-contents indexes for different levels of the help hierarchy
+ - Comanche conditionals
+ - Cover photo enhancements (does not disappear after initial scrolldown)
+ - Website import/export
+ - Server roles (basic, standard and pro)
+
+ Bugfixes
+ - Fix connected time not shown on ajax loaded connections
+ - API issues
+ - Fix readmore.js collapsing on scrolldirection change in some mobile browsers
+ - Personalize Server Emails
+ - Audio player doesn't automatically show for m4a files
+ - Fix ajax page update with /channel?f=&mid=hash
+ - Angle bracket characters in DB password not recognised
+ - Regression: files/photos were not synchronising to channel clones properly
+ - Missing categories in preview mode
+ - attach_store() sql issue
+ - Rename id share_container to distr_container - share_container seem to be blacklisted in various security browser plugins
+ - Add 'map' extension to files served natively by nginx without using the project controller
+ - Zot discovery wasn't returning in all cases (after discovering zot)
+ - Do not show hidden channels in /randprof
+ - Numerous postgres fixes
+ - Illegal offset errors in include/conversation:status_editor() when no permissions array is passed
+ - Patch foundation-6.2.3 to work with jquery-3.1
+ - Custom/expert permissions bug
+ - Mail: return array instead of object
+ - Don't send purge_all notification to self
+ - Saved search: tags and connection searches weren't being saved
+ - Do not allow PERMS_PUBLIC as a choice for writable permission limits
+ - Force cover photos as well as profile photos to be public. As a side effect 'thing' photos will also be considered public
+ - Make lock switching actually work with multiple acl forms
+ - Create smarty dir before any templates can be initialised
+ - Fix aconfig
+ - Broken doc search
+ - Public forum check with custom/expert permissions
+
+ Plugins
+ - Standard Embed: update to convert old corporate bbcodes
+ - Cdav security: fix rw permission check
+ - Cdav: add partial support for recurring events in the browser client (editing/creating is not implemented)
+ - New plugin phpmailer: use phpmailer class instead of php's built-in mail() function
+ - Diaspora: third party on other network comment issue
+ - Diaspora: comment fix (hubzilla originated comment with plugin activated by comment author not making it to Diaspora)
+ - Cdav: provide calendar list view
+ - Diaspora: allow comments on public diaspora posts which were imported by subscribing to public tags.
+ - Wppost: add blog_id parameter for WordPress MU sites such as WordPress.com
+ - Wppost: don't log the password in normal mode
+ - Hubwall: provide choice of sender addresses, the real admin email, postmaster, or noreply.
+ - Chord: General cleanup of chord app
+ - Chord: Update chord binary for modern linux systems
+ - Start grouping addons by server_role
+
Hubzilla 1.12
- extensible permissions so you can create a new permission rule such as "can write to my wiki" or "can see me naked".
- guest access tokens can do anything you let them, including create posts and administer your channel
diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php
index ec974ad61..350dda7a0 100644
--- a/Zotlabs/Daemon/Cron.php
+++ b/Zotlabs/Daemon/Cron.php
@@ -43,7 +43,7 @@ class Cron {
// expire any expired mail
- q("delete from mail where expires != '%s' and expires < %s ",
+ q("delete from mail where expires > '%s' and expires < %s ",
dbesc(NULL_DATE),
db_utcnow()
);
@@ -63,7 +63,7 @@ class Cron {
// delete expired access tokens
- $r = q("select atoken_id from atoken where atoken_expires != '%s' && atoken_expires < %s",
+ $r = q("select atoken_id from atoken where atoken_expires > '%s' and atoken_expires < %s",
dbesc(NULL_DATE),
db_utcnow()
);
diff --git a/Zotlabs/Daemon/Externals.php b/Zotlabs/Daemon/Externals.php
index 24cfe64ec..a9988a509 100644
--- a/Zotlabs/Daemon/Externals.php
+++ b/Zotlabs/Daemon/Externals.php
@@ -58,7 +58,7 @@ class Externals {
}
if($url) {
- if($r[0]['site_pull'] !== NULL_DATE)
+ if($r[0]['site_pull'] > NULL_DATE)
$mindate = urlencode(datetime_convert('','',$r[0]['site_pull'] . ' - 1 day'));
else {
$days = get_config('externals','since_days');
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index ebc9d83a5..c0997138e 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -238,7 +238,7 @@ class Notifier {
$channel = $s[0];
$uid = $item_id;
$recipients = array();
- $r = q("select abook_xchan from abook where abook_channel = %d",
+ $r = q("select abook_xchan from abook where abook_channel = %d and abook_self = 0",
intval($item_id)
);
if($r) {
diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php
index 21c46cec5..33b244dc5 100644
--- a/Zotlabs/Daemon/Onepoll.php
+++ b/Zotlabs/Daemon/Onepoll.php
@@ -54,7 +54,7 @@ class Onepoll {
logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
- $last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] === NULL_DATE))
+ $last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] <= NULL_DATE))
? datetime_convert('UTC','UTC','now - 7 days')
: datetime_convert('UTC','UTC',$contact['abook_updated'] . ' - 2 days')
);
@@ -102,11 +102,20 @@ class Onepoll {
$fetch_feed = true;
$x = null;
+ // They haven't given us permission to see their stream
+
$can_view_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'their_perms','view_stream'));
if(! $can_view_stream)
$fetch_feed = false;
+ // we haven't given them permission to send us their stream
+
+ $can_send_stream = intval(get_abconfig($importer_uid,$contact['abook_xchan'],'my_perms','send_stream'));
+
+ if(! $can_send_stream)
+ $fetch_feed = false;
+
if($fetch_feed) {
$feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']);
diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php
index 75efbf8f7..e4bc9c143 100644
--- a/Zotlabs/Daemon/Poller.php
+++ b/Zotlabs/Daemon/Poller.php
@@ -117,7 +117,7 @@ class Poller {
// if we've never connected with them, start the mark for death countdown from now
- if($c == NULL_DATE) {
+ if($c <= NULL_DATE) {
$r = q("update abook set abook_connected = '%s' where abook_id = %d",
dbesc(datetime_convert()),
intval($contact['abook_id'])
@@ -171,7 +171,7 @@ class Poller {
}
if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
- $r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last = '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ",
+ $r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last <= '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ",
intval(UPDATE_FLAGS_UPDATED),
dbesc(NULL_DATE),
db_utcnow(), db_quoteinterval('7 DAY')
@@ -182,7 +182,7 @@ class Poller {
// If they didn't respond when we attempted before, back off to once a day
// After 7 days we won't bother anymore
- if($rr['ud_last'] != NULL_DATE)
+ if($rr['ud_last'] > NULL_DATE)
if($rr['ud_last'] > datetime_convert('UTC','UTC', 'now - 1 day'))
continue;
Master::Summon(array('Onedirsync',$rr['ud_id']));
diff --git a/Zotlabs/Lib/Api_router.php b/Zotlabs/Lib/Api_router.php
new file mode 100644
index 000000000..404678bd9
--- /dev/null
+++ b/Zotlabs/Lib/Api_router.php
@@ -0,0 +1,24 @@
+ $fn, 'auth' => $auth_required ];
+ }
+
+ static function find($path) {
+ if(array_key_exists($path,self::$routes))
+ return self::$routes[$path];
+ return null;
+ }
+
+ static function dbg() {
+ return self::$routes;
+ }
+
+}
\ No newline at end of file
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 19ed1b612..a646d8a30 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -112,7 +112,7 @@ class Apps {
static public function app_name_compare($a,$b) {
- return strcmp($a['name'],$b['name']);
+ return strcasecmp($a['name'],$b['name']);
}
diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php
index 56c717468..9a8628968 100644
--- a/Zotlabs/Lib/Enotify.php
+++ b/Zotlabs/Lib/Enotify.php
@@ -70,7 +70,22 @@ class Enotify {
$hostname = substr($hostname,0,strpos($hostname,':'));
// Do not translate 'noreply' as it must be a legal 7-bit email address
- $sender_email = 'noreply' . '@' . $hostname;
+
+ $reply_email = get_config('system','reply_address');
+ if(! $reply_email)
+ $reply_email = 'noreply' . '@' . $hostname;
+
+ $sender_email = get_config('system','from_email');
+ if(! $sender_email)
+ $sender_email = 'Administrator' . '@' . \App::get_hostname();
+
+
+ $sender_name = get_config('system','from_email_name');
+ if(! $sender_name)
+ $sender_name = \Zotlabs\Lib\System::get_site_name();
+
+
+
$additional_mail_header = "";
@@ -101,7 +116,7 @@ class Enotify {
if ($params['type'] == NOTIFY_MAIL) {
logger('notification: mail');
- $subject = sprintf( t('[Hubzilla:Notify] New mail received at %s'),$sitename);
+ $subject = sprintf( t('[$Projectname:Notify] New mail received at %s'),$sitename);
$preamble = sprintf( t('%1$s, %2$s sent you a new private message at %3$s.'),$recip['channel_name'], $sender['xchan_name'],$sitename);
$epreamble = sprintf( t('%1$s sent you %2$s.'),'[zrl=' . $sender['xchan_url'] . ']' . $sender['xchan_name'] . '[/zrl]', '[zrl=$itemlink]' . t('a private message') . '[/zrl]');
@@ -116,10 +131,13 @@ class Enotify {
$itemlink = $params['link'];
- // ignore like/unlike activity on posts - they probably require a sepearate notification preference
+ // ignore like/unlike activity on posts - they probably require a separate notification preference
- if (array_key_exists('item',$params) && (! visible_activity($params['item'])))
+ if (array_key_exists('item',$params) && (! visible_activity($params['item']))) {
+ logger('notification: not a visible activity. Ignoring.');
+ pop_lang();
return;
+ }
$parent_mid = $params['parent_mid'];
@@ -189,7 +207,7 @@ class Enotify {
// Before this we have the name of the replier on the subject rendering
// differents subjects for messages on the same thread.
- $subject = sprintf( t('[Hubzilla:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
+ $subject = sprintf( t('[$Projectname:Notify] Comment to conversation #%1$d by %2$s'), $parent_id, $sender['xchan_name']);
$preamble = sprintf( t('%1$s, %2$s commented on an item/conversation you have been following.'), $recip['channel_name'], $sender['xchan_name']);
$epreamble = $dest_str;
@@ -199,7 +217,7 @@ class Enotify {
}
if($params['type'] == NOTIFY_WALL) {
- $subject = sprintf( t('[Hubzilla:Notify] %s posted to your profile wall') , $sender['xchan_name']);
+ $subject = sprintf( t('[$Projectname:Notify] %s posted to your profile wall') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s, %2$s posted to your profile wall at %3$s') , $recip['channel_name'], $sender['xchan_name'], $sitename);
@@ -227,7 +245,7 @@ class Enotify {
return;
}
- $subject = sprintf( t('[Hubzilla:Notify] %s tagged you') , $sender['xchan_name']);
+ $subject = sprintf( t('[$Projectname:Notify] %s tagged you') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s, %2$s tagged you at %3$s') , $recip['channel_name'], $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s, %2$s [zrl=%3$s]tagged you[/zrl].') ,
$recip['channel_name'],
@@ -241,7 +259,7 @@ class Enotify {
}
if ($params['type'] == NOTIFY_POKE) {
- $subject = sprintf( t('[Hubzilla:Notify] %1$s poked you') , $sender['xchan_name']);
+ $subject = sprintf( t('[$Projectname:Notify] %1$s poked you') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s, %2$s poked you at %3$s') , $recip['channel_name'], $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s, %2$s [zrl=%2$s]poked you[/zrl].') ,
$recip['channel_name'],
@@ -259,7 +277,7 @@ class Enotify {
}
if ($params['type'] == NOTIFY_TAGSHARE) {
- $subject = sprintf( t('[Hubzilla:Notify] %s tagged your post') , $sender['xchan_name']);
+ $subject = sprintf( t('[$Projectname:Notify] %s tagged your post') , $sender['xchan_name']);
$preamble = sprintf( t('%1$s, %2$s tagged your post at %3$s') , $recip['channel_name'],$sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]') ,
$recip['channel_name'],
@@ -273,7 +291,7 @@ class Enotify {
}
if ($params['type'] == NOTIFY_INTRO) {
- $subject = sprintf( t('[Hubzilla:Notify] Introduction received'));
+ $subject = sprintf( t('[$Projectname:Notify] Introduction received'));
$preamble = sprintf( t('%1$s, you\'ve received an new connection request from \'%2$s\' at %3$s'), $recip['channel_name'], $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s, you\'ve received [zrl=%2$s]a new connection request[/zrl] from %3$s.'),
$recip['channel_name'],
@@ -288,7 +306,7 @@ class Enotify {
}
if ($params['type'] == NOTIFY_SUGGEST) {
- $subject = sprintf( t('[Hubzilla:Notify] Friend suggestion received'));
+ $subject = sprintf( t('[$Projectname:Notify] Friend suggestion received'));
$preamble = sprintf( t('%1$s, you\'ve received a friend suggestion from \'%2$s\' at %3$s'), $recip['channel_name'], $sender['xchan_name'], $sitename);
$epreamble = sprintf( t('%1$s, you\'ve received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from %4$s.'),
$recip['channel_name'],
@@ -386,8 +404,11 @@ class Enotify {
// Mark some notifications as seen right away
// Note! The notification have to be created, because they are used to send emails
// So easiest solution to hide them from Notices is to mark them as seen right away.
- // Another option would be to not add them to the DB, and change how emails are handled (probably would be better that way)
+ // Another option would be to not add them to the DB, and change how emails are handled
+ // (probably would be better that way)
+
$always_show_in_notices = get_pconfig($recip['channel_id'],'system','always_show_in_notices');
+
if (!$always_show_in_notices) {
if (($params['type'] == NOTIFY_WALL) || ($params['type'] == NOTIFY_MAIL) || ($params['type'] == NOTIFY_INTRO)) {
$seen = 1;
@@ -459,7 +480,7 @@ class Enotify {
// use $_SESSION['zid_override'] to force zid() to use
// the recipient address instead of the current observer
- $_SESSION['zid_override'] = $recip['channel_address'] . '@' . \App::get_hostname();
+ $_SESSION['zid_override'] = channel_reddress($recip);
$_SESSION['zrl_override'] = z_root() . '/channel/' . $recip['channel_address'];
$textversion = zidify_links($textversion);
@@ -515,7 +536,7 @@ class Enotify {
$private_activity = true;
case NOTIFY_MAIL:
$datarray['textversion'] = $datarray['htmlversion'] = $datarray['title'] = '';
- $datarray['subject'] = preg_replace('/' . preg_quote(t('[Hubzilla:Notify]')) . '/','$0*',$datarray['subject']);
+ $datarray['subject'] = preg_replace('/' . preg_quote(t('[$Projectname:Notify]')) . '/','$0*',$datarray['subject']);
break;
default:
break;
@@ -577,7 +598,7 @@ class Enotify {
self::send(array(
'fromName' => $sender_name,
'fromEmail' => $sender_email,
- 'replyTo' => $sender_email,
+ 'replyTo' => $reply_email,
'toEmail' => $recip['account_email'],
'messageSubject' => $datarray['subject'],
'htmlVersion' => $email_html_body,
@@ -606,6 +627,16 @@ class Enotify {
*/
static public function send($params) {
+ $params['sent'] = false;
+ $params['result'] = false;
+
+ call_hooks('email_send', $params);
+
+ if($params['sent']) {
+ logger("notification: enotify::send (addon) returns " . $params['result'], LOGGER_DEBUG);
+ return $params['result'];
+ }
+
$fromName = email_header_encode(html_entity_decode($params['fromName'],ENT_QUOTES,'UTF-8'),'UTF-8');
$messageSubject = email_header_encode(html_entity_decode($params['messageSubject'],ENT_QUOTES,'UTF-8'),'UTF-8');
@@ -646,6 +677,7 @@ class Enotify {
$messageHeader // message headers
);
logger("notification: enotify::send returns " . $res, LOGGER_DEBUG);
+ return $res;
}
static public function format($item) {
@@ -654,12 +686,12 @@ class Enotify {
require_once('include/conversation.php');
- // Call localize_item with the "brief" flag to get a one line status for activities.
+ // Call localize_item to get a one line status for activities.
// This should set $item['localized'] to indicate we have a brief summary.
localize_item($item);
- if($item_localize) {
+ if($item['localize']) {
$itemem_text = $item['localize'];
}
else {
@@ -671,7 +703,7 @@ class Enotify {
// convert this logic into a json array just like the system notifications
return array(
- 'notify_link' => $item['llink'],
+ 'notify_link' => $item['llink'],
'name' => $item['author']['xchan_name'],
'url' => $item['author']['xchan_url'],
'photo' => $item['author']['xchan_photo_s'],
diff --git a/Zotlabs/Lib/ExtendedZip.php b/Zotlabs/Lib/ExtendedZip.php
new file mode 100644
index 000000000..a40110c55
--- /dev/null
+++ b/Zotlabs/Lib/ExtendedZip.php
@@ -0,0 +1,57 @@
+addEmptyDir($localname);
+ $this->_addTree($dirname, $localname);
+ }
+
+ // Internal function, to recurse
+ protected function _addTree($dirname, $localname) {
+ $dir = opendir($dirname);
+ while ($filename = readdir($dir)) {
+ // Discard . and ..
+ if ($filename == '.' || $filename == '..')
+ continue;
+
+ // Proceed according to type
+ $path = $dirname . '/' . $filename;
+ $localpath = $localname ? ($localname . '/' . $filename) : $filename;
+ if (is_dir($path)) {
+ // Directory: add & recurse
+ $this->addEmptyDir($localpath);
+ $this->_addTree($path, $localpath);
+ }
+ else if (is_file($path)) {
+ // File: just add
+ $this->addFile($path, $localpath);
+ }
+ }
+ closedir($dir);
+ }
+
+ // Helper function
+ public static function zipTree($dirname, $zipFilename, $flags = 0, $localname = '') {
+ $zip = new self();
+ $zip->open($zipFilename, $flags);
+ $zip->addTree($dirname, $localname);
+ $zip->close();
+ }
+
+}
diff --git a/Zotlabs/Lib/SuperCurl.php b/Zotlabs/Lib/SuperCurl.php
index 1c8583ff5..462a62b36 100644
--- a/Zotlabs/Lib/SuperCurl.php
+++ b/Zotlabs/Lib/SuperCurl.php
@@ -105,7 +105,7 @@ class SuperCurl {
$opts['cookie'] = 'PHPSESSID=' . trim(file_get_contents('store/[data]/cookien_' . $this->magicauth));
$c = channelx_by_n($this->magicauth);
if($c)
- $url = zid($this->url,$c['channel_address'] . '@' . \App::get_hostname());
+ $url = zid($this->url,channel_reddress($c));
}
if($this->custom)
$opts['custom'] = $this->custom;
diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php
index 4479bf597..6ccfd664c 100644
--- a/Zotlabs/Lib/System.php
+++ b/Zotlabs/Lib/System.php
@@ -45,7 +45,7 @@ class System {
static public function get_server_role() {
if(is_array(\App::$config) && is_array(\App::$config['system']) && \App::$config['system']['server_role'])
return \App::$config['system']['server_role'];
- return 'pro';
+ return 'standard';
}
static public function get_std_version() {
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index eee3b2a4f..a3e871810 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -174,6 +174,11 @@ class ThreadItem {
$responses = get_responses($conv_responses,$response_verbs,$this,$item);
+ $my_responses = [];
+ foreach($response_verbs as $v) {
+ $my_responses[$v] = (($conv_responses[$v][$item['mid'] . '-m']) ? 1 : 0);
+ }
+
$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) {
@@ -246,10 +251,11 @@ class ThreadItem {
}
$server_role = get_config('system','server_role');
+
$has_bookmarks = false;
if(is_array($item['term'])) {
foreach($item['term'] as $t) {
- if(($server_role != 'basic') && ($t['ttype'] == TERM_BOOKMARK))
+ if((get_account_techlevel() > 0) && ($t['ttype'] == TERM_BOOKMARK))
$has_bookmarks = true;
}
}
@@ -343,7 +349,7 @@ class ThreadItem {
'isotime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'c'),
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r')) : ''),
- 'expiretime' => (($item['expires'] !== NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
+ 'expiretime' => (($item['expires'] > NULL_DATE) ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r')):''),
'lock' => $lock,
'verified' => $verified,
'unverified' => $unverified,
@@ -380,6 +386,7 @@ class ThreadItem {
'list_unseen_txt' => $list_unseen_txt,
'markseen' => t('Mark all seen'),
'responses' => $responses,
+ 'my_responses' => $my_responses,
'like_count' => $like_count,
'like_list' => $like_list,
'like_list_part' => $like_list_part,
@@ -396,6 +403,7 @@ class ThreadItem {
'comment' => $this->get_comment_box($indent),
'previewing' => ($conv->is_preview() ? ' preview ' : ''),
'wait' => t('Please wait'),
+ 'submid' => substr($item['mid'],0,32),
'thread_level' => $thread_level
);
@@ -411,6 +419,12 @@ class ThreadItem {
if($visible_comments === false)
$visible_comments = 3;
+// needed for scroll to comment from notification but needs more work
+// as we do not want to open all comments unless there is actually an #item_xx anchor
+// and the url fragment is not sent to the server.
+// if(in_array(\App::$module,['display','update_display']))
+// $visible_comments = 99999;
+
if(($this->get_display_mode() === 'normal') && ($nb_children > 0)) {
foreach($children as $child) {
$result['children'][] = $child->get_template_data($conv_responses, $thread_level + 1);
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php
index 8c62f4de9..1acd8e320 100644
--- a/Zotlabs/Module/Acl.php
+++ b/Zotlabs/Module/Acl.php
@@ -66,7 +66,7 @@ class Acl extends \Zotlabs\Web\Controller {
// These queries require permission checking. We'll create a simple array of xchan_hash for those with
// the requisite permissions which we can check against.
- $x = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = '%s' and v = 1",
+ $x = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = '%s' and v = '1'",
intval(local_channel()),
dbesc(($type === 'm') ? 'post_mail' : 'tag_deliver')
);
diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php
index 085d13fd7..e3702992f 100644
--- a/Zotlabs/Module/Admin.php
+++ b/Zotlabs/Module/Admin.php
@@ -1,7 +1,6 @@
sm = new \Zotlabs\Web\SubModule();
+ }
+
function post(){
logger('admin_post', LOGGER_DEBUG);
if(! is_site_admin()) {
return;
}
-
- // urls
if (argc() > 1) {
- switch (argv(1)) {
- case 'site':
- $this->admin_page_site_post($a);
- break;
- case 'accounts':
- $this->admin_page_accounts_post($a);
- break;
- case 'channels':
- $this->admin_page_channels_post($a);
- break;
- case 'plugins':
- if (argc() > 2 && argv(2) === 'addrepo') {
- $this->admin_page_plugins_post('addrepo');
- break;
- }
- if (argc() > 2 && argv(2) === 'installrepo') {
- $this->admin_page_plugins_post('installrepo');
- break;
- }
- if (argc() > 2 && argv(2) === 'removerepo') {
- $this->admin_page_plugins_post('removerepo');
- break;
- }
- if (argc() > 2 && argv(2) === 'updaterepo') {
- $this->admin_page_plugins_post('updaterepo');
- break;
- }
- if (argc() > 2 &&
- is_file("addon/" . argv(2) . "/" . argv(2) . ".php")){
- @include_once("addon/" . argv(2) . "/" . argv(2) . ".php");
- if(function_exists(argv(2).'_plugin_admin_post')) {
- $func = argv(2) . '_plugin_admin_post';
- $func($a);
- }
- }
- goaway(z_root() . '/admin/plugins/' . argv(2) );
- break;
- case 'themes':
- $theme = argv(2);
- if (is_file("view/theme/$theme/php/config.php")){
- require_once("view/theme/$theme/php/config.php");
- // fixme add parent theme if derived
- if (function_exists("theme_admin_post")){
- theme_admin_post($a);
- }
- }
- info(t('Theme settings updated.'));
- if(is_ajax()) return;
-
- goaway(z_root() . '/admin/themes/' . $theme );
- break;
- case 'logs':
- $this->admin_page_logs_post($a);
- break;
- case 'hubloc':
- $this->admin_page_hubloc_post($a);
- break;
- case 'security':
- $this->admin_page_security_post($a);
- break;
- case 'features':
- $this->admin_page_features_post($a);
- break;
- case 'dbsync':
- $this->admin_page_dbsync_post($a);
- break;
- case 'profs':
- $this->admin_page_profs_post($a);
- break;
- }
+ $this->sm->call('post');
}
goaway(z_root() . '/admin' );
}
/**
- * @param App &$a
* @return string
*/
+
function get() {
logger('admin_content', LOGGER_DEBUG);
@@ -119,59 +53,25 @@ class Admin extends \Zotlabs\Web\Controller {
/*
* Page content
*/
+
$o = '';
- // urls
- if (argc() > 1){
- switch (argv(1)) {
- case 'site':
- $o = $this->admin_page_site($a);
- break;
- case 'accounts':
- $o = $this->admin_page_accounts($a);
- break;
- case 'channels':
- $o = $this->admin_page_channels($a);
- break;
- case 'plugins':
- $o = $this->admin_page_plugins($a);
- break;
- case 'themes':
- $o = $this->admin_page_themes($a);
- break;
- // case 'hubloc':
- // $o = $this->admin_page_hubloc($a);
- // break;
- case 'security':
- $o = $this->admin_page_security($a);
- break;
- case 'features':
- $o = $this->admin_page_features($a);
- break;
- case 'logs':
- $o = $this->admin_page_logs($a);
- break;
- case 'dbsync':
- $o = $this->admin_page_dbsync($a);
- break;
- case 'profs':
- $o = $this->admin_page_profs($a);
- break;
- case 'queue':
- $o = $this->admin_page_queue($a);
- break;
- default:
- notice( t('Item not found.') );
+ if(argc() > 1) {
+ $o = $this->sm->call('get');
+ if($o === false) {
+ notice( t('Item not found.') );
}
- } else {
- $o = $this->admin_page_summary($a);
+ }
+ else {
+ $o = $this->admin_page_summary();
}
if(is_ajax()) {
echo $o;
killme();
return '';
- } else {
+ }
+ else {
return $o;
}
}
@@ -183,11 +83,11 @@ class Admin extends \Zotlabs\Web\Controller {
* @param App &$a
* @return string HTML from parsed admin_summary.tpl
*/
- function admin_page_summary(&$a) {
+ function admin_page_summary() {
// list total user accounts, expirations etc.
$accounts = array();
- $r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires != '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account",
+ $r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account",
db_utcnow(),
db_utcnow(),
dbesc(NULL_DATE),
@@ -255,1870 +155,5 @@ class Admin extends \Zotlabs\Web\Controller {
}
- /**
- * @brief POST handler for Admin Site Page.
- *
- * @param App &$a
- */
- function admin_page_site_post(&$a){
- if (!x($_POST, 'page_site')){
- return;
- }
-
- check_form_security_token_redirectOnErr('/admin/site', 'admin_site');
-
- $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : '');
- $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false);
- $admininfo = ((x($_POST,'admininfo')) ? trim($_POST['admininfo']) : false);
- $language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : '');
- $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : '');
- $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
- // $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
- $maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0);
-
- $register_policy = ((x($_POST,'register_policy')) ? intval(trim($_POST['register_policy'])) : 0);
-
- $access_policy = ((x($_POST,'access_policy')) ? intval(trim($_POST['access_policy'])) : 0);
- $invite_only = ((x($_POST,'invite_only')) ? True : False);
- $abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0);
-
- $register_text = ((x($_POST,'register_text')) ? notags(trim($_POST['register_text'])) : '');
- $frontpage = ((x($_POST,'frontpage')) ? notags(trim($_POST['frontpage'])) : '');
- $mirror_frontpage = ((x($_POST,'mirror_frontpage')) ? intval(trim($_POST['mirror_frontpage'])) : 0);
- $directory_server = ((x($_POST,'directory_server')) ? trim($_POST['directory_server']) : '');
- $allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : '');
- $allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : '');
- $not_allowed_email = ((x($_POST,'not_allowed_email')) ? notags(trim($_POST['not_allowed_email'])) : '');
- $force_publish = ((x($_POST,'publish_all')) ? True : False);
- $disable_discover_tab = ((x($_POST,'disable_discover_tab')) ? False : True);
- $login_on_homepage = ((x($_POST,'login_on_homepage')) ? True : False);
- $enable_context_help = ((x($_POST,'enable_context_help')) ? True : False);
- $global_directory = ((x($_POST,'directory_submit_url')) ? notags(trim($_POST['directory_submit_url'])) : '');
- $no_community_page = !((x($_POST,'no_community_page')) ? True : False);
- $default_expire_days = ((array_key_exists('default_expire_days',$_POST)) ? intval($_POST['default_expire_days']) : 0);
-
- $verifyssl = ((x($_POST,'verifyssl')) ? True : False);
- $proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : '');
- $proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : '');
- $timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['timeout'])) : 60);
- $delivery_interval = ((x($_POST,'delivery_interval'))? intval(trim($_POST['delivery_interval'])) : 0);
- $delivery_batch_count = ((x($_POST,'delivery_batch_count') && $_POST['delivery_batch_count'] > 0)? intval(trim($_POST['delivery_batch_count'])) : 1);
- $poll_interval = ((x($_POST,'poll_interval')) ? intval(trim($_POST['poll_interval'])) : 0);
- $maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50);
- $feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
- $verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
-
- set_config('system', 'feed_contacts', $feed_contacts);
- set_config('system', 'delivery_interval', $delivery_interval);
- set_config('system', 'delivery_batch_count', $delivery_batch_count);
- set_config('system', 'poll_interval', $poll_interval);
- set_config('system', 'maxloadavg', $maxloadavg);
- set_config('system', 'frontpage', $frontpage);
- set_config('system', 'mirror_frontpage', $mirror_frontpage);
- set_config('system', 'sitename', $sitename);
- set_config('system', 'login_on_homepage', $login_on_homepage);
- set_config('system', 'enable_context_help', $enable_context_help);
- set_config('system', 'verify_email', $verify_email);
- set_config('system', 'default_expire_days', $default_expire_days);
-
- if($directory_server)
- set_config('system','directory_server',$directory_server);
-
- if ($banner == '') {
- del_config('system', 'banner');
- } else {
- set_config('system', 'banner', $banner);
- }
-
- if ($admininfo == ''){
- del_config('system', 'admininfo');
- } else {
- require_once('include/text.php');
- linkify_tags($a, $admininfo, local_channel());
- set_config('system', 'admininfo', $admininfo);
- }
- set_config('system', 'language', $language);
- set_config('system', 'theme', $theme);
- if ( $theme_mobile === '---' ) {
- del_config('system', 'mobile_theme');
- } else {
- set_config('system', 'mobile_theme', $theme_mobile);
- }
- // set_config('system','site_channel', $site_channel);
- set_config('system','maximagesize', $maximagesize);
-
- set_config('system','register_policy', $register_policy);
- set_config('system','invitation_only', $invite_only);
- set_config('system','access_policy', $access_policy);
- set_config('system','account_abandon_days', $abandon_days);
- set_config('system','register_text', $register_text);
- set_config('system','allowed_sites', $allowed_sites);
- set_config('system','allowed_email', $allowed_email);
- set_config('system','not_allowed_email', $not_allowed_email);
- set_config('system','publish_all', $force_publish);
- set_config('system','disable_discover_tab', $disable_discover_tab);
- if ($global_directory == '') {
- del_config('system', 'directory_submit_url');
- } else {
- set_config('system', 'directory_submit_url', $global_directory);
- }
-
- set_config('system','no_community_page', $no_community_page);
- set_config('system','no_utf', $no_utf);
- set_config('system','verifyssl', $verifyssl);
- set_config('system','proxyuser', $proxyuser);
- set_config('system','proxy', $proxy);
- set_config('system','curl_timeout', $timeout);
-
- info( t('Site settings updated.') . EOL);
- goaway(z_root() . '/admin/site' );
- }
-
- /**
- * @brief Admin page site.
- *
- * @param App $a
- * @return string
- */
- function admin_page_site(&$a) {
-
- /* Installed langs */
- $lang_choices = array();
- $langs = glob('view/*/hstrings.php');
-
- if(is_array($langs) && count($langs)) {
- if(! in_array('view/en/hstrings.php',$langs))
- $langs[] = 'view/en/';
- asort($langs);
- foreach($langs as $l) {
- $t = explode("/",$l);
- $lang_choices[$t[1]] = $t[1];
- }
- }
-
- /* Installed themes */
- $theme_choices_mobile["---"] = t("Default");
- $theme_choices = array();
- $files = glob('view/theme/*');
- if($files) {
- foreach($files as $file) {
- $vars = '';
- $f = basename($file);
- if (file_exists($file . '/library'))
- continue;
- if (file_exists($file . '/mobile'))
- $vars = t('mobile');
- if (file_exists($file . '/experimental'))
- $vars .= t('experimental');
- if (file_exists($file . '/unsupported'))
- $vars .= t('unsupported');
- if ($vars) {
- $theme_choices[$f] = $f . ' (' . $vars . ')';
- $theme_choices_mobile[$f] = $f . ' (' . $vars . ')';
- }
- else {
- $theme_choices[$f] = $f;
- $theme_choices_mobile[$f] = $f;
- }
- }
- }
-
- $dir_choices = null;
- $dirmode = get_config('system','directory_mode');
- $realm = get_directory_realm();
-
- // directory server should not be set or settable unless we are a directory client
-
- if($dirmode == DIRECTORY_MODE_NORMAL) {
- $x = q("select site_url from site where site_flags in (%d,%d) and site_realm = '%s'",
- intval(DIRECTORY_MODE_SECONDARY),
- intval(DIRECTORY_MODE_PRIMARY),
- dbesc($realm)
- );
- if($x) {
- $dir_choices = array();
- foreach($x as $xx) {
- $dir_choices[$xx['site_url']] = $xx['site_url'];
- }
- }
- }
-
- /* Banner */
-
- $banner = get_config('system', 'banner');
- if($banner === false)
- $banner = get_config('system','sitename');
-
- $banner = htmlspecialchars($banner);
-
- /* Admin Info */
- $admininfo = get_config('system', 'admininfo');
-
- /* Register policy */
- $register_choices = Array(
- REGISTER_CLOSED => t("No"),
- REGISTER_APPROVE => t("Yes - with approval"),
- REGISTER_OPEN => t("Yes")
- );
-
- /* Acess policy */
- $access_choices = Array(
- ACCESS_PRIVATE => t("My site is not a public server"),
- ACCESS_PAID => t("My site has paid access only"),
- ACCESS_FREE => t("My site has free access only"),
- ACCESS_TIERED => t("My site offers free accounts with optional paid upgrades")
- );
-
- // $ssl_choices = array(
- // SSL_POLICY_NONE => t("No SSL policy, links will track page SSL state"),
- // SSL_POLICY_FULL => t("Force all links to use SSL")
- // );
-
- $discover_tab = get_config('system','disable_discover_tab');
- // $disable public streams by default
- if($discover_tab === false)
- $discover_tab = 1;
- // now invert the logic for the setting.
- $discover_tab = (1 - $discover_tab);
-
-
- $homelogin = get_config('system','login_on_homepage');
- $enable_context_help = get_config('system','enable_context_help');
-
- $t = get_markup_template("admin_site.tpl");
- return replace_macros($t, array(
- '$title' => t('Administration'),
- '$page' => t('Site'),
- '$submit' => t('Submit'),
- '$registration' => t('Registration'),
- '$upload' => t('File upload'),
- '$corporate' => t('Policies'),
- '$advanced' => t('Advanced'),
-
- '$baseurl' => z_root(),
- // name, label, value, help string, extra data...
- '$sitename' => array('sitename', t("Site name"), htmlspecialchars(get_config('system','sitename'), ENT_QUOTES, 'UTF-8'),''),
- '$banner' => array('banner', t("Banner/Logo"), $banner, ""),
- '$admininfo' => array('admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here")),
- '$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
- '$theme' => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - change theme settings"), $theme_choices),
- '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
- // '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
- '$feed_contacts' => array('feed_contacts', t('Allow Feeds as Connections'),get_config('system','feed_contacts'),t('(Heavy system resource usage)')),
- '$maximagesize' => array('maximagesize', t("Maximum image size"), intval(get_config('system','maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")),
- '$register_policy' => array('register_policy', t("Does this site allow new member registration?"), get_config('system','register_policy'), "", $register_choices),
- '$invite_only' => array('invite_only', t("Invitation only"), get_config('system','invitation_only'), t("Only allow new member registrations with an invitation code. Above register policy must be set to Yes.")),
- '$access_policy' => array('access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system','access_policy'), "This is displayed on the public server site list.", $access_choices),
- '$register_text' => array('register_text', t("Register text"), htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")),
- '$frontpage' => array('frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")),
- '$mirror_frontpage' => array('mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')),
- '$abandon_days' => array('abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')),
- '$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")),
- '$allowed_email' => array('allowed_email', t("Allowed email domains"), get_config('system','allowed_email'), t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")),
- '$not_allowed_email' => array('not_allowed_email', t("Not allowed email domains"), get_config('system','not_allowed_email'), t("Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined.")),
- '$verify_email' => array('verify_email', t("Verify Email Addresses"), get_config('system','verify_email'), t("Check to verify email addresses used in account registration (recommended).")),
- '$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")),
- '$disable_discover_tab' => array('disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.')),
- '$login_on_homepage' => array('login_on_homepage', t("Login on Homepage"),((intval($homelogin) || $homelogin === false) ? 1 : '') , t("Present a login box to visitors on the home page if no other content has been configured.")),
- '$enable_context_help' => array('enable_context_help', t("Enable context help"),((intval($enable_context_help) === 1 || $enable_context_help === false) ? 1 : 0) , t("Display contextual help for the current page when the help button is pressed.")),
-
- '$directory_server' => (($dir_choices) ? array('directory_server', t("Directory Server URL"), get_config('system','directory_server'), t("Default directory server"), $dir_choices) : null),
-
- '$proxyuser' => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""),
- '$proxy' => array('proxy', t("Proxy URL"), get_config('system','proxy'), ""),
- '$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.")),
- '$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.")),
- '$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"),
- ));
- }
-
- function admin_page_hubloc_post(&$a){
- check_form_security_token_redirectOnErr('/admin/hubloc', 'admin_hubloc');
- require_once('include/zot.php');
-
- //prepare for ping
-
- if ( $_POST['hublocid']) {
- $hublocid = $_POST['hublocid'];
- $arrhublocurl = q("SELECT hubloc_url FROM hubloc WHERE hubloc_id = %d ",
- intval($hublocid)
- );
- $hublocurl = $arrhublocurl[0]['hubloc_url'] . '/post';
-
- //perform ping
- $m = zot_build_packet(\App::get_channel(),'ping');
- $r = zot_zot($hublocurl,$m);
- //handle results and set the hubloc flags in db to make results visible
- $r2 = $r['body'];
- $r3 = $r2['success'];
- if ( $r3['success'] == True ){
- //set HUBLOC_OFFLINE to 0
- logger(' success = true ',LOGGER_DEBUG);
- } else {
- //set HUBLOC_OFFLINE to 1
- logger(' success = false ', LOGGER_DEBUG);
- }
-
- //unfotunatly zping wont work, I guess return format is not correct
- //require_once('mod/zping.php');
- //$r = zping_content($hublocurl);
- //logger('zping answer: ' . $r, LOGGER_DEBUG);
-
- //in case of repair store new pub key for tested hubloc (all channel with this hubloc) in db
- //after repair set hubloc flags to 0
- }
-
- goaway(z_root() . '/admin/hubloc' );
- }
-
- function trim_array_elems($arr) {
- $narr = array();
-
- if($arr && is_array($arr)) {
- for($x = 0; $x < count($arr); $x ++) {
- $y = trim($arr[$x]);
- if($y)
- $narr[] = $y;
- }
- }
- return $narr;
- }
-
- function admin_page_security_post(&$a){
- check_form_security_token_redirectOnErr('/admin/security', 'admin_security');
-
- logger('post: ' . print_r($_POST,true));
-
- $block_public = ((x($_POST,'block_public')) ? True : False);
- set_config('system','block_public',$block_public);
-
- $ws = $this->trim_array_elems(explode("\n",$_POST['whitelisted_sites']));
- set_config('system','whitelisted_sites',$ws);
-
- $bs = $this->trim_array_elems(explode("\n",$_POST['blacklisted_sites']));
- set_config('system','blacklisted_sites',$bs);
-
- $wc = $this->trim_array_elems(explode("\n",$_POST['whitelisted_channels']));
- set_config('system','whitelisted_channels',$wc);
-
- $bc = $this->trim_array_elems(explode("\n",$_POST['blacklisted_channels']));
- set_config('system','blacklisted_channels',$bc);
-
- $embed_sslonly = ((x($_POST,'embed_sslonly')) ? True : False);
- set_config('system','embed_sslonly',$embed_sslonly);
-
- $we = $this->trim_array_elems(explode("\n",$_POST['embed_allow']));
- set_config('system','embed_allow',$we);
-
- $be = $this->trim_array_elems(explode("\n",$_POST['embed_deny']));
- set_config('system','embed_deny',$be);
-
- $ts = ((x($_POST,'transport_security')) ? True : False);
- set_config('system','transport_security_header',$ts);
-
- $cs = ((x($_POST,'content_security')) ? True : False);
- set_config('system','content_security_policy',$cs);
-
- goaway(z_root() . '/admin/security');
- }
-
-
-
-
- function admin_page_features_post(&$a) {
-
- check_form_security_token_redirectOnErr('/admin/features', 'admin_manage_features');
-
- logger('postvars: ' . print_r($_POST,true));
-
- $arr = array();
- $features = get_features(false);
-
- foreach($features as $fname => $fdata) {
- foreach(array_slice($fdata,1) as $f) {
- $feature = $f[0];
-
- if(array_key_exists('feature_' . $feature,$_POST))
- $val = intval($_POST['feature_' . $feature]);
- else
- $val = 0;
- set_config('feature',$feature,$val);
-
- if(array_key_exists('featurelock_' . $feature,$_POST))
- set_config('feature_lock',$feature,$val);
- else
- del_config('feature_lock',$feature);
- }
- }
-
- goaway(z_root() . '/admin/features' );
-
- }
-
- function admin_page_features(&$a) {
-
- if((argc() > 1) && (argv(1) === 'features')) {
- $arr = array();
- $features = get_features(false);
-
- foreach($features as $fname => $fdata) {
- $arr[$fname] = array();
- $arr[$fname][0] = $fdata[0];
- foreach(array_slice($fdata,1) as $f) {
-
- $set = get_config('feature',$f[0]);
- if($set === false)
- $set = $f[3];
- $arr[$fname][1][] = array(
- array('feature_' .$f[0],$f[1],$set,$f[2],array(t('Off'),t('On'))),
- array('featurelock_' .$f[0],sprintf( t('Lock feature %s'),$f[1]),(($f[4] !== false) ? 1 : 0),'',array(t('Off'),t('On')))
- );
- }
- }
-
- $tpl = get_markup_template("admin_settings_features.tpl");
- $o .= replace_macros($tpl, array(
- '$form_security_token' => get_form_security_token("admin_manage_features"),
- '$title' => t('Manage Additional Features'),
- '$features' => $arr,
- '$submit' => t('Submit'),
- ));
-
- return $o;
- }
- }
-
-
-
-
-
- function admin_page_hubloc(&$a) {
- $hubloc = q("SELECT hubloc_id, hubloc_addr, hubloc_host, hubloc_status FROM hubloc");
-
- if(! $hubloc){
- notice( t('No server found') . EOL);
- goaway(z_root() . '/admin/hubloc');
- }
-
- $t = get_markup_template('admin_hubloc.tpl');
- return replace_macros($t, array(
- '$hubloc' => $hubloc,
- '$th_hubloc' => array(t('ID'), t('for channel'), t('on server'), t('Status')),
- '$title' => t('Administration'),
- '$page' => t('Server'),
- '$queues' => $queues,
- //'$accounts' => $accounts, /*$accounts is empty here*/
- '$pending' => array( t('Pending registrations'), $pending),
- '$plugins' => array( t('Active plugins'), \App::$plugins ),
- '$form_security_token' => get_form_security_token('admin_hubloc')
- ));
- }
-
- function admin_page_security(&$a) {
-
- $whitesites = get_config('system','whitelisted_sites');
- $whitesites_str = ((is_array($whitesites)) ? implode($whitesites,"\n") : '');
-
- $blacksites = get_config('system','blacklisted_sites');
- $blacksites_str = ((is_array($blacksites)) ? implode($blacksites,"\n") : '');
-
-
- $whitechannels = get_config('system','whitelisted_channels');
- $whitechannels_str = ((is_array($whitechannels)) ? implode($whitechannels,"\n") : '');
-
- $blackchannels = get_config('system','blacklisted_channels');
- $blackchannels_str = ((is_array($blackchannels)) ? implode($blackchannels,"\n") : '');
-
-
- $whiteembeds = get_config('system','embed_allow');
- $whiteembeds_str = ((is_array($whiteembeds)) ? implode($whiteembeds,"\n") : '');
-
- $blackembeds = get_config('system','embed_deny');
- $blackembeds_str = ((is_array($blackembeds)) ? implode($blackembeds,"\n") : '');
-
- $embed_coop = intval(get_config('system','embed_coop'));
-
- if((! $whiteembeds) && (! $blackembeds)) {
- $embedhelp1 = t("By default, unfiltered HTML is allowed in embedded media. This is inherently insecure.");
- }
-
- $embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:");
- $embedhelp3 = t("https://youtube.com/
https://www.youtube.com/
https://youtu.be/
https://vimeo.com/
https://soundcloud.com/
");
- $embedhelp4 = t("All other embedded content will be filtered, unless embedded content from that site is explicitly blocked.");
-
- $t = get_markup_template('admin_security.tpl');
- return replace_macros($t, array(
- '$title' => t('Administration'),
- '$page' => t('Security'),
- '$form_security_token' => get_form_security_token('admin_security'),
- '$block_public' => array('block_public', t("Block public"), get_config('system','block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.")),
- '$transport_security' => array('transport_security', t('Set "Transport Security" HTTP header'),intval(get_config('system','transport_security_header')),''),
- '$content_security' => array('content_security', t('Set "Content Security Policy" HTTP header'),intval(get_config('system','content_security_policy')),''),
- '$whitelisted_sites' => array('whitelisted_sites', t('Allow communications only from these sites'), $whitesites_str, t('One site per line. Leave empty to allow communication from anywhere by default')),
- '$blacklisted_sites' => array('blacklisted_sites', t('Block communications from these sites'), $blacksites_str, ''),
- '$whitelisted_channels' => array('whitelisted_channels', t('Allow communications only from these channels'), $whitechannels_str, t('One channel (hash) per line. Leave empty to allow from any channel by default')),
- '$blacklisted_channels' => array('blacklisted_channels', t('Block communications from these channels'), $blackchannels_str, ''),
- '$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''),
- '$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $whiteembeds_str, t('One site per line. By default embedded content is filtered.')),
- '$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $blackembeds_str, ''),
-
-// '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')),
-
- '$submit' => t('Submit')
- ));
- }
-
-
-
-
- function admin_page_dbsync(&$a) {
- $o = '';
-
- if(argc() > 3 && intval(argv(3)) && argv(2) === 'mark') {
- set_config('database', 'update_r' . intval(argv(3)), 'success');
- if(intval(get_config('system','db_version')) <= intval(argv(3)))
- set_config('system','db_version',intval(argv(3)) + 1);
- info( t('Update has been marked successful') . EOL);
- goaway(z_root() . '/admin/dbsync');
- }
-
- if(argc() > 2 && intval(argv(2))) {
- require_once('install/update.php');
- $func = 'update_r' . intval(argv(2));
- if(function_exists($func)) {
- $retval = $func();
- if($retval === UPDATE_FAILED) {
- $o .= sprintf( t('Executing %s failed. Check system logs.'), $func);
- }
- elseif($retval === UPDATE_SUCCESS) {
- $o .= sprintf( t('Update %s was successfully applied.'), $func);
- set_config('database',$func, 'success');
- }
- else
- $o .= sprintf( t('Update %s did not return a status. Unknown if it succeeded.'), $func);
- }
- else
- $o .= sprintf( t('Update function %s could not be found.'), $func);
-
- return $o;
- }
-
- $failed = array();
- $r = q("select * from config where `cat` = 'database' ");
- if(count($r)) {
- foreach($r as $rr) {
- $upd = intval(substr($rr['k'],8));
- if($rr['v'] === 'success')
- continue;
- $failed[] = $upd;
- }
- }
- if(! count($failed))
- return '
". file_get_contents("addon/$plugin/README") .""; - } - - $admin_form = ''; - - $r = q("select * from addon where plugin_admin = 1 and aname = '%s' limit 1", - dbesc($plugin) - ); - - if($r) { - @require_once("addon/$plugin/$plugin.php"); - if(function_exists($plugin.'_plugin_admin')) { - $func = $plugin.'_plugin_admin'; - $func($a, $admin_form); - } - } - - - $t = get_markup_template('admin_plugins_details.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Plugins'), - '$toggle' => t('Toggle'), - '$settings' => t('Settings'), - '$baseurl' => z_root(), - - '$plugin' => $plugin, - '$status' => $status, - '$action' => $action, - '$info' => $info, - '$str_author' => t('Author: '), - '$str_maintainer' => t('Maintainer: '), - '$str_minversion' => t('Minimum project version: '), - '$str_maxversion' => t('Maximum project version: '), - '$str_minphpversion' => t('Minimum PHP version: '), - '$str_requires' => t('Requires: '), - '$disabled' => t('Disabled - version incompatibility'), - - '$admin_form' => $admin_form, - '$function' => 'plugins', - '$screenshot' => '', - '$readme' => $readme, - - '$form_security_token' => get_form_security_token('admin_plugins'), - )); - } - - - /* - * List plugins - */ - $plugins = array(); - $files = glob('addon/*/'); - if($files) { - foreach($files as $file) { - if (is_dir($file)){ - list($tmp, $id) = array_map('trim', explode('/', $file)); - $info = get_plugin_info($id); - $enabled = in_array($id,\App::$plugins); - $x = check_plugin_versions($info); - - // disable plugins which are installed but incompatible versions - - if($enabled && ! $x) { - $enabled = false; - $idz = array_search($id, \App::$plugins); - if ($idz !== false) { - unset(\App::$plugins[$idz]); - uninstall_plugin($id); - set_config("system","addon", implode(", ",\App::$plugins)); - } - } - $info['disabled'] = 1-intval($x); - - $plugins[] = array( $id, (($enabled)?"on":"off") , $info); - } - } - } - - usort($plugins,'self::plugin_sort'); - - - $admin_plugins_add_repo_form= replace_macros( - get_markup_template('admin_plugins_addrepo.tpl'), array( - '$post' => 'admin/plugins/addrepo', - '$desc' => t('Enter the public git repository URL of the plugin repo.'), - '$repoURL' => array('repoURL', t('Plugin repo git URL'), '', ''), - '$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')), - '$submit' => t('Download Plugin Repo') - ) - ); - $newRepoModalID = random_string(3); - $newRepoModal = replace_macros( - get_markup_template('generic_modal.tpl'), array( - '$id' => $newRepoModalID, - '$title' => t('Install new repo'), - '$ok' => t('Install'), - '$cancel' => t('Cancel') - ) - ); - - $reponames = $this->listAddonRepos(); - $addonrepos = []; - foreach($reponames as $repo) { - $addonrepos[] = array('name' => $repo, 'description' => ''); - // TODO: Parse repo info to provide more information about repos - } - - $t = get_markup_template('admin_plugins.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Plugins'), - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$function' => 'plugins', - '$plugins' => $plugins, - '$disabled' => t('Disabled - version incompatibility'), - '$form_security_token' => get_form_security_token('admin_plugins'), - '$managerepos' => t('Manage Repos'), - '$installedtitle' => t('Installed Plugin Repositories'), - '$addnewrepotitle' => t('Install a New Plugin Repository'), - '$expandform' => false, - '$form' => $admin_plugins_add_repo_form, - '$newRepoModal' => $newRepoModal, - '$newRepoModalID' => $newRepoModalID, - '$addonrepos' => $addonrepos, - '$repoUpdateButton' => t('Update'), - '$repoBranchButton' => t('Switch branch'), - '$repoRemoveButton' => t('Remove') - )); - } - - function listAddonRepos() { - $addonrepos = []; - $addonDir = __DIR__ . '/../../extend/addon/'; - if(is_dir($addonDir)) { - if ($handle = opendir($addonDir)) { - while (false !== ($entry = readdir($handle))) { - if ($entry != "." && $entry != "..") { - $addonrepos[] = $entry; - } - } - closedir($handle); - } - } - return $addonrepos; - } - - static public function plugin_sort($a,$b) { - return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name']))); - } - - - /** - * @param array $themes - * @param string $th - * @param int $result - */ - function toggle_theme(&$themes, $th, &$result) { - for($x = 0; $x < count($themes); $x ++) { - if($themes[$x]['name'] === $th) { - if($themes[$x]['allowed']) { - $themes[$x]['allowed'] = 0; - $result = 0; - } - else { - $themes[$x]['allowed'] = 1; - $result = 1; - } - } - } - } - - /** - * @param array $themes - * @param string $th - * @return int - */ - function theme_status($themes, $th) { - for($x = 0; $x < count($themes); $x ++) { - if($themes[$x]['name'] === $th) { - if($themes[$x]['allowed']) { - return 1; - } - else { - return 0; - } - } - } - return 0; - } - - - /** - * @param array $themes - * @return string - */ - function rebuild_theme_table($themes) { - $o = ''; - if(count($themes)) { - foreach($themes as $th) { - if($th['allowed']) { - if(strlen($o)) - $o .= ','; - $o .= $th['name']; - } - } - } - return $o; - } - - - /** - * @brief Themes admin page. - * - * @param App &$a - * @return string - */ - function admin_page_themes(&$a){ - - $allowed_themes_str = get_config('system', 'allowed_themes'); - $allowed_themes_raw = explode(',', $allowed_themes_str); - $allowed_themes = array(); - if(count($allowed_themes_raw)) - foreach($allowed_themes_raw as $x) - if(strlen(trim($x))) - $allowed_themes[] = trim($x); - - $themes = array(); - $files = glob('view/theme/*'); - if($files) { - foreach($files as $file) { - $f = basename($file); - $is_experimental = intval(file_exists($file . '/.experimental')); - $is_supported = 1-(intval(file_exists($file . '/.unsupported'))); // Is not used yet - $is_allowed = intval(in_array($f,$allowed_themes)); - $themes[] = array('name' => $f, 'experimental' => $is_experimental, 'supported' => $is_supported, 'allowed' => $is_allowed); - } - } - - if(! count($themes)) { - notice( t('No themes found.')); - return ''; - } - - /* - * Single theme - */ - - if (\App::$argc == 3){ - $theme = \App::$argv[2]; - if(! is_dir("view/theme/$theme")){ - notice( t("Item not found.") ); - return ''; - } - - if (x($_GET,"a") && $_GET['a']=="t"){ - check_form_security_token_redirectOnErr('/admin/themes', 'admin_themes', 't'); - - // Toggle theme status - - $this->toggle_theme($themes, $theme, $result); - $s = $this->rebuild_theme_table($themes); - if($result) - info( sprintf('Theme %s enabled.', $theme)); - else - info( sprintf('Theme %s disabled.', $theme)); - - set_config('system', 'allowed_themes', $s); - goaway(z_root() . '/admin/themes' ); - } - - // display theme details - require_once('library/markdown.php'); - - if ($this->theme_status($themes,$theme)) { - $status="on"; $action= t("Disable"); - } else { - $status="off"; $action= t("Enable"); - } - - $readme=Null; - if (is_file("view/theme/$theme/README.md")){ - $readme = file_get_contents("view/theme/$theme/README.md"); - $readme = Markdown($readme); - } else if (is_file("view/theme/$theme/README")){ - $readme = "
". file_get_contents("view/theme/$theme/README") .""; - } - - $admin_form = ''; - if (is_file("view/theme/$theme/php/config.php")){ - require_once("view/theme/$theme/php/config.php"); - if(function_exists("theme_admin")){ - $admin_form = theme_admin($a); - } - } - - $screenshot = array( get_theme_screenshot($theme), t('Screenshot')); - if(! stristr($screenshot[0],$theme)) - $screenshot = null; - - $t = get_markup_template('admin_plugins_details.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Themes'), - '$toggle' => t('Toggle'), - '$settings' => t('Settings'), - '$baseurl' => z_root(), - - '$plugin' => $theme, - '$status' => $status, - '$action' => $action, - '$info' => get_theme_info($theme), - '$function' => 'themes', - '$admin_form' => $admin_form, - '$str_author' => t('Author: '), - '$str_maintainer' => t('Maintainer: '), - '$screenshot' => $screenshot, - '$readme' => $readme, - - '$form_security_token' => get_form_security_token('admin_themes'), - )); - } - - /* - * List themes - */ - - $xthemes = array(); - if($themes) { - foreach($themes as $th) { - $xthemes[] = array($th['name'],(($th['allowed']) ? "on" : "off"), get_theme_info($th['name'])); - } - } - - $t = get_markup_template('admin_plugins.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Themes'), - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$function' => 'themes', - '$plugins' => $xthemes, - '$experimental' => t('[Experimental]'), - '$unsupported' => t('[Unsupported]'), - '$form_security_token' => get_form_security_token('admin_themes'), - )); - } - - - /** - * @brief POST handler for logs admin page. - * - * @param App &$a - */ - function admin_page_logs_post(&$a) { - if (x($_POST, 'page_logs')) { - check_form_security_token_redirectOnErr('/admin/logs', 'admin_logs'); - - $logfile = ((x($_POST,'logfile')) ? notags(trim($_POST['logfile'])) : ''); - $debugging = ((x($_POST,'debugging')) ? true : false); - $loglevel = ((x($_POST,'loglevel')) ? intval(trim($_POST['loglevel'])) : 0); - - set_config('system','logfile', $logfile); - set_config('system','debugging', $debugging); - set_config('system','loglevel', $loglevel); - } - - info( t('Log settings updated.') ); - goaway(z_root() . '/admin/logs' ); - } - - /** - * @brief Logs admin page. - * - * @param App $a - * @return string - */ - function admin_page_logs(&$a){ - - $log_choices = Array( - LOGGER_NORMAL => 'Normal', - LOGGER_TRACE => 'Trace', - LOGGER_DEBUG => 'Debug', - LOGGER_DATA => 'Data', - LOGGER_ALL => 'All' - ); - - $t = get_markup_template('admin_logs.tpl'); - - $f = get_config('system', 'logfile'); - - $data = ''; - - if(!file_exists($f)) { - $data = t("Error trying to open $f log file.\r\n
". file_get_contents("addon/$plugin/README") .""; + } + + $admin_form = ''; + + $r = q("select * from addon where plugin_admin = 1 and aname = '%s' limit 1", + dbesc($plugin) + ); + + if($r) { + @require_once("addon/$plugin/$plugin.php"); + if(function_exists($plugin.'_plugin_admin')) { + $func = $plugin.'_plugin_admin'; + $func($a, $admin_form); + } + } + + + $t = get_markup_template('admin_plugins_details.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Plugins'), + '$toggle' => t('Toggle'), + '$settings' => t('Settings'), + '$baseurl' => z_root(), + + '$plugin' => $plugin, + '$status' => $status, + '$action' => $action, + '$info' => $info, + '$str_author' => t('Author: '), + '$str_maintainer' => t('Maintainer: '), + '$str_minversion' => t('Minimum project version: '), + '$str_maxversion' => t('Maximum project version: '), + '$str_minphpversion' => t('Minimum PHP version: '), + '$str_serverroles' => t('Compatible Server Roles: '), + '$str_requires' => t('Requires: '), + '$disabled' => t('Disabled - version incompatibility'), + + '$admin_form' => $admin_form, + '$function' => 'plugins', + '$screenshot' => '', + '$readme' => $readme, + + '$form_security_token' => get_form_security_token('admin_plugins'), + )); + } + + + /* + * List plugins + */ + $plugins = array(); + $files = glob('addon/*/'); + if($files) { + foreach($files as $file) { + if (is_dir($file)){ + list($tmp, $id) = array_map('trim', explode('/', $file)); + $info = get_plugin_info($id); + $enabled = in_array($id,\App::$plugins); + $x = check_plugin_versions($info); + + // disable plugins which are installed but incompatible versions + + if($enabled && ! $x) { + $enabled = false; + $idz = array_search($id, \App::$plugins); + if ($idz !== false) { + unset(\App::$plugins[$idz]); + uninstall_plugin($id); + set_config("system","addon", implode(", ",\App::$plugins)); + } + } + $info['disabled'] = 1-intval($x); + + $plugins[] = array( $id, (($enabled)?"on":"off") , $info); + } + } + } + + usort($plugins,'self::plugin_sort'); + + + $admin_plugins_add_repo_form= replace_macros( + get_markup_template('admin_plugins_addrepo.tpl'), array( + '$post' => 'admin/plugins/addrepo', + '$desc' => t('Enter the public git repository URL of the plugin repo.'), + '$repoURL' => array('repoURL', t('Plugin repo git URL'), '', ''), + '$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')), + '$submit' => t('Download Plugin Repo') + ) + ); + $newRepoModalID = random_string(3); + $newRepoModal = replace_macros( + get_markup_template('generic_modal.tpl'), array( + '$id' => $newRepoModalID, + '$title' => t('Install new repo'), + '$ok' => t('Install'), + '$cancel' => t('Cancel') + ) + ); + + $reponames = $this->listAddonRepos(); + $addonrepos = []; + foreach($reponames as $repo) { + $addonrepos[] = array('name' => $repo, 'description' => ''); + // TODO: Parse repo info to provide more information about repos + } + + $t = get_markup_template('admin_plugins.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Plugins'), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$function' => 'plugins', + '$plugins' => $plugins, + '$disabled' => t('Disabled - version incompatibility'), + '$form_security_token' => get_form_security_token('admin_plugins'), + '$managerepos' => t('Manage Repos'), + '$installedtitle' => t('Installed Plugin Repositories'), + '$addnewrepotitle' => t('Install a New Plugin Repository'), + '$expandform' => false, + '$form' => $admin_plugins_add_repo_form, + '$newRepoModal' => $newRepoModal, + '$newRepoModalID' => $newRepoModalID, + '$addonrepos' => $addonrepos, + '$repoUpdateButton' => t('Update'), + '$repoBranchButton' => t('Switch branch'), + '$repoRemoveButton' => t('Remove') + )); + } + + function listAddonRepos() { + $addonrepos = []; + $addonDir = 'extend/addon/'; + if(is_dir($addonDir)) { + if ($handle = opendir($addonDir)) { + while (false !== ($entry = readdir($handle))) { + if ($entry != "." && $entry != "..") { + $addonrepos[] = $entry; + } + } + closedir($handle); + } + } + return $addonrepos; + } + + static public function plugin_sort($a,$b) { + return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name']))); + } + + +} \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Profs.php b/Zotlabs/Module/Admin/Profs.php new file mode 100644 index 000000000..b3da09cb7 --- /dev/null +++ b/Zotlabs/Module/Admin/Profs.php @@ -0,0 +1,169 @@ + 3) && argv(2) == 'drop' && intval(argv(3))) { + $r = q("delete from profdef where id = %d", + intval(argv(3)) + ); + // remove from allowed fields + + goaway(z_root() . '/admin/profs'); + } + + if((argc() > 2) && argv(2) === 'new') { + return replace_macros(get_markup_template('profdef_edit.tpl'),array( + '$header' => t('New Profile Field'), + '$field_name' => array('field_name',t('Field nickname'),$_REQUEST['field_name'],t('System name of field')), + '$field_type' => array('field_type',t('Input type'),(($_REQUEST['field_type']) ? $_REQUEST['field_type'] : 'text'),''), + '$field_desc' => array('field_desc',t('Field Name'),$_REQUEST['field_desc'],t('Label on profile pages')), + '$field_help' => array('field_help',t('Help text'),$_REQUEST['field_help'],t('Additional info (optional)')), + '$submit' => t('Save') + )); + } + + if((argc() > 2) && intval(argv(2))) { + $r = q("select * from profdef where id = %d limit 1", + intval(argv(2)) + ); + if(! $r) { + notice( t('Field definition not found') . EOL); + goaway(z_root() . '/admin/profs'); + } + + return replace_macros(get_markup_template('profdef_edit.tpl'),array( + '$id' => intval($r[0]['id']), + '$header' => t('Edit Profile Field'), + '$field_name' => array('field_name',t('Field nickname'),$r[0]['field_name'],t('System name of field')), + '$field_type' => array('field_type',t('Input type'),$r[0]['field_type'],''), + '$field_desc' => array('field_desc',t('Field Name'),$r[0]['field_desc'],t('Label on profile pages')), + '$field_help' => array('field_help',t('Help text'),$r[0]['field_help'],t('Additional info (optional)')), + '$submit' => t('Save') + )); + } + + $basic = ''; + $barr = array(); + $fields = get_profile_fields_basic(); + if(! $fields) + $fields = get_profile_fields_basic(1); + if($fields) { + foreach($fields as $k => $v) { + if($basic) + $basic .= ', '; + $basic .= trim($k); + $barr[] = trim($k); + } + } + + $advanced = ''; + $fields = get_profile_fields_advanced(); + if(! $fields) + $fields = get_profile_fields_advanced(1); + if($fields) { + foreach($fields as $k => $v) { + if(in_array(trim($k),$barr)) + continue; + if($advanced) + $advanced .= ', '; + $advanced .= trim($k); + } + } + + $all = ''; + $fields = get_profile_fields_advanced(1); + if($fields) { + foreach($fields as $k => $v) { + if($all) + $all .= ', '; + $all .= trim($k); + } + } + + $r = q("select * from profdef where true"); + if($r) { + foreach($r as $rr) { + if($all) + $all .= ', '; + $all .= $rr['field_name']; + } + } + + + $o = replace_macros(get_markup_template('admin_profiles.tpl'),array( + '$title' => t('Profile Fields'), + '$basic' => array('basic',t('Basic Profile Fields'),$basic,''), + '$advanced' => array('advanced',t('Advanced Profile Fields'),$advanced,t('(In addition to basic fields)')), + '$all' => $all, + '$all_desc' => t('All available fields'), + '$cust_field_desc' => t('Custom Fields'), + '$cust_fields' => $r, + '$edit' => t('Edit'), + '$drop' => t('Delete'), + '$new' => t('Create Custom Field'), + '$submit' => t('Submit') + )); + + return $o; + + + } + + + + + +} \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Queue.php b/Zotlabs/Module/Admin/Queue.php new file mode 100644 index 000000000..4986de925 --- /dev/null +++ b/Zotlabs/Module/Admin/Queue.php @@ -0,0 +1,54 @@ + t('Queue Statistics'), + '$numentries' => t('Total Entries'), + '$priority' => t('Priority'), + '$desturl' => t('Destination URL'), + '$nukehub' => t('Mark hub permanently offline'), + '$empty' => t('Empty queue for this hub'), + '$lastconn' => t('Last known contact'), + '$hasentries' => ((count($r)) ? true : false), + '$entries' => $r, + '$expert' => $expert + )); + + return $o; + } + + + + +} \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Security.php b/Zotlabs/Module/Admin/Security.php new file mode 100644 index 000000000..a1e4bf537 --- /dev/null +++ b/Zotlabs/Module/Admin/Security.php @@ -0,0 +1,123 @@ +trim_array_elems(explode("\n",$_POST['whitelisted_sites'])); + set_config('system','whitelisted_sites',$ws); + + $bs = $this->trim_array_elems(explode("\n",$_POST['blacklisted_sites'])); + set_config('system','blacklisted_sites',$bs); + + $wc = $this->trim_array_elems(explode("\n",$_POST['whitelisted_channels'])); + set_config('system','whitelisted_channels',$wc); + + $bc = $this->trim_array_elems(explode("\n",$_POST['blacklisted_channels'])); + set_config('system','blacklisted_channels',$bc); + + $embed_sslonly = ((x($_POST,'embed_sslonly')) ? True : False); + set_config('system','embed_sslonly',$embed_sslonly); + + $we = $this->trim_array_elems(explode("\n",$_POST['embed_allow'])); + set_config('system','embed_allow',$we); + + $be = $this->trim_array_elems(explode("\n",$_POST['embed_deny'])); + set_config('system','embed_deny',$be); + + $ts = ((x($_POST,'transport_security')) ? True : False); + set_config('system','transport_security_header',$ts); + + $cs = ((x($_POST,'content_security')) ? True : False); + set_config('system','content_security_policy',$cs); + + goaway(z_root() . '/admin/security'); + } + + + + function get() { + + $whitesites = get_config('system','whitelisted_sites'); + $whitesites_str = ((is_array($whitesites)) ? implode($whitesites,"\n") : ''); + + $blacksites = get_config('system','blacklisted_sites'); + $blacksites_str = ((is_array($blacksites)) ? implode($blacksites,"\n") : ''); + + + $whitechannels = get_config('system','whitelisted_channels'); + $whitechannels_str = ((is_array($whitechannels)) ? implode($whitechannels,"\n") : ''); + + $blackchannels = get_config('system','blacklisted_channels'); + $blackchannels_str = ((is_array($blackchannels)) ? implode($blackchannels,"\n") : ''); + + + $whiteembeds = get_config('system','embed_allow'); + $whiteembeds_str = ((is_array($whiteembeds)) ? implode($whiteembeds,"\n") : ''); + + $blackembeds = get_config('system','embed_deny'); + $blackembeds_str = ((is_array($blackembeds)) ? implode($blackembeds,"\n") : ''); + + $embed_coop = intval(get_config('system','embed_coop')); + + if((! $whiteembeds) && (! $blackembeds)) { + $embedhelp1 = t("By default, unfiltered HTML is allowed in embedded media. This is inherently insecure."); + } + + $embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:"); + $embedhelp3 = t("https://youtube.com/
". file_get_contents("view/theme/$theme/README") .""; + } + + $admin_form = ''; + if (is_file("view/theme/$theme/php/config.php")){ + require_once("view/theme/$theme/php/config.php"); + if(function_exists("theme_admin")){ + $admin_form = theme_admin($a); + } + } + + $screenshot = array( get_theme_screenshot($theme), t('Screenshot')); + if(! stristr($screenshot[0],$theme)) + $screenshot = null; + + $t = get_markup_template('admin_plugins_details.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Themes'), + '$toggle' => t('Toggle'), + '$settings' => t('Settings'), + '$baseurl' => z_root(), + + '$plugin' => $theme, + '$status' => $status, + '$action' => $action, + '$info' => get_theme_info($theme), + '$function' => 'themes', + '$admin_form' => $admin_form, + '$str_author' => t('Author: '), + '$str_maintainer' => t('Maintainer: '), + '$screenshot' => $screenshot, + '$readme' => $readme, + + '$form_security_token' => get_form_security_token('admin_themes'), + )); + } + + /* + * List themes + */ + + $xthemes = array(); + if($themes) { + foreach($themes as $th) { + $xthemes[] = array($th['name'],(($th['allowed']) ? "on" : "off"), get_theme_info($th['name'])); + } + } + + $t = get_markup_template('admin_plugins.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Themes'), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$function' => 'themes', + '$plugins' => $xthemes, + '$experimental' => t('[Experimental]'), + '$unsupported' => t('[Unsupported]'), + '$form_security_token' => get_form_security_token('admin_themes'), + )); + } + + + + /** + * @param array $themes + * @param string $th + * @param int $result + */ + function toggle_theme(&$themes, $th, &$result) { + for($x = 0; $x < count($themes); $x ++) { + if($themes[$x]['name'] === $th) { + if($themes[$x]['allowed']) { + $themes[$x]['allowed'] = 0; + $result = 0; + } + else { + $themes[$x]['allowed'] = 1; + $result = 1; + } + } + } + } + + /** + * @param array $themes + * @param string $th + * @return int + */ + function theme_status($themes, $th) { + for($x = 0; $x < count($themes); $x ++) { + if($themes[$x]['name'] === $th) { + if($themes[$x]['allowed']) { + return 1; + } + else { + return 0; + } + } + } + return 0; + } + + + /** + * @param array $themes + * @return string + */ + function rebuild_theme_table($themes) { + $o = ''; + if(count($themes)) { + foreach($themes as $th) { + if($th['allowed']) { + if(strlen($o)) + $o .= ','; + $o .= $th['name']; + } + } + } + return $o; + } + + + + + + + + +} \ No newline at end of file diff --git a/Zotlabs/Module/Api.php b/Zotlabs/Module/Api.php index e4744c29f..4fd59acc4 100644 --- a/Zotlabs/Module/Api.php +++ b/Zotlabs/Module/Api.php @@ -8,20 +8,15 @@ require_once('include/api.php'); class Api extends \Zotlabs\Web\Controller { function post() { - if(! local_channel()) { notice( t('Permission denied.') . EOL); return; } - if(count(\App::$user) && x(\App::$user,'uid') && \App::$user['uid'] != local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - } - function get() { + function get() { + if(\App::$cmd=='api/oauth/authorize'){ /* @@ -33,7 +28,8 @@ class Api extends \Zotlabs\Web\Controller { // get consumer/client from request token try { $request = OAuth1Request::from_request(); - } catch(Exception $e) { + } + catch(\Exception $e) { echo "
"; var_dump($e); killme(); } @@ -41,17 +37,20 @@ class Api extends \Zotlabs\Web\Controller { if(x($_POST,'oauth_yes')){ $app = $this->oauth_get_client($request); - if (is_null($app)) return "Invalid request. Unknown token."; + if (is_null($app)) + return "Invalid request. Unknown token."; + $consumer = new OAuth1Consumer($app['client_id'], $app['pw'], $app['redirect_uri']); $verifier = md5($app['secret'].local_channel()); set_config("oauth", $verifier, local_channel()); - if($consumer->callback_url!=null) { + if($consumer->callback_url != null) { $params = $request->get_parameters(); - $glue="?"; - if (strstr($consumer->callback_url,$glue)) $glue="?"; + $glue = '?'; + if(strstr($consumer->callback_url,$glue)) + $glue = '?'; goaway($consumer->callback_url . $glue . "oauth_token=" . OAuth1Util::urlencode_rfc3986($params['oauth_token']) . "&oauth_verifier=" . OAuth1Util::urlencode_rfc3986($verifier)); killme(); } @@ -59,7 +58,7 @@ class Api extends \Zotlabs\Web\Controller { $tpl = get_markup_template("oauth_authorize_done.tpl"); $o = replace_macros($tpl, array( '$title' => t('Authorize application connection'), - '$info' => t('Return to your app and insert this Securty Code:'), + '$info' => t('Return to your app and insert this Security Code:'), '$code' => $verifier, )); @@ -72,14 +71,11 @@ class Api extends \Zotlabs\Web\Controller { notice( t('Please login to continue.') . EOL ); return login(false,'api-login',$request->get_parameters()); } - //FKOAuth1::loginUser(4); $app = $this->oauth_get_client($request); - if (is_null($app)) return "Invalid request. Unknown token."; - - - - + if (is_null($app)) + return "Invalid request. Unknown token."; + $tpl = get_markup_template('oauth_authorize.tpl'); $o = replace_macros($tpl, array( '$title' => t('Authorize application connection'), @@ -94,29 +90,24 @@ class Api extends \Zotlabs\Web\Controller { return $o; } - echo api_call($a); + echo api_call(); killme(); } function oauth_get_client($request){ - $params = $request->get_parameters(); - $token = $params['oauth_token']; + $token = $params['oauth_token']; - $r = q("SELECT `clients`.* - FROM `clients`, `tokens` - WHERE `clients`.`client_id`=`tokens`.`client_id` - AND `tokens`.`id`='%s' AND `tokens`.`auth_scope`='request'", - dbesc($token)); + $r = q("SELECT clients.* FROM clients, tokens WHERE clients.client_id = tokens.client_id + AND tokens.id = '%s' AND tokens.auth_scope = 'request' ", + dbesc($token) + ); + if($r) + return $r[0]; - if (!count($r)) - return null; + return null; - return $r[0]; } - - - } diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php index 4bdec4573..4dab621b2 100644 --- a/Zotlabs/Module/Apps.php +++ b/Zotlabs/Module/Apps.php @@ -1,7 +1,6 @@ 2) ? intval(argv(2)) : 0)); + $r = attach_by_hash(argv(1),get_observer_hash(),((argc() > 2) ? intval(argv(2)) : 0)); if(! $r['success']) { notice( $r['message'] . EOL); diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index 59cb9f06c..209d86236 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -120,8 +120,9 @@ class Channel extends \Zotlabs\Web\Controller { 'deny_gid' => $channel['channel_deny_gid'] ); } - else - $channel_acl = array(); + else { + $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; + } if($perms['post_wall']) { @@ -133,14 +134,15 @@ class Channel extends \Zotlabs\Web\Controller { 'nickname' => \App::$profile['channel_address'], 'lockstate' => (((strlen(\App::$profile['channel_allow_cid'])) || (strlen(\App::$profile['channel_allow_gid'])) || (strlen(\App::$profile['channel_deny_cid'])) || (strlen(\App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'), 'acl' => (($is_owner) ? populate_acl($channel_acl,true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''), - 'permissions' => (($is_owner) ? $channel_acl : ''), + 'permissions' => $channel_acl, 'showacl' => (($is_owner) ? 'yes' : ''), 'bang' => '', 'visitor' => (($is_owner || $observer) ? true : false), 'profile_uid' => \App::$profile['profile_uid'], 'editor_autocomplete' => true, 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true + 'bbcode' => true, + 'jotnets' => true ); $o .= status_editor($a,$x); @@ -176,10 +178,11 @@ class Channel extends \Zotlabs\Web\Controller { if($mid) { $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal - AND item_wall = 1 AND item_unseen = 1 $sql_extra limit 1", + AND item_wall = 1 $simple_update $sql_extra limit 1", dbesc($mid . '%'), intval(\App::$profile['profile_uid']) ); + $_SESSION['loadtime'] = datetime_convert(); } else { $r = q("SELECT distinct parent AS `item_id`, created from item diff --git a/Zotlabs/Module/Connect.php b/Zotlabs/Module/Connect.php index 962c05cce..dec375104 100644 --- a/Zotlabs/Module/Connect.php +++ b/Zotlabs/Module/Connect.php @@ -60,13 +60,13 @@ class Connect extends \Zotlabs\Web\Controller { $observer = \App::get_observer(); if(($observer) && ($_POST['submit'] === t('Continue'))) { if($observer['xchan_follow']) - $url = sprintf($observer['xchan_follow'],urlencode(\App::$data['channel']['channel_address'] . '@' . \App::get_hostname())); + $url = sprintf($observer['xchan_follow'],urlencode(channel_reddress(\App::$data['channel']))); if(! $url) { $r = q("select * from hubloc where hubloc_hash = '%s' order by hubloc_id desc limit 1", dbesc($observer['xchan_hash']) ); if($r) - $url = $r[0]['hubloc_url'] . '/follow?f=&url=' . urlencode(\App::$data['channel']['channel_address'] . '@' . \App::get_hostname()); + $url = $r[0]['hubloc_url'] . '/follow?f=&url=' . urlencode(channel_reddress(\App::$data['channel'])); } } if($url) diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 217249469..43feac189 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -663,13 +663,9 @@ class Connedit extends \Zotlabs\Web\Controller { $rating_text = $xl[0]['xlink_rating_text']; } - $poco_rating = get_config('system','poco_rating_enable'); + $rating_enabled = get_config('system','rating_enabled'); - // if unset default to enabled - if($poco_rating === false) - $poco_rating = true; - - if($poco_rating) { + if($rating_enabled) { $rating = replace_macros(get_markup_template('rating_slider.tpl'),array( '$min' => -10, '$val' => $rating_val diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php index 560038ffc..e1068223b 100644 --- a/Zotlabs/Module/Directory.php +++ b/Zotlabs/Module/Directory.php @@ -84,10 +84,9 @@ class Directory extends \Zotlabs\Web\Controller { $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); - if(strpos($search,'=') && local_channel() && get_pconfig(local_channel(),'feature','expert')) + if(strpos($search,'=') && local_channel() && feature_enabled(local_channel(), 'advanced_dirsearch')) $advanced = $search; - $keywords = (($_GET['keywords']) ? $_GET['keywords'] : ''); // Suggest channels if no search terms or keywords are given @@ -239,7 +238,9 @@ class Directory extends \Zotlabs\Web\Controller { $page_type = ''; - if($rr['total_ratings']) + $rating_enabled = get_config('system','rating_enabled'); + + if($rr['total_ratings'] && $rating_enabled) $total_ratings = sprintf( tt("%d rating", "%d ratings", $rr['total_ratings']), $rr['total_ratings']); else $total_ratings = ''; @@ -264,6 +265,7 @@ class Directory extends \Zotlabs\Web\Controller { $keywords = ((x($profile,'keywords')) ? $profile['keywords'] : ''); + $out = ''; if($keywords) { @@ -312,7 +314,7 @@ class Directory extends \Zotlabs\Web\Controller { 'gender' => $gender, 'total_ratings' => $total_ratings, 'viewrate' => true, - 'canrate' => ((local_channel()) ? true : false), + 'canrate' => (($rating_enabled && local_channel()) ? true : false), 'pdesc' => $pdesc, 'pdesc_label' => t('Description:'), 'marital' => $marital, diff --git a/Zotlabs/Module/Dirsearch.php b/Zotlabs/Module/Dirsearch.php index 8f60910f1..ebd6c3715 100644 --- a/Zotlabs/Module/Dirsearch.php +++ b/Zotlabs/Module/Dirsearch.php @@ -448,9 +448,9 @@ class Dirsearch extends \Zotlabs\Web\Controller { $register = 'closed'; if(strpos($rr['site_url'],'https://') !== false) - $ret['sites'][] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location'], 'project' => $rr['site_project']); + $ret['sites'][] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location'], 'project' => $rr['site_project'], 'version' => $rr['site_version']); else - $insecure[] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location'], 'project' => $rr['site_project']); + $insecure[] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location'], 'project' => $rr['site_project'], 'version' => $rr['site_version']); } if($insecure) { $ret['sites'] = array_merge($ret['sites'],$insecure); diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index 35ed0c894..e9441bbdf 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -73,7 +73,8 @@ class Display extends \Zotlabs\Web\Controller { 'expanded' => true, 'editor_autocomplete' => true, 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true + 'bbcode' => true, + 'jotnets' => true ); $o = ''; diff --git a/Zotlabs/Module/Dreport.php b/Zotlabs/Module/Dreport.php index d2933b464..3fdeff369 100644 --- a/Zotlabs/Module/Dreport.php +++ b/Zotlabs/Module/Dreport.php @@ -74,7 +74,7 @@ class Dreport extends \Zotlabs\Web\Controller { if(! $r) { notice( t('no results') . EOL); - return; +// return; } for($x = 0; $x < count($r); $x++ ) { diff --git a/Zotlabs/Module/Events.php b/Zotlabs/Module/Events.php index d27de9989..2bff4676e 100644 --- a/Zotlabs/Module/Events.php +++ b/Zotlabs/Module/Events.php @@ -118,7 +118,7 @@ class Events extends \Zotlabs\Web\Controller { goaway($onerror_url); } - $share = ((intval($_POST['share'])) ? intval($_POST['share']) : 0); + $share = ((intval($_POST['distr'])) ? intval($_POST['distr']) : 0); $channel = \App::get_channel(); @@ -469,7 +469,7 @@ class Events extends \Zotlabs\Web\Controller { '$t_orig' => $t_orig, '$sh_text' => t('Share this event'), '$sh_checked' => $sh_checked, - '$share' => array('share', t('Share this event'), $sh_checked, '', array(t('No'),t('Yes'))), + '$share' => array('distr', t('Share this event'), $sh_checked, '', array(t('No'),t('Yes'))), '$preview' => t('Preview'), '$perms_label' => t('Permission settings'), // populating the acl dialog was a permission description from view_stream because Cal.php, which diff --git a/Zotlabs/Module/Fhublocs.php b/Zotlabs/Module/Fhublocs.php index f5b439421..cdf323a41 100644 --- a/Zotlabs/Module/Fhublocs.php +++ b/Zotlabs/Module/Fhublocs.php @@ -42,7 +42,7 @@ class Fhublocs extends \Zotlabs\Web\Controller { if($y) $primary_address = $y[0]['xchan_addr']; - $hub_address = $rr['channel']['channel_address'] . '@' . \App::get_hostname(); + $hub_address = channel_reddress($rr['channel']); $primary = (($hub_address === $primary_address) ? 1 : 0); @@ -61,7 +61,7 @@ class Fhublocs extends \Zotlabs\Web\Controller { dbesc($rr['channel_guid']), dbesc($rr['channel_guid_sig']), dbesc($rr['channel_hash']), - dbesc($rr['channel_address'] . '@' . \App::get_hostname()), + dbesc(channel_reddress($rr)), intval($primary), dbesc(z_root()), dbesc(base64url_encode(rsa_sign(z_root(),$rr['channel_prvkey']))), diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php index a401f4822..8b8620d6f 100644 --- a/Zotlabs/Module/Filestorage.php +++ b/Zotlabs/Module/Filestorage.php @@ -44,14 +44,14 @@ class Filestorage extends \Zotlabs\Web\Controller { //get the object before permissions change so we can catch eventual former allowed members $object = get_file_activity_object($channel_id, $resource, $cloudPath); - attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse); + attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true); file_activity($channel_id, $object, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], 'post', $notify); goaway($cloudPath); } - function get() { + function get() { if(argc() > 1) $which = argv(1); diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php index 09d761887..3d859d94b 100644 --- a/Zotlabs/Module/Getfile.php +++ b/Zotlabs/Module/Getfile.php @@ -27,10 +27,12 @@ require_once('include/attach.php'); class Getfile extends \Zotlabs\Web\Controller { function post() { + + logger('post: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO); - $hash = $_POST['hash']; - $time = $_POST['time']; - $sig = $_POST['signature']; + $hash = $_POST['hash']; + $time = $_POST['time']; + $sig = $_POST['signature']; $resource = $_POST['resource']; $revision = intval($_POST['revision']); @@ -38,9 +40,11 @@ class Getfile extends \Zotlabs\Web\Controller { killme(); $channel = channelx_by_hash($hash); - - if((! $channel) || (! $time) || (! $sig)) + + if((! $channel) || (! $time) || (! $sig)) { + logger('error: missing info'); killme(); + } $slop = intval(get_pconfig($channel['channel_id'],'system','getfile_time_slop')); if($slop < 1) @@ -58,16 +62,15 @@ class Getfile extends \Zotlabs\Web\Controller { logger('verify failed.'); killme(); } - - - $r = attach_by_hash($resource,$revision); + + $r = attach_by_hash($resource,$channel['channel_hash'],$revision); if(! $r['success']) { + logger('attach_by_hash failed: ' . $r['message']); notice( $r['message'] . EOL); return; } - - + $unsafe_types = array('text/html','text/css','application/javascript'); if(in_array($r['data']['filetype'],$unsafe_types)) { @@ -76,10 +79,10 @@ class Getfile extends \Zotlabs\Web\Controller { else { header('Content-type: ' . $r['data']['filetype']); } - + header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"'); if(intval($r['data']['os_storage'])) { - $fname = dbunescbin($r['data']['data']); + $fname = dbunescbin($r['data']['content']); if(strpos($fname,'store') !== false) $istream = fopen($fname,'rb'); else @@ -91,11 +94,9 @@ class Getfile extends \Zotlabs\Web\Controller { fclose($ostream); } } - else - echo dbunescbin($r['data']['data']); + else { + echo dbunescbin($r['data']['content']); + } killme(); - - - } } diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php index 479925b66..54d4aecfb 100644 --- a/Zotlabs/Module/Help.php +++ b/Zotlabs/Module/Help.php @@ -17,6 +17,7 @@ require_once('include/help.php'); class Help extends \Zotlabs\Web\Controller { function get() { + nav_set_selected('help'); if($_REQUEST['search']) { @@ -36,8 +37,9 @@ class Help extends \Zotlabs\Web\Controller { $fname = substr($fname,0,strrpos($fname,'.')); $path = trim(substr($dirname,4),'/'); - $o .= '' . ucwords(str_replace('_',' ',notags($fname))) . ' '; + $o .= '
' . - str_replace('$Projectname',\Zotlabs\Lib\System::get_platform_name(),substr($rr['text'],0,200)) . '...' . ucwords(str_replace('_',' ',notags($fname))) . ' '; } $o .= ''; @@ -47,100 +49,18 @@ class Help extends \Zotlabs\Web\Controller { return $o; } - - global $lang; - - $doctype = 'markdown'; - - $text = ''; - - if(argc() > 1) { - $path = ''; - for($x = 1; $x < argc(); $x ++) { - if(strlen($path)) - $path .= '/'; - $path .= argv($x); - } - $title = basename($path); - - $text = load_doc_file('doc/' . $path . '.md'); - \App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title))); - - if(! $text) { - $text = load_doc_file('doc/' . $path . '.bb'); - if($text) - $doctype = 'bbcode'; - \App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('_',' ',notags($title))); - } - if(! $text) { - $text = load_doc_file('doc/' . $path . '.html'); - if($text) - $doctype = 'html'; - \App::$page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title))); - } - } - - if(! $text) { - $text = load_doc_file('doc/Site.md'); - \App::$page['title'] = t('Help'); - } - if(! $text) { - $doctype = 'bbcode'; - $text = load_doc_file('doc/main.bb'); - \App::$page['title'] = t('Help'); - } - - if(! strlen($text)) { - header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found')); - $tpl = get_markup_template("404.tpl"); - return replace_macros($tpl, array( - '$message' => t('Page not found.' ) - )); - } - - if($doctype === 'html') - $content = $text; - if($doctype === 'markdown') { - require_once('library/markdown.php'); - # escape #include tags - $text = preg_replace('/#include/ism', '%%include', $text); - $content = Markdown($text); - $content = preg_replace('/%%include/ism', '#include', $content); - } - if($doctype === 'bbcode') { - require_once('include/bbcode.php'); - $content = bbcode($text); - // bbcode retargets external content to new windows. This content is internal. - $content = str_replace(' target="_blank"','',$content); - } - - $content = preg_replace_callback("/#include (.*?)\;/ism", 'self::preg_callback_help_include', $content); - + + $content = get_help_content(); + + return replace_macros(get_markup_template("help.tpl"), array( '$title' => t('$Projectname Documentation'), - '$content' => translate_projectname($content) + '$content' => $content )); } - private static function preg_callback_help_include($matches) { - - if($matches[1]) { - $include = str_replace($matches[0],load_doc_file($matches[1]),$matches[0]); - if(preg_match('/\.bb$/', $matches[1]) || preg_match('/\.txt$/', $matches[1])) { - require_once('include/bbcode.php'); - $include = bbcode($include); - $include = str_replace(' target="_blank"','',$include); - } - elseif(preg_match('/\.md$/', $matches[1])) { - require_once('library/markdown.php'); - $include = Markdown($include); - } - return $include; - } - - } } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index d27f013b9..9574de07c 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -209,7 +209,7 @@ class Import extends \Zotlabs\Web\Controller { dbesc($channel['channel_guid']), dbesc($channel['channel_guid_sig']), dbesc($channel['channel_hash']), - dbesc($channel['channel_address'] . '@' . \App::get_hostname()), + dbesc(channel_reddress($channel)), dbesc('zot'), intval(($seize) ? 1 : 0), dbesc(z_root()), @@ -252,7 +252,7 @@ class Import extends \Zotlabs\Web\Controller { dbesc(z_root() . "/photo/profile/l/" . $channel['channel_id']), dbesc(z_root() . "/photo/profile/m/" . $channel['channel_id']), dbesc(z_root() . "/photo/profile/s/" . $channel['channel_id']), - dbesc($channel['channel_address'] . '@' . \App::get_hostname()), + dbesc(channel_reddress($channel)), dbesc(z_root() . '/channel/' . $channel['channel_address']), dbesc(z_root() . '/follow?f=&url=%s'), dbesc(z_root() . '/poco/' . $channel['channel_address']), diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php index 3d7438484..5198b1231 100644 --- a/Zotlabs/Module/Invite.php +++ b/Zotlabs/Module/Invite.php @@ -59,12 +59,15 @@ class Invite extends \Zotlabs\Web\Controller { $account = \App::get_account(); - - $res = mail($recip, sprintf( t('Please join us on $Projectname'), \App::$config['sitename']), - $nmessage, - "From: " . $account['account_email'] . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' ); + $res = z_mail( + [ + 'toEmail' => $recip, + 'fromName' => ' ', + 'fromEmail' => $account['account_email'], + 'messageSubject' => t('Please join us on $Projectname'), + 'textVersion' => $nmessage, + ] + ); if($res) { $total ++; diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 2d0c1ba02..a2128e47a 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -20,6 +20,8 @@ namespace Zotlabs\Module; require_once('include/crypto.php'); require_once('include/items.php'); require_once('include/attach.php'); +require_once('include/bbcode.php'); + use \Zotlabs\Lib as Zlib; @@ -81,6 +83,7 @@ class Item extends \Zotlabs\Web\Controller { $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false); $consensus = intval($_REQUEST['consensus']); + $nocomment = intval($_REQUEST['nocomment']); // 'origin' (if non-zero) indicates that this network is where the message originated, // for the purpose of relaying comments to other conversation members. @@ -549,6 +552,8 @@ class Item extends \Zotlabs\Web\Controller { $body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','\red_escape_codeblock',$body); $body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','\red_escape_codeblock',$body); + + $body = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ism", 'nakedoembed', $body); $body = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ism", '\red_zrl_callback', $body); $body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','\red_unescape_codeblock',$body); @@ -625,9 +630,9 @@ class Item extends \Zotlabs\Web\Controller { */ if(! $preview) { - $this->fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); - $this->fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); } @@ -707,6 +712,7 @@ class Item extends \Zotlabs\Web\Controller { $item_wall = (($post_type === 'wall' || $post_type === 'wall-comment') ? 1 : 0); $item_origin = (($origin) ? 1 : 0); $item_consensus = (($consensus) ? 1 : 0); + $item_nocomment = (($nocomment) ? 1 : 0); // determine if this is a wall post @@ -753,71 +759,64 @@ class Item extends \Zotlabs\Web\Controller { $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid; } - - - - - $datarray['aid'] = $channel['channel_account_id']; - $datarray['uid'] = $profile_uid; - - $datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']); - $datarray['author_xchan'] = $observer['xchan_hash']; - $datarray['created'] = $created; - $datarray['edited'] = (($orig_post) ? datetime_convert() : $created); - $datarray['expires'] = $expires; - $datarray['commented'] = (($orig_post) ? datetime_convert() : $created); - $datarray['received'] = (($orig_post) ? datetime_convert() : $created); - $datarray['changed'] = (($orig_post) ? datetime_convert() : $created); - $datarray['mid'] = $mid; - $datarray['parent_mid'] = $parent_mid; - $datarray['mimetype'] = $mimetype; - $datarray['title'] = $title; - $datarray['body'] = $body; - $datarray['app'] = $app; - $datarray['location'] = $location; - $datarray['coord'] = $coord; - $datarray['verb'] = $verb; - $datarray['obj_type'] = $obj_type; - $datarray['allow_cid'] = $str_contact_allow; - $datarray['allow_gid'] = $str_group_allow; - $datarray['deny_cid'] = $str_contact_deny; - $datarray['deny_gid'] = $str_group_deny; - $datarray['item_private'] = $private; - $datarray['item_wall'] = $item_wall; - $datarray['attach'] = $attachments; - $datarray['thr_parent'] = $thr_parent; - $datarray['postopts'] = $postopts; - $datarray['item_unseen'] = $item_unseen; - $datarray['item_wall'] = $item_wall; - $datarray['item_origin'] = $item_origin; - $datarray['item_type'] = $webpage; - $datarray['item_thread_top'] = $item_thread_top; - $datarray['item_unseen'] = $item_unseen; - $datarray['item_starred'] = $item_starred; - $datarray['item_uplink'] = $item_uplink; - $datarray['item_consensus'] = $item_consensus; - $datarray['item_notshown'] = $item_notshown; - $datarray['item_nsfw'] = $item_nsfw; - $datarray['item_relay'] = $item_relay; - $datarray['item_mentionsme'] = $item_mentionsme; - $datarray['item_nocomment'] = $item_nocomment; - $datarray['item_obscured'] = $item_obscured; - $datarray['item_verified'] = $item_verified; - $datarray['item_retained'] = $item_retained; - $datarray['item_rss'] = $item_rss; - $datarray['item_deleted'] = $item_deleted; - $datarray['item_hidden'] = $item_hidden; - $datarray['item_unpublished'] = $item_unpublished; - $datarray['item_delayed'] = $item_delayed; - $datarray['item_pending_remove'] = $item_pending_remove; - $datarray['item_blocked'] = $item_blocked; - - $datarray['layout_mid'] = $layout_mid; - $datarray['public_policy'] = $public_policy; - $datarray['comment_policy'] = map_scope($comment_policy); - $datarray['term'] = $post_tags; - $datarray['plink'] = $plink; - $datarray['route'] = $route; + $datarray['aid'] = $channel['channel_account_id']; + $datarray['uid'] = $profile_uid; + $datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']); + $datarray['author_xchan'] = $observer['xchan_hash']; + $datarray['created'] = $created; + $datarray['edited'] = (($orig_post) ? datetime_convert() : $created); + $datarray['expires'] = $expires; + $datarray['commented'] = (($orig_post) ? datetime_convert() : $created); + $datarray['received'] = (($orig_post) ? datetime_convert() : $created); + $datarray['changed'] = (($orig_post) ? datetime_convert() : $created); + $datarray['mid'] = $mid; + $datarray['parent_mid'] = $parent_mid; + $datarray['mimetype'] = $mimetype; + $datarray['title'] = $title; + $datarray['body'] = $body; + $datarray['app'] = $app; + $datarray['location'] = $location; + $datarray['coord'] = $coord; + $datarray['verb'] = $verb; + $datarray['obj_type'] = $obj_type; + $datarray['allow_cid'] = $str_contact_allow; + $datarray['allow_gid'] = $str_group_allow; + $datarray['deny_cid'] = $str_contact_deny; + $datarray['deny_gid'] = $str_group_deny; + $datarray['attach'] = $attachments; + $datarray['thr_parent'] = $thr_parent; + $datarray['postopts'] = $postopts; + $datarray['item_unseen'] = intval($item_unseen); + $datarray['item_wall'] = intval($item_wall); + $datarray['item_origin'] = intval($item_origin); + $datarray['item_type'] = $webpage; + $datarray['item_private'] = intval($private); + $datarray['item_thread_top'] = intval($item_thread_top); + $datarray['item_unseen'] = intval($item_unseen); + $datarray['item_starred'] = intval($item_starred); + $datarray['item_uplink'] = intval($item_uplink); + $datarray['item_consensus'] = intval($item_consensus); + $datarray['item_notshown'] = intval($item_notshown); + $datarray['item_nsfw'] = intval($item_nsfw); + $datarray['item_relay'] = intval($item_relay); + $datarray['item_mentionsme'] = intval($item_mentionsme); + $datarray['item_nocomment'] = intval($item_nocomment); + $datarray['item_obscured'] = intval($item_obscured); + $datarray['item_verified'] = intval($item_verified); + $datarray['item_retained'] = intval($item_retained); + $datarray['item_rss'] = intval($item_rss); + $datarray['item_deleted'] = intval($item_deleted); + $datarray['item_hidden'] = intval($item_hidden); + $datarray['item_unpublished'] = intval($item_unpublished); + $datarray['item_delayed'] = intval($item_delayed); + $datarray['item_pending_remove'] = intval($item_pending_remove); + $datarray['item_blocked'] = intval($item_blocked); + $datarray['layout_mid'] = $layout_mid; + $datarray['public_policy'] = $public_policy; + $datarray['comment_policy'] = map_scope($comment_policy); + $datarray['term'] = $post_tags; + $datarray['plink'] = $plink; + $datarray['route'] = $route; if($iconfig) $datarray['iconfig'] = $iconfig; @@ -927,7 +926,9 @@ class Item extends \Zotlabs\Web\Controller { $post = item_store($datarray,$execflag); $post_id = $post['item_id']; - + + $datarray = $post['item']; + if($post_id) { logger('mod_item: saved item ' . $post_id); @@ -1088,138 +1089,6 @@ class Item extends \Zotlabs\Web\Controller { } - function fix_attached_photo_permissions($uid,$xchan_hash,$body, - $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) { - - if(get_pconfig($uid,'system','force_public_uploads')) { - $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; - } - - $match = null; - // match img and zmg image links - if(preg_match_all("/\[[zi]mg(.*?)\](.*?)\[\/[zi]mg\]/",$body,$match)) { - $images = $match[2]; - if($images) { - foreach($images as $image) { - if(! stristr($image,z_root() . '/photo/')) - continue; - $image_uri = substr($image,strrpos($image,'/') + 1); - if(strpos($image_uri,'-') !== false) - $image_uri = substr($image_uri,0, strpos($image_uri,'-')); - if(strpos($image_uri,'.') !== false) - $image_uri = substr($image_uri,0, strpos($image_uri,'.')); - if(! strlen($image_uri)) - continue; - $srch = '<' . $xchan_hash . '>'; - - $r = q("select folder from attach where hash = '%s' and uid = %d limit 1", - dbesc($image_uri), - intval($uid) - ); - if($r && $r[0]['folder']) { - $f = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", - dbesc($r[0]['folder']), - intval($uid) - ); - if(($f) && (($f[0]['allow_cid']) || ($f[0]['allow_gid']) || ($f[0]['deny_cid']) || ($f[0]['deny_gid']))) { - $str_contact_allow = $f[0]['allow_cid']; - $str_group_allow = $f[0]['allow_gid']; - $str_contact_deny = $f[0]['deny_cid']; - $str_group_deny = $f[0]['deny_gid']; - } - } - - $r = q("SELECT id FROM photo - WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = '' - AND resource_id = '%s' AND uid = %d LIMIT 1", - dbesc($srch), - dbesc($image_uri), - intval($uid) - ); - - if($r) { - $r = q("UPDATE photo SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' - WHERE resource_id = '%s' AND uid = %d ", - dbesc($str_contact_allow), - dbesc($str_group_allow), - dbesc($str_contact_deny), - dbesc($str_group_deny), - dbesc($image_uri), - intval($uid) - ); - - // also update the linked item (which is probably invisible) - - $r = q("select id from item - WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = '' - AND resource_id = '%s' and resource_type = 'photo' AND uid = %d LIMIT 1", - dbesc($srch), - dbesc($image_uri), - intval($uid) - ); - if($r) { - $private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); - - $r = q("UPDATE item SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d - WHERE id = %d AND uid = %d", - dbesc($str_contact_allow), - dbesc($str_group_allow), - dbesc($str_contact_deny), - dbesc($str_group_deny), - intval($private), - intval($r[0]['id']), - intval($uid) - ); - } - $r = q("select id from attach where hash = '%s' and uid = %d limit 1", - dbesc($image_uri), - intval($uid) - ); - if($r) { - q("update attach SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' - WHERE id = %d AND uid = %d", - dbesc($str_contact_allow), - dbesc($str_group_allow), - dbesc($str_contact_deny), - dbesc($str_group_deny), - intval($r[0]['id']), - intval($uid) - ); - } - } - } - } - } - } - - - function fix_attached_file_permissions($channel,$observer_hash,$body, - $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) { - - if(get_pconfig($channel['channel_id'],'system','force_public_uploads')) { - $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; - } - - $match = false; - - if(preg_match_all("/\[attachment\](.*?)\[\/attachment\]/",$body,$match)) { - $attaches = $match[1]; - if($attaches) { - foreach($attaches as $attach) { - $hash = substr($attach,0,strpos($attach,',')); - $rev = intval(substr($attach,strpos($attach,','))); - attach_store($channel,$observer_hash,$options = 'update', array( - 'hash' => $hash, - 'revision' => $rev, - 'allow_cid' => $str_contact_allow, - 'allow_gid' => $str_group_allow, - 'deny_cid' => $str_contact_deny, - 'deny_gid' => $str_group_deny - )); - } - } - } - } function item_check_service_class($channel_id,$iswebpage) { $ret = array('success' => false, 'message' => ''); diff --git a/Zotlabs/Module/Lostpass.php b/Zotlabs/Module/Lostpass.php index eeddd0a13..072657d7b 100644 --- a/Zotlabs/Module/Lostpass.php +++ b/Zotlabs/Module/Lostpass.php @@ -43,18 +43,19 @@ class Lostpass extends \Zotlabs\Web\Controller { $subject = email_header_encode(sprintf( t('Password reset requested at %s'),get_config('system','sitename')), 'UTF-8'); - $res = mail($email, $subject , - $message, - 'From: Administrator@' . $_SERVER['SERVER_NAME'] . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' ); - - + $res = z_mail( + [ + 'toEmail' => $email, + 'messageSubject' => sprintf( t('Password reset requested at %s'), get_config('system','sitename')), + 'textVersion' => $message, + ] + ); + goaway(z_root()); } - function get() { + function get() { if(x($_GET,'verify')) { @@ -102,20 +103,22 @@ class Lostpass extends \Zotlabs\Web\Controller { $email_tpl = get_intltext_template("passchanged_eml.tpl"); $message = replace_macros($email_tpl, array( - '$sitename' => \App::$config['sitename'], - '$siteurl' => z_root(), - '$username' => sprintf( t('Site Member (%s)'), $email), - '$email' => $email, - '$new_password' => $new_password, - '$uid' => $newuid )); - - $subject = email_header_encode( sprintf( t('Your password has changed at %s'), get_config('system','sitename')), 'UTF-8'); - - $res = mail($email,$subject,$message, - 'From: ' . 'Administrator@' . $_SERVER['SERVER_NAME'] . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' ); + '$sitename' => \App::$config['sitename'], + '$siteurl' => z_root(), + '$username' => sprintf( t('Site Member (%s)'), $email), + '$email' => $email, + '$new_password' => $new_password, + '$uid' => $newuid ) + ); + $res = z_mail( + [ + 'toEmail' => $email, + 'messageSubject' => sprintf( t('Your password has changed at %s'), get_config('system','sitename')), + 'textVersion' => $message, + ] + ); + return $o; } diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php index 6798f72a9..9ee5f9324 100644 --- a/Zotlabs/Module/Magic.php +++ b/Zotlabs/Module/Magic.php @@ -140,7 +140,7 @@ class Magic extends \Zotlabs\Web\Controller { \Zotlabs\Zot\Verify::create('auth',$channel['channel_id'],$token,$x[0]['hubloc_url']); - $target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode($channel['channel_address'] . '@' . \App::get_hostname()) + $target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode(channel_reddress($channel)) . '&sec=' . $token . '&dest=' . urlencode($dest) . '&version=' . ZOT_REVISION; if($delegate) diff --git a/Zotlabs/Module/Mail.php b/Zotlabs/Module/Mail.php index 043c28078..a61b02cdf 100644 --- a/Zotlabs/Module/Mail.php +++ b/Zotlabs/Module/Mail.php @@ -60,7 +60,7 @@ class Mail extends \Zotlabs\Web\Controller { if($j['permissions']['data']) { $permissions = crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']); if($permissions) - $permissions = json_decode($permissions); + $permissions = json_decode($permissions, true); logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA); } else @@ -332,7 +332,7 @@ class Mail extends \Zotlabs\Web\Controller { 'delete' => t('Delete message'), 'dreport' => t('Delivery report'), 'recall' => t('Recall message'), - 'can_recall' => (($channel['channel_hash'] == $message['from_xchan']) ? true : false), + 'can_recall' => (($channel['channel_hash'] == $message['from_xchan'] && get_account_techlevel() > 0) ? true : false), 'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''), 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'], 'c'), ); diff --git a/Zotlabs/Module/Manage.php b/Zotlabs/Module/Manage.php index 8f815d6d4..ec9ef4c06 100644 --- a/Zotlabs/Module/Manage.php +++ b/Zotlabs/Module/Manage.php @@ -143,7 +143,7 @@ class Manage extends \Zotlabs\Web\Controller { $create = array( 'new_channel', t('Create a new channel'), t('Create New')); $delegates = q("select * from abook left join xchan on abook_xchan = xchan_hash where - abook_channel = %d and abook_xchan in ( select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'delegate' and v = 1 )", + abook_channel = %d and abook_xchan in ( select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'delegate' and v = '1' )", intval(local_channel()), intval(local_channel()) ); diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 0128adc2c..4f831c050 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -61,6 +61,7 @@ class Network extends \Zotlabs\Web\Controller { $search = (($_GET['search']) ? $_GET['search'] : ''); if($search) { + $_GET['netsearch'] = escape_tags($search); if(strpos($search,'@') === 0) { $r = q("select abook_id from abook left join xchan on abook_xchan = xchan_hash where xchan_name = '%s' and abook_channel = %d limit 1", dbesc(substr($search,1)), @@ -138,7 +139,7 @@ class Network extends \Zotlabs\Web\Controller { if($_GET['pf'] === '1') $deftag = '@' . t('forum') . '+' . intval($cid) . '+'; else - $def_acl = array('allow_cid' => '<' . $r[0]['abook_xchan'] . '>'); + $def_acl = [ 'allow_cid' => '<' . $r[0]['abook_xchan'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; } if(! $update) { @@ -159,7 +160,7 @@ class Network extends \Zotlabs\Web\Controller { 'allow_gid' => $channel['channel_allow_gid'], 'deny_cid' => $channel['channel_deny_cid'], 'deny_gid' => $channel['channel_deny_gid'] - ); + ); $private_editing = ((($group || $cid) && (! intval($_GET['pf']))) ? true : false); @@ -176,7 +177,8 @@ class Network extends \Zotlabs\Web\Controller { 'profile_uid' => local_channel(), 'editor_autocomplete' => true, 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true + 'bbcode' => true, + 'jotnets' => true ); if($deftag) $x['pretext'] = $deftag; diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php index 26883b6e2..8e6fd1d37 100644 --- a/Zotlabs/Module/New_channel.php +++ b/Zotlabs/Module/New_channel.php @@ -125,11 +125,16 @@ class New_channel extends \Zotlabs\Web\Controller { } } + $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" ); + + $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); + if((get_account_techlevel() < 4) && $privacy_role !== 'custom') + unset($perm_roles[t('Other')]); + $name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'), "*"); $nickhub = '@' . \App::get_hostname(); $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub), "*"); - $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" ); - $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' ' . t('Read more about roles') . '',get_roles()); + $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' ' . t('Read more about roles') . '',$perm_roles); $o = replace_macros(get_markup_template('new_channel.tpl'), array( '$title' => t('Create Channel'), diff --git a/Zotlabs/Module/Oembed.php b/Zotlabs/Module/Oembed.php index b02182053..9394e5942 100644 --- a/Zotlabs/Module/Oembed.php +++ b/Zotlabs/Module/Oembed.php @@ -22,10 +22,10 @@ class Oembed extends \Zotlabs\Web\Controller { } else { - echo ""; + echo "
' + . '' . 'help/' . (($path) ? $path . '/' : '') . $fname . '
' . + '...' . str_replace('$Projectname',\Zotlabs\Lib\System::get_platform_name(),$rr['text']) . '..."; $src = base64url_decode(argv(1)); $j = oembed_fetch_url($src); - echo $j->html; + echo $j['html']; // logger('mod-oembed ' . $h, LOGGER_ALL); echo ""; } diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php index 5cb00f165..618444480 100644 --- a/Zotlabs/Module/Pdledit.php +++ b/Zotlabs/Module/Pdledit.php @@ -9,6 +9,9 @@ class Pdledit extends \Zotlabs\Web\Controller { return; if(! $_REQUEST['module']) return; + if(! feature_enabled(local_channel(),'advanced_theming')) + return; + if(! trim($_REQUEST['content'])) { del_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl'); goaway(z_root() . '/pdledit/' . $_REQUEST['module']); @@ -26,6 +29,11 @@ class Pdledit extends \Zotlabs\Web\Controller { notice( t('Permission denied.') . EOL); return; } + + if(! feature_enabled(local_channel(),'advanced_theming')) { + notice( t('Feature disabled.') . EOL); + return; + } if(argc() > 1) $module = 'mod_' . argv(1) . '.pdl'; diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php index 66aaec49f..4332fd6e9 100644 --- a/Zotlabs/Module/Photo.php +++ b/Zotlabs/Module/Photo.php @@ -59,20 +59,33 @@ class Photo extends \Zotlabs\Web\Controller { } $uid = $person; - - $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1", - intval($resolution), - intval($uid), - intval(PHOTO_PROFILE) - ); - if($r) { - $data = dbunescbin($r[0]['content']); - $mimetype = $r[0]['mimetype']; + + $d = [ 'imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => '' ]; + call_hooks('get_profile_photo',$d); + + $resolution = $d['imgscale']; + $uid = $d['channel_id']; + $default = $d['default']; + $data = $d['data']; + $mimetype = $d['mimetype']; + + if(! $data) { + $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1", + intval($resolution), + intval($uid), + intval(PHOTO_PROFILE) + ); + if($r) { + $data = dbunescbin($r[0]['content']); + $mimetype = $r[0]['mimetype']; + } + if(intval($r[0]['os_storage'])) + $data = file_get_contents($data); } - if(intval($r[0]['os_storage'])) - $data = file_get_contents($data); - if(! isset($data)) { + if(! $data) { $data = file_get_contents($default); + } + if(! $mimetype) { $mimetype = 'image/png'; } } @@ -88,6 +101,7 @@ class Photo extends \Zotlabs\Web\Controller { Project link: https://github.com/Retina-Images/Retina-Images License link: http://creativecommons.org/licenses/by/3.0/ */ + $cookie_value = false; if (isset($_COOKIE['devicePixelRatio'])) { $cookie_value = intval($_COOKIE['devicePixelRatio']); @@ -114,15 +128,15 @@ class Photo extends \Zotlabs\Web\Controller { } // If using resolution 1, make sure it exists before proceeding: - if ($resolution == 1) - { + if($resolution == 1) { $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", dbesc($photo), intval($resolution) - ); - if (!($r)) + ); + if(! $r) { $resolution = 2; - } + } + } $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", dbesc($photo), @@ -133,7 +147,16 @@ class Photo extends \Zotlabs\Web\Controller { $allowed = (($r[0]['uid']) ? perm_is_allowed($r[0]['uid'],$observer_xchan,'view_storage') : true); $sql_extra = permissions_sql($r[0]['uid']); + + if(! $sql_extra) + $sql_extra = ' and true '; + + // Only check permissions on normal photos. Those photos we don't check includes + // profile photos, xchan photos (which are also profile photos), 'thing' photos, + // and cover photos + $sql_extra = " and (( photo_usage = 0 $sql_extra ) or photo_usage != 0 )"; + $channel = channelx_by_n($r[0]['uid']); // Now we'll see if we can access the photo diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php index 6aeac7af7..040a90aaa 100644 --- a/Zotlabs/Module/Photos.php +++ b/Zotlabs/Module/Photos.php @@ -50,7 +50,7 @@ class Photos extends \Zotlabs\Web\Controller { - function post() { + function post() { logger('mod-photos: photos_post: begin' , LOGGER_DEBUG); @@ -105,24 +105,6 @@ class Photos extends \Zotlabs\Web\Controller { } - /* - * RENAME photo album - */ - - $newalbum = notags(trim($_REQUEST['albumname'])); - if($newalbum != $album) { - - // @fixme - syncronise with DAV or disallow completely - - goaway(z_root() . '/' . $_SESSION['photo_return']); - - // $x = photos_album_rename($page_owner_uid,$album,$newalbum); - // if($x) { - // $newurl = str_replace(bin2hex($album),bin2hex($newalbum),$_SESSION['photo_return']); - // goaway(z_root() . '/' . $newurl); - // } - } - /* * DELETE photo album and all its photos */ @@ -229,15 +211,25 @@ class Photos extends \Zotlabs\Web\Controller { goaway(z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . $_SESSION['album_return']); } - - - if((\App::$argc > 2) && ((x($_POST,'desc') !== false) || (x($_POST,'newtag') !== false)) || (x($_POST,'albname') !== false)) { - + + if((argc() > 2) && array_key_exists('move_to_album',$_POST)) { + $m = q("select folder from attach where hash = '%s' and uid = %d limit 1", + dbesc(argv(2)), + intval($page_owner_uid) + ); + if(($m) && ($m[0]['folder'] != $_POST['move_to_album'])) { + attach_move($page_owner_uid,argv(2),$_POST['move_to_album']); + if(! ($_POST['desc'] && $_POST['newtag'])) + goaway(z_root() . '/' . $_SESSION['photo_return']); + } + } + + if((argc() > 2) && ((x($_POST,'desc') !== false) || (x($_POST,'newtag') !== false))) { $desc = ((x($_POST,'desc')) ? notags(trim($_POST['desc'])) : ''); $rawtags = ((x($_POST,'newtag')) ? notags(trim($_POST['newtag'])) : ''); $item_id = ((x($_POST,'item_id')) ? intval($_POST['item_id']) : 0); - $albname = ((x($_POST,'albname')) ? notags(trim($_POST['albname'])) : ''); + $is_nsfw = ((x($_POST,'adult')) ? intval($_POST['adult']) : 0); $acl->set_from_array($_POST); @@ -245,10 +237,6 @@ class Photos extends \Zotlabs\Web\Controller { $resource_id = argv(2); - if(! strlen($albname)) - $albname = datetime_convert('UTC',date_default_timezone_get(),'now', 'Y'); - - if((x($_POST,'rotate') !== false) && ( (intval($_POST['rotate']) == 1) || (intval($_POST['rotate']) == 2) )) { logger('rotate'); @@ -464,14 +452,15 @@ class Photos extends \Zotlabs\Web\Controller { } } - - goaway(z_root() . '/' . $_SESSION['photo_return']); - return; // NOTREACHED - + $sync = attach_export_data(\App::$data['channel'],$resource_id); if($sync) build_sync_packet($page_owner_uid,array('file' => array($sync))); + + goaway(z_root() . '/' . $_SESSION['photo_return']); + return; // NOTREACHED + } @@ -1023,12 +1012,22 @@ class Photos extends \Zotlabs\Web\Controller { $edit = null; if($can_post) { + + $m = q("select folder from attach where hash = '%s' and uid = %d limit 1", + dbesc($ph[0]['resource_id']), + intval($ph[0]['uid']) + ); + if($m) + $album_hash = $m[0]['folder']; + $album_e = $ph[0]['album']; $caption_e = $ph[0]['description']; $aclselect_e = (($_is_owner) ? populate_acl($ph[0], true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : ''); $albums = ((array_key_exists('albums', \App::$data)) ? \App::$data['albums'] : photos_albums_list(\App::$data['channel'],\App::$data['observer'])); $_SESSION['album_return'] = bin2hex($ph[0]['album']); + + $folder_list = attach_folder_select_list($ph[0]['uid']); $edit = array( 'edit' => t('Edit photo'), @@ -1037,6 +1036,7 @@ class Photos extends \Zotlabs\Web\Controller { 'rotateccw' => t('Rotate CCW (left)'), 'albums' => $albums['albums'], 'album' => $album_e, + 'album_select' => [ 'move_to_album', t('Move photo to album'), $album_hash, '', $folder_list ], 'newalbum_label' => t('Enter a new album name'), 'newalbum_placeholder' => t('or select an existing one (doubleclick)'), 'nickname' => \App::$data['channel']['channel_address'], diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php index 4b05182c2..788673296 100644 --- a/Zotlabs/Module/Profiles.php +++ b/Zotlabs/Module/Profiles.php @@ -724,7 +724,7 @@ class Profiles extends \Zotlabs\Web\Controller { '$marital' => marital_selector($r[0]['marital']), '$marital_min' => marital_selector_min($r[0]['marital']), '$with' => array('with', t("Who (if applicable)"), $r[0]['partner'], t('Examples: cathy123, Cathy Williams, cathy@example.com')), - '$howlong' => array('howlong', t('Since (date)'), ($r[0]['howlong'] === NULL_DATE ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong']))), + '$howlong' => array('howlong', t('Since (date)'), ($r[0]['howlong'] <= NULL_DATE ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong']))), '$sexual' => sexpref_selector($r[0]['sexual']), '$sexual_min' => sexpref_selector_min($r[0]['sexual']), '$about' => array('about', t('Tell us about yourself'), $r[0]['about']), diff --git a/Zotlabs/Module/Pubsites.php b/Zotlabs/Module/Pubsites.php index 0dda08e6d..1c9cd5121 100644 --- a/Zotlabs/Module/Pubsites.php +++ b/Zotlabs/Module/Pubsites.php @@ -16,7 +16,9 @@ class Pubsites extends \Zotlabs\Web\Controller { $url = $directory['url'] . '/dirsearch'; } $url .= '/sites'; - + + $rating_enabled = get_config('system','rating_enabled'); + $o .= ' '; $o .= ''; @@ -28,12 +30,20 @@ class Pubsites extends \Zotlabs\Web\Controller { if($ret['success']) { $j = json_decode($ret['body'],true); if($j) { - $o .= '' . t('Public Hubs') . '
'; + $o .= ' ' . t('Hub URL') . ' ' . t('Access Type') . ' ' . t('Registration Policy') . ' ' . t('Stats') . ' ' . t('Software') . ' ' . t('Ratings') . '
'; if($j['sites']) { foreach($j['sites'] as $jj) { - $m = parse_url($jj['url']); - if(strpos($jj['project'],\Zotlabs\Lib\System::get_platform_name()) === false) + if(! $jj['project']) continue; + if(strpos($jj['version'],' ')) { + $x = explode(' ', $jj['version']); + if($x[1]) + $jj['version'] = $x[1]; + } + $m = parse_url($jj['url']); $host = strtolower(substr($jj['url'],strpos($jj['url'],'://')+3)); $rate_links = ((local_channel()) ? ' ' . t('Hub URL') . ' ' . t('Access Type') . ' ' . t('Registration Policy') . ' ' . t('Stats') . ' ' . t('Software') . ' '; + if($rating_enabled) + $o .= '' . t('Ratings') . ' '; + $o .= '' . t('Rate') . ' ' : ''); $location = ''; @@ -44,7 +54,10 @@ class Pubsites extends \Zotlabs\Web\Controller { $location = '
'; } $urltext = str_replace(array('https://'), '', $jj['url']); - $o .= ''; + $o .= ' ' . $urltext . '' . $location . ' ' . $jj['access'] . ' ' . $jj['register'] . ' ' . ' ' . ucwords($jj['project']) . ' ' . t('View') . ' ' . $rate_links . ''; } } diff --git a/Zotlabs/Module/Rate.php b/Zotlabs/Module/Rate.php index 2f769b36b..c03aaa54f 100644 --- a/Zotlabs/Module/Rate.php +++ b/Zotlabs/Module/Rate.php @@ -119,8 +119,8 @@ class Rate extends \Zotlabs\Web\Controller { // return; // } - $poco_rating = get_config('system','poco_rating_enable'); - if((! $poco_rating) && ($poco_rating !== false)) { + $rating_enabled = get_config('system','rating_enabled'); + if(! $rating_enabled) { notice('Ratings are disabled on this site.'); return; } @@ -141,11 +141,7 @@ class Rate extends \Zotlabs\Web\Controller { $rating_text = ''; } - // if unset default to enabled - if($poco_rating === false) - $poco_rating = true; - - if($poco_rating) { + if($rating_enabled) { $rating = replace_macros(get_markup_template('rating_slider.tpl'),array( '$min' => -10, '$val' => $rating_val diff --git a/Zotlabs/Module/Ratings.php b/Zotlabs/Module/Ratings.php index 969fb5015..055b16ca3 100644 --- a/Zotlabs/Module/Ratings.php +++ b/Zotlabs/Module/Ratings.php @@ -21,12 +21,9 @@ class Ratings extends \Zotlabs\Web\Controller { if($x) $url = $x['url']; - $poco_rating = get_config('system','poco_rating_enable'); - // if unset default to enabled - if($poco_rating === false) - $poco_rating = true; + $rating_enabled = get_config('system','rating_enabled'); - if(! $poco_rating) + if(! $rating_enabled) return; if(argc() > 1) @@ -87,12 +84,9 @@ class Ratings extends \Zotlabs\Web\Controller { return; } - $poco_rating = get_config('system','poco_rating_enable'); - // if unset default to enabled - if($poco_rating === false) - $poco_rating = true; + $rating_enabled = get_config('system','rating_enabled'); - if(! $poco_rating) + if(! $rating_enabled) return; $site_target = ((array_key_exists('target',\App::$data) && array_key_exists('site_url',\App::$data['target'])) ? diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php index 0b16d4a66..1d8944d8e 100644 --- a/Zotlabs/Module/Register.php +++ b/Zotlabs/Module/Register.php @@ -174,7 +174,7 @@ class Register extends \Zotlabs\Web\Controller { - function get() { + function get() { $registration_is = ''; $other_sites = ''; @@ -205,6 +205,12 @@ class Register extends \Zotlabs\Web\Controller { return; } } + + $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : ""); + + $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); + if((get_account_techlevel() < 4) && $privacy_role !== 'custom') + unset($perm_roles[t('Other')]); // Configurable terms of service link @@ -231,8 +237,7 @@ class Register extends \Zotlabs\Web\Controller { $name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"')); $nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl')); $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub)); - $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : ""); - $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' ' . t('Read more about roles') . '',get_roles()); + $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel role with your privacy requirements.') . ' ' . t('Read more about roles') . '',$perm_roles); $tos = array('tos', $label_tos, '', '', array(t('no'),t('yes'))); $server_role = get_config('system','server_role'); @@ -254,11 +259,11 @@ class Register extends \Zotlabs\Web\Controller { '$invite_code' => $invite_code, '$auto_create' => $auto_create, '$name' => $name, - '$role' => $role, + '$role' => $role, '$default_role' => $default_role, '$nickname' => $nickname, '$enable_tos' => $enable_tos, - '$tos' => $tos, + '$tos' => $tos, '$email' => $email, '$pass1' => $password, '$pass2' => $password2, diff --git a/Zotlabs/Module/Removeaccount.php b/Zotlabs/Module/Removeaccount.php index 9fac7838e..9d2bbd0de 100644 --- a/Zotlabs/Module/Removeaccount.php +++ b/Zotlabs/Module/Removeaccount.php @@ -29,7 +29,7 @@ class Removeaccount extends \Zotlabs\Web\Controller { if(! ($x && $x['account'])) return; - if($account['account_password_changed'] != NULL_DATE) { + if($account['account_password_changed'] > NULL_DATE) { $d1 = datetime_convert('UTC','UTC','now - 48 hours'); if($account['account_password_changed'] > d1) { notice( t('Account removals are not allowed within 48 hours of changing the account password.') . EOL); diff --git a/Zotlabs/Module/Removeme.php b/Zotlabs/Module/Removeme.php index bc18fe0f8..ca2080e83 100644 --- a/Zotlabs/Module/Removeme.php +++ b/Zotlabs/Module/Removeme.php @@ -29,7 +29,7 @@ class Removeme extends \Zotlabs\Web\Controller { if(! ($x && $x['account'])) return; - if($account['account_password_changed'] != NULL_DATE) { + if($account['account_password_changed'] > NULL_DATE) { $d1 = datetime_convert('UTC','UTC','now - 48 hours'); if($account['account_password_changed'] > d1) { notice( t('Channel removals are not allowed within 48 hours of changing the account password.') . EOL); diff --git a/Zotlabs/Module/Rpost.php b/Zotlabs/Module/Rpost.php index 28a1f1bb0..1349cd1c5 100644 --- a/Zotlabs/Module/Rpost.php +++ b/Zotlabs/Module/Rpost.php @@ -127,7 +127,9 @@ class Rpost extends \Zotlabs\Web\Controller { 'return_path' => 'rpost/return', 'bbco_autocomplete' => 'bbcode', 'editor_autocomplete'=> true, - 'bbcode' => true + 'bbcode' => true, + 'jotnets' => true + ); $editor = status_editor($a,$x); diff --git a/Zotlabs/Module/Search_ac.php b/Zotlabs/Module/Search_ac.php index 4e936d97b..24b724c5d 100644 --- a/Zotlabs/Module/Search_ac.php +++ b/Zotlabs/Module/Search_ac.php @@ -18,49 +18,68 @@ class Search_ac extends \Zotlabs\Web\Controller { $search = $_REQUEST['query']; } + $do_people = true; + $do_tags = true; + + if(substr($search,0,1) === '@') { + $do_tags = false; + $search = substr($search,1); + } + + if(substr($search,0,1) === '#') { + $do_people = false; + $search = substr($search,1); + } + // Priority to people searches if ($search) { - $people_sql_extra = protect_sprintf(" AND `xchan_name` LIKE '%". dbesc($search) . "%' "); - $tag_sql_extra = protect_sprintf(" AND term LIKE '%". dbesc($search) . "%' "); + $people_sql_extra = protect_sprintf(" AND xchan_name LIKE '%" . dbesc($search) . "%' "); + $tag_sql_extra = protect_sprintf(" AND term LIKE '%" . dbesc($search) . "%' "); } + + $results = []; + if($do_people) { + $r = q("SELECT abook_id, xchan_name, xchan_photo_s, xchan_url, xchan_addr FROM abook + left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d + $people_sql_extra + ORDER BY xchan_name ASC ", + intval(local_channel()) + ); - $r = q("SELECT `abook_id`, `xchan_name`, `xchan_photo_s`, `xchan_url`, `xchan_addr` FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d - $people_sql_extra - ORDER BY `xchan_name` ASC ", - intval(local_channel()) - ); - - $results = array(); - if($r) { - foreach($r as $g) { - $results[] = array( - "photo" => $g['xchan_photo_s'], - "name" => '@'.$g['xchan_name'], - "id" => $g['abook_id'], - "link" => $g['xchan_url'], - "label" => '', - "nick" => '', - ); + if($r) { + foreach($r as $g) { + $results[] = [ + 'photo' => $g['xchan_photo_s'], + 'name' => '@' . $g['xchan_name'], + 'id' => $g['abook_id'], + 'link' => $g['xchan_url'], + 'label' => '', + 'nick' => '', + ]; + } } } + + if($do_tags) { + $r = q("select distinct term, tid, url from term + where ttype in ( %d, %d ) $tag_sql_extra group by term order by term asc", + intval(TERM_HASHTAG), + intval(TERM_COMMUNITYTAG) + ); - $r = q("select distinct term, tid, url from term where ttype in ( %d, %d ) $tag_sql_extra group by term order by term asc", - intval(TERM_HASHTAG), - intval(TERM_COMMUNITYTAG) - ); - - if(count($r)) { - foreach($r as $g) { - $results[] = array( - "photo" => z_root() . '/images/hashtag.png', - "name" => '#'.$g['term'], - "id" => $g['tid'], - "link" => $g['url'], - "label" => '', - "nick" => '', - ); + if($r) { + foreach($r as $g) { + $results[] = [ + 'photo' => z_root() . '/images/hashtag.png', + 'name' => '#' . $g['term'], + 'id' => $g['tid'], + 'link' => $g['url'], + 'label' => '', + 'nick' => '', + ]; + } } } @@ -72,7 +91,7 @@ class Search_ac extends \Zotlabs\Web\Controller { ); echo json_encode($o); - logger('search_ac: ' . print_r($x,true)); + logger('search_ac: ' . print_r($x,true),LOGGER_DATA,LOG_INFO); killme(); } diff --git a/Zotlabs/Module/Settings.php b/Zotlabs/Module/Settings.php index 12157944f..76794e21c 100644 --- a/Zotlabs/Module/Settings.php +++ b/Zotlabs/Module/Settings.php @@ -6,6 +6,8 @@ require_once('include/security.php'); class Settings extends \Zotlabs\Web\Controller { + private $sm = null; + function init() { if(! local_channel()) return; @@ -22,6 +24,8 @@ class Settings extends \Zotlabs\Web\Controller { \App::$argc = 2; \App::$argv[] = 'channel'; } + + $this->sm = new \Zotlabs\Web\SubModule(); } @@ -33,611 +37,24 @@ class Settings extends \Zotlabs\Web\Controller { if($_SESSION['delegate']) return; - $channel = \App::get_channel(); - // logger('mod_settings: ' . print_r($_REQUEST,true)); - - if((argc() > 1) && (argv(1) === 'oauth') && x($_POST,'remove')){ - check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); - - $key = $_POST['remove']; - q("DELETE FROM tokens WHERE id='%s' AND uid=%d", - dbesc($key), - local_channel()); - goaway(z_root()."/settings/oauth/"); - return; - } - - if((argc() > 2) && (argv(1) === 'oauth') && (argv(2) === 'edit'||(argv(2) === 'add')) && x($_POST,'submit')) { - - check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); - - $name = ((x($_POST,'name')) ? $_POST['name'] : ''); - $key = ((x($_POST,'key')) ? $_POST['key'] : ''); - $secret = ((x($_POST,'secret')) ? $_POST['secret'] : ''); - $redirect = ((x($_POST,'redirect')) ? $_POST['redirect'] : ''); - $icon = ((x($_POST,'icon')) ? $_POST['icon'] : ''); - $ok = true; - if($name == '') { - $ok = false; - notice( t('Name is required') . EOL); - } - if($key == '' || $secret == '') { - $ok = false; - notice( t('Key and Secret are required') . EOL); - } - - if($ok) { - if ($_POST['submit']==t("Update")){ - $r = q("UPDATE clients SET - client_id='%s', - pw='%s', - clname='%s', - redirect_uri='%s', - icon='%s', - uid=%d - WHERE client_id='%s'", - dbesc($key), - dbesc($secret), - dbesc($name), - dbesc($redirect), - dbesc($icon), - intval(local_channel()), - dbesc($key)); - } else { - $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid) - VALUES ('%s','%s','%s','%s','%s',%d)", - dbesc($key), - dbesc($secret), - dbesc($name), - dbesc($redirect), - dbesc($icon), - intval(local_channel()) - ); - $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", - dbesc($key), - intval(local_channel()), - dbesc('all') - ); - } - } - goaway(z_root()."/settings/oauth/"); - return; - } - - if((argc() > 1) && (argv(1) == 'featured')) { - check_form_security_token_redirectOnErr('/settings/featured', 'settings_featured'); - - call_hooks('feature_settings_post', $_POST); - - build_sync_packet(); - return; - } - - - if((argc() > 1) && (argv(1) == 'tokens')) { - check_form_security_token_redirectOnErr('/settings/tokens', 'settings_tokens'); - $token_errs = 0; - if(array_key_exists('token',$_POST)) { - $atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0); - $name = trim(escape_tags($_POST['name'])); - $token = trim($_POST['token']); - if((! $name) || (! $token)) - $token_errs ++; - if(trim($_POST['expires'])) - $expires = datetime_convert(date_default_timezone_get(),'UTC',$_POST['expires']); - else - $expires = NULL_DATE; - $max_atokens = service_class_fetch(local_channel(),'access_tokens'); - if($max_atokens) { - $r = q("select count(atoken_id) as total where atoken_uid = %d", - intval(local_channel()) - ); - if($r && intval($r[0]['total']) >= $max_tokens) { - notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL); - return; - } - } - } - if($token_errs) { - notice( t('Name and Password are required.') . EOL); + if(argc() > 1) { + if($this->sm->call('post') !== false) { return; } - if($atoken_id) { - $r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s' - where atoken_id = %d and atoken_uid = %d", - dbesc($name), - dbesc($token), - dbesc($expires), - intval($atoken_id), - intval($channel['channel_id']) - ); - } - else { - $r = q("insert into atoken ( atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires ) - values ( %d, %d, '%s', '%s', '%s' ) ", - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc($name), - dbesc($token), - dbesc($expires) - ); - } - - $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $name; - - $all_perms = \Zotlabs\Access\Permissions::Perms(); - - if($all_perms) { - foreach($all_perms as $perm => $desc) { - if(array_key_exists('perms_' . $perm, $_POST)) { - set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,intval($_POST['perms_' . $perm])); - } - else { - set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,0); - } - } - } - - - info( t('Token saved.') . EOL); - return; - } - - - - if((argc() > 1) && (argv(1) === 'features')) { - check_form_security_token_redirectOnErr('/settings/features', 'settings_features'); - - // Build list of features and check which are set - $features = get_features(); - $all_features = array(); - foreach($features as $k => $v) { - foreach($v as $f) - $all_features[] = $f[0]; - } - foreach($all_features as $k) { - if(x($_POST,"feature_$k")) - set_pconfig(local_channel(),'feature',$k, 1); - else - set_pconfig(local_channel(),'feature',$k, 0); - } - build_sync_packet(); - return; - } - - if((argc() > 1) && (argv(1) == 'display')) { - - check_form_security_token_redirectOnErr('/settings/display', 'settings_display'); - - $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : \App::$channel['channel_theme']); - $mobile_theme = ((x($_POST,'mobile_theme')) ? notags(trim($_POST['mobile_theme'])) : ''); - $preload_images = ((x($_POST,'preload_images')) ? intval($_POST['preload_images']) : 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); - $channel_list_mode = ((x($_POST,'channel_list_mode')) ? intval($_POST['channel_list_mode']) : 0); - $network_list_mode = ((x($_POST,'network_list_mode')) ? intval($_POST['network_list_mode']) : 0); - - $channel_divmore_height = ((x($_POST,'channel_divmore_height')) ? intval($_POST['channel_divmore_height']) : 400); - if($channel_divmore_height < 50) - $channel_divmore_height = 50; - $network_divmore_height = ((x($_POST,'network_divmore_height')) ? intval($_POST['network_divmore_height']) : 400); - if($network_divmore_height < 50) - $network_divmore_height = 50; - - $browser_update = ((x($_POST,'browser_update')) ? intval($_POST['browser_update']) : 0); - $browser_update = $browser_update * 1000; - if($browser_update < 10000) - $browser_update = 10000; - - $itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 20); - if($itemspage > 100) - $itemspage = 100; - - - if ($mobile_theme == "---") - del_pconfig(local_channel(),'system','mobile_theme'); - else { - set_pconfig(local_channel(),'system','mobile_theme',$mobile_theme); - } - - set_pconfig(local_channel(),'system','preload_images',$preload_images); - set_pconfig(local_channel(),'system','user_scalable',$user_scalable); - set_pconfig(local_channel(),'system','update_interval', $browser_update); - set_pconfig(local_channel(),'system','itemspage', $itemspage); - set_pconfig(local_channel(),'system','no_smilies',1-intval($nosmile)); - set_pconfig(local_channel(),'system','title_tosource',$title_tosource); - set_pconfig(local_channel(),'system','channel_list_mode', $channel_list_mode); - set_pconfig(local_channel(),'system','network_list_mode', $network_list_mode); - set_pconfig(local_channel(),'system','channel_divmore_height', $channel_divmore_height); - set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height); - - if ($theme == \App::$channel['channel_theme']){ - // call theme_post only if theme has not been changed - if( ($themeconfigfile = $this->get_theme_config_file($theme)) != null){ - require_once($themeconfigfile); - theme_post($a); - } - } - - $r = q("UPDATE channel SET channel_theme = '%s' WHERE channel_id = %d", - dbesc($theme), - intval(local_channel()) - ); - - call_hooks('display_settings_post', $_POST); - build_sync_packet(); - goaway(z_root() . '/settings/display' ); - return; // NOTREACHED - } - - - if(argc() > 1 && argv(1) === 'account') { - - check_form_security_token_redirectOnErr('/settings/account', 'settings_account'); - - call_hooks('account_settings_post', $_POST); - // call_hooks('settings_account', $_POST); - - $errs = array(); - - $email = ((x($_POST,'email')) ? trim(notags($_POST['email'])) : ''); - $account = \App::get_account(); - if($email != $account['account_email']) { - if(! valid_email($email)) - $errs[] = t('Not valid email.'); - $adm = trim(get_config('system','admin_email')); - if(($adm) && (strcasecmp($email,$adm) == 0)) { - $errs[] = t('Protected email address. Cannot change to that email.'); - $email = \App::$user['email']; - } - if(! $errs) { - $r = q("update account set account_email = '%s' where account_id = %d", - dbesc($email), - intval($account['account_id']) - ); - if(! $r) - $errs[] = t('System failure storing new email. Please try again.'); - } - } - - if($errs) { - foreach($errs as $err) - notice($err . EOL); - $errs = array(); - } - - - if((x($_POST,'npassword')) || (x($_POST,'confirm'))) { - - $origpass = trim($_POST['origpass']); - - require_once('include/auth.php'); - if(! account_verify_password($email,$origpass)) { - $errs[] = t('Password verification failed.'); - } - - $newpass = trim($_POST['npassword']); - $confirm = trim($_POST['confirm']); - - if($newpass != $confirm ) { - $errs[] = t('Passwords do not match. Password unchanged.'); - } - - if((! x($newpass)) || (! x($confirm))) { - $errs[] = t('Empty passwords are not allowed. Password unchanged.'); - } - - if(! $errs) { - $salt = random_string(32); - $password_encoded = hash('whirlpool', $salt . $newpass); - $r = q("update account set account_salt = '%s', account_password = '%s', account_password_changed = '%s' - where account_id = %d", - dbesc($salt), - dbesc($password_encoded), - dbesc(datetime_convert()), - intval(get_account_id()) - ); - if($r) - info( t('Password changed.') . EOL); - else - $errs[] = t('Password update failed. Please try again.'); - } - } - - - if($errs) { - foreach($errs as $err) - notice($err . EOL); - } - goaway(z_root() . '/settings/account' ); - } - - - check_form_security_token_redirectOnErr('/settings', 'settings'); - - call_hooks('settings_post', $_POST); - - $set_perms = ''; - - $role = ((x($_POST,'permissions_role')) ? notags(trim($_POST['permissions_role'])) : ''); - $oldrole = get_pconfig(local_channel(),'system','permissions_role'); - - if(($role != $oldrole) || ($role === 'custom')) { - - if($role === 'custom') { - $hide_presence = (((x($_POST,'hide_presence')) && (intval($_POST['hide_presence']) == 1)) ? 1: 0); - $publish = (((x($_POST,'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0); - $def_group = ((x($_POST,'group-selection')) ? notags(trim($_POST['group-selection'])) : ''); - $r = q("update channel set channel_default_group = '%s' where channel_id = %d", - dbesc($def_group), - intval(local_channel()) - ); - - $global_perms = \Zotlabs\Access\Permissions::Perms(); - - foreach($global_perms as $k => $v) { - \Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,intval($_POST[$k])); - } - $acl = new \Zotlabs\Access\AccessList($channel); - $acl->set_from_array($_POST); - $x = $acl->get(); - - $r = q("update channel set channel_allow_cid = '%s', channel_allow_gid = '%s', - channel_deny_cid = '%s', channel_deny_gid = '%s' where channel_id = %d", - dbesc($x['allow_cid']), - dbesc($x['allow_gid']), - dbesc($x['deny_cid']), - dbesc($x['deny_gid']), - intval(local_channel()) - ); - } - else { - $role_permissions = \Zotlabs\Access\PermissionRoles::role_perms($_POST['permissions_role']); - if(! $role_permissions) { - notice('Permissions category could not be found.'); - return; - } - $hide_presence = 1 - (intval($role_permissions['online'])); - if($role_permissions['default_collection']) { - $r = q("select hash from groups where uid = %d and gname = '%s' limit 1", - intval(local_channel()), - dbesc( t('Friends') ) - ); - if(! $r) { - require_once('include/group.php'); - group_add(local_channel(), t('Friends')); - group_add_member(local_channel(),t('Friends'),$channel['channel_hash']); - $r = q("select hash from groups where uid = %d and gname = '%s' limit 1", - intval(local_channel()), - dbesc( t('Friends') ) - ); - } - if($r) { - q("update channel set channel_default_group = '%s', channel_allow_gid = '%s', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d", - dbesc($r[0]['hash']), - dbesc('<' . $r[0]['hash'] . '>'), - intval(local_channel()) - ); - } - else { - notice( sprintf('Default privacy group \'%s\' not found. Please create and re-submit permission change.', t('Friends')) . EOL); - return; - } - } - // no default collection - else { - q("update channel set channel_default_group = '', channel_allow_gid = '', channel_allow_cid = '', channel_deny_gid = '', - channel_deny_cid = '' where channel_id = %d", - intval(local_channel()) - ); - } - - $x = \Zotlabs\Access\Permissions::FilledPerms($role_permissions['perms_connect']); - foreach($x as $k => $v) { - set_abconfig(local_channel(),$channel['channel_hash'],'my_perms',$k, $v); - if($role_permissions['perms_auto']) { - set_pconfig(local_channel(),'autoperms',$k,$v); - } - else { - del_pconfig(local_channel(),'autoperms',$k); - } - } - - if($role_permissions['limits']) { - foreach($role_permissions['limits'] as $k => $v) { - \Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,$v); - } - } - if(array_key_exists('directory_publish',$role_permissions)) { - $publish = intval($role_permissions['directory_publish']); - } - } - - set_pconfig(local_channel(),'system','hide_online_status',$hide_presence); - set_pconfig(local_channel(),'system','permissions_role',$role); - } - - $username = ((x($_POST,'username')) ? notags(trim($_POST['username'])) : ''); - $timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); - $defloc = ((x($_POST,'defloc')) ? notags(trim($_POST['defloc'])) : ''); - $openid = ((x($_POST,'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); - $maxreq = ((x($_POST,'maxreq')) ? intval($_POST['maxreq']) : 0); - $expire = ((x($_POST,'expire')) ? intval($_POST['expire']) : 0); - $evdays = ((x($_POST,'evdays')) ? intval($_POST['evdays']) : 3); - $photo_path = ((x($_POST,'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : ''); - $attach_path = ((x($_POST,'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : ''); - - $channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : ''); - - $expire_items = ((x($_POST,'expire_items')) ? intval($_POST['expire_items']) : 0); - $expire_starred = ((x($_POST,'expire_starred')) ? intval($_POST['expire_starred']) : 0); - $expire_photos = ((x($_POST,'expire_photos'))? intval($_POST['expire_photos']) : 0); - $expire_network_only = ((x($_POST,'expire_network_only'))? intval($_POST['expire_network_only']) : 0); - - $allow_location = (((x($_POST,'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1: 0); - - $blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted! - $unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0); - $cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0); - $suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0); - - $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0); - $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0); - $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0); - $adult = (($_POST['adult'] == 1) ? 1 : 0); - - $cal_first_day = (((x($_POST,'first_day')) && (intval($_POST['first_day']) == 1)) ? 1: 0); - - $channel = \App::get_channel(); - $pageflags = $channel['channel_pageflags']; - $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); - if($adult != $existing_adult) - $pageflags = ($pageflags ^ PAGE_ADULT); - - - $notify = 0; - - if(x($_POST,'notify1')) - $notify += intval($_POST['notify1']); - if(x($_POST,'notify2')) - $notify += intval($_POST['notify2']); - if(x($_POST,'notify3')) - $notify += intval($_POST['notify3']); - if(x($_POST,'notify4')) - $notify += intval($_POST['notify4']); - if(x($_POST,'notify5')) - $notify += intval($_POST['notify5']); - if(x($_POST,'notify6')) - $notify += intval($_POST['notify6']); - if(x($_POST,'notify7')) - $notify += intval($_POST['notify7']); - if(x($_POST,'notify8')) - $notify += intval($_POST['notify8']); - - - $vnotify = 0; - - if(x($_POST,'vnotify1')) - $vnotify += intval($_POST['vnotify1']); - if(x($_POST,'vnotify2')) - $vnotify += intval($_POST['vnotify2']); - if(x($_POST,'vnotify3')) - $vnotify += intval($_POST['vnotify3']); - if(x($_POST,'vnotify4')) - $vnotify += intval($_POST['vnotify4']); - if(x($_POST,'vnotify5')) - $vnotify += intval($_POST['vnotify5']); - if(x($_POST,'vnotify6')) - $vnotify += intval($_POST['vnotify6']); - if(x($_POST,'vnotify7')) - $vnotify += intval($_POST['vnotify7']); - if(x($_POST,'vnotify8')) - $vnotify += intval($_POST['vnotify8']); - if(x($_POST,'vnotify9')) - $vnotify += intval($_POST['vnotify9']); - if(x($_POST,'vnotify10')) - $vnotify += intval($_POST['vnotify10']); - if(x($_POST,'vnotify11')) - $vnotify += intval($_POST['vnotify11']); - - $always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0; - - $channel = \App::get_channel(); - - $err = ''; - - $name_change = false; - - if($username != $channel['channel_name']) { - $name_change = true; - require_once('include/channel.php'); - $err = validate_channelname($username); - if($err) { - notice($err); - return; - } - } - - if($timezone != $channel['channel_timezone']) { - if(strlen($timezone)) - date_default_timezone_set($timezone); - } - - set_pconfig(local_channel(),'system','use_browser_location',$allow_location); - set_pconfig(local_channel(),'system','suggestme', $suggestme); - set_pconfig(local_channel(),'system','post_newfriend', $post_newfriend); - set_pconfig(local_channel(),'system','post_joingroup', $post_joingroup); - set_pconfig(local_channel(),'system','post_profilechange', $post_profilechange); - set_pconfig(local_channel(),'system','blocktags',$blocktags); - set_pconfig(local_channel(),'system','channel_menu',$channel_menu); - set_pconfig(local_channel(),'system','vnotify',$vnotify); - set_pconfig(local_channel(),'system','always_show_in_notices',$always_show_in_notices); - set_pconfig(local_channel(),'system','evdays',$evdays); - set_pconfig(local_channel(),'system','photo_path',$photo_path); - set_pconfig(local_channel(),'system','attach_path',$attach_path); - set_pconfig(local_channel(),'system','cal_first_day',$cal_first_day); - - $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), - intval($pageflags), - dbesc($timezone), - dbesc($defloc), - intval($notify), - intval($unkmail), - intval($maxreq), - intval($expire), - intval(local_channel()) - ); - if($r) - info( t('Settings updated.') . EOL); - - if(! is_null($publish)) { - $r = q("UPDATE profile SET publish = %d WHERE is_default = 1 AND uid = %d", - intval($publish), - intval(local_channel()) - ); - } - - if($name_change) { - $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", - dbesc($username), - dbesc(datetime_convert()), - dbesc($channel['channel_hash']) - ); - $r = q("update profile set fullname = '%s' where uid = %d and is_default = 1", - dbesc($username), - intval($channel['channel_id']) - ); - } - - \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel())); - - build_sync_packet(); - - - //$_SESSION['theme'] = $theme; - if($email_changed && \App::$config['system']['register_policy'] == REGISTER_VERIFY) { - - // FIXME - set to un-verified, blocked and redirect to logout - // Why? Are we verifying people or email addresses? - } goaway(z_root() . '/settings' ); return; // NOTREACHED } - + function get() { - $o = ''; nav_set_selected('settings'); - if((! local_channel()) || ($_SESSION['delegate'])) { notice( t('Permission denied.') . EOL ); return login(); @@ -648,662 +65,14 @@ class Settings extends \Zotlabs\Web\Controller { if($channel) head_set_icon($channel['xchan_photo_s']); - $yes_no = array(t('No'),t('Yes')); - - if((argc() > 1) && (argv(1) === 'oauth')) { - - if((argc() > 2) && (argv(2) === 'add')) { - $tpl = get_markup_template("settings_oauth_edit.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth"), - '$title' => t('Add application'), - '$submit' => t('Submit'), - '$cancel' => t('Cancel'), - '$name' => array('name', t('Name'), '', t('Name of application')), - '$key' => array('key', t('Consumer Key'), random_string(16), t('Automatically generated - change if desired. Max length 20')), - '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), - '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), - '$icon' => array('icon', t('Icon url'), '', t('Optional')), - )); - return $o; - } - - if((argc() > 3) && (argv(2) === 'edit')) { - $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d", - dbesc(argv(3)), - local_channel()); - - if (!count($r)){ - notice(t('Application not found.')); - return; - } - $app = $r[0]; - - $tpl = get_markup_template("settings_oauth_edit.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth"), - '$title' => t('Add application'), - '$submit' => t('Update'), - '$cancel' => t('Cancel'), - '$name' => array('name', t('Name'), $app['clname'] , ''), - '$key' => array('key', t('Consumer Key'), $app['client_id'], ''), - '$secret' => array('secret', t('Consumer Secret'), $app['pw'], ''), - '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''), - '$icon' => array('icon', t('Icon url'), $app['icon'], ''), - )); - return $o; - } - - if((argc() > 3) && (argv(2) === 'delete')) { - check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth', 't'); - - $r = q("DELETE FROM clients WHERE client_id='%s' AND uid=%d", - dbesc(argv(3)), - local_channel()); - goaway(z_root()."/settings/oauth/"); - return; - } - - - $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my - FROM clients - LEFT JOIN tokens ON clients.client_id=tokens.client_id - WHERE clients.uid IN (%d,0)", - local_channel(), - local_channel()); - - - $tpl = get_markup_template("settings_oauth.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth"), - '$baseurl' => z_root(), - '$title' => t('Connected Apps'), - '$add' => t('Add application'), - '$edit' => t('Edit'), - '$delete' => t('Delete'), - '$consumerkey' => t('Client key starts with'), - '$noname' => t('No name'), - '$remove' => t('Remove authorization'), - '$apps' => $r, - )); + $o = $this->sm->call('get'); + if($o !== false) return $o; - - } - if((argc() > 1) && (argv(1) === 'featured')) { - $settings_addons = ""; - - $o = ''; - - $r = q("SELECT * FROM `hook` WHERE `hook` = 'feature_settings' "); - if(! $r) - $settings_addons = t('No feature settings configured'); - - call_hooks('feature_settings', $settings_addons); - - $tpl = get_markup_template("settings_addons.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_featured"), - '$title' => t('Feature/Addon Settings'), - '$settings_addons' => $settings_addons - )); - return $o; - } - - - /* - * ACCOUNT SETTINGS - */ - - - if((argc() > 1) && (argv(1) === 'account')) { - $account_settings = ""; - - call_hooks('account_settings', $account_settings); - - $email = \App::$account['account_email']; - - - $tpl = get_markup_template("settings_account.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_account"), - '$title' => t('Account Settings'), - '$origpass' => array('origpass', t('Current Password'), ' ',''), - '$password1'=> array('npassword', t('Enter New Password'), '', ''), - '$password2'=> array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')), - '$submit' => t('Submit'), - '$email' => array('email', t('Email Address:'), $email, ''), - '$removeme' => t('Remove Account'), - '$removeaccount' => t('Remove this account including all its channels'), - '$account_settings' => $account_settings - )); - return $o; - } - - if((argc() > 1) && (argv(1) === 'tokens')) { - $atoken = null; - $atoken_xchan = ''; - - if(argc() > 2) { - $id = argv(2); - - $atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d", - intval($id), - intval(local_channel()) - ); - - if($atoken) { - $atoken = $atoken[0]; - $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_name']; - } - - if($atoken && argc() > 3 && argv(3) === 'drop') { - atoken_delete($id); - $atoken = null; - $atoken_xchan = ''; - } - } - - $t = q("select * from atoken where atoken_uid = %d", - intval(local_channel()) - ); - - $desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'); - - $desc2 = t('You may also provide dropbox style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'); - - $global_perms = \Zotlabs\Access\Permissions::Perms(); - - $existing = get_all_perms(local_channel(),(($atoken_xchan) ? $atoken_xchan : '')); - - if($atoken_xchan) { - $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", - intval(local_channel()), - dbesc($atoken_xchan) - ); - $their_perms = array(); - if($theirs) { - foreach($theirs as $t) { - $their_perms[$t['k']] = $t['v']; - } - } - } - foreach($global_perms as $k => $v) { - $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k); -//fixme - - $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k); - - if($existing[$k]) - $thisperm = "1"; - - $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); - } - - - - $tpl = get_markup_template("settings_tokens.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_tokens"), - '$title' => t('Guest Access Tokens'), - '$desc' => $desc, - '$desc2' => $desc2, - '$tokens' => $t, - '$atoken' => $atoken, - '$url1' => z_root() . '/channel/' . $channel['channel_address'], - '$url2' => z_root() . '/photos/' . $channel['channel_address'], - '$name' => array('name', t('Login Name') . ' *', (($atoken) ? $atoken['atoken_name'] : ''),''), - '$token'=> array('token', t('Login Password') . ' *',(($atoken) ? $atoken['atoken_token'] : autoname(8)), ''), - '$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] != NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''), - '$them' => t('Their Settings'), - '$me' => t('My Settings'), - '$perms' => $perms, - '$inherited' => t('inherited'), - '$notself' => '1', - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), - '$submit' => t('Submit') - )); - return $o; - } + $o = ''; - - - if((argc() > 1) && (argv(1) === 'features')) { - $arr = array(); - $features = get_features(); - - foreach($features as $fname => $fdata) { - $arr[$fname] = array(); - $arr[$fname][0] = $fdata[0]; - foreach(array_slice($fdata,1) as $f) { - $arr[$fname][1][] = array('feature_' .$f[0],$f[1],((intval(feature_enabled(local_channel(),$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On'))); - } - } - - $tpl = get_markup_template("settings_features.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_features"), - '$title' => t('Additional Features'), - '$features' => $arr, - '$submit' => t('Submit'), - )); - - return $o; - } - - - - - - if((argc() > 1) && (argv(1) === 'connectors')) { - - $settings_connectors = ""; - - call_hooks('connector_settings', $settings_connectors); - - $r = null; - - $tpl = get_markup_template("settings_connectors.tpl"); - - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_connectors"), - '$title' => t('Connector Settings'), - '$submit' => t('Submit'), - '$settings_connectors' => $settings_connectors - )); - - call_hooks('display_settings', $o); - return $o; - } - - /* - * DISPLAY SETTINGS - */ - - if((argc() > 1) && (argv(1) === 'display')) { - $default_theme = get_config('system','theme'); - if(! $default_theme) - $default_theme = 'default'; - $default_mobile_theme = get_config('system','mobile_theme'); - if(! $mobile_default_theme) - $mobile_default_theme = 'none'; - - $allowed_themes_str = get_config('system','allowed_themes'); - $allowed_themes_raw = explode(',',$allowed_themes_str); - $allowed_themes = array(); - if(count($allowed_themes_raw)) - foreach($allowed_themes_raw as $x) - if(strlen(trim($x)) && is_dir("view/theme/$x")) - $allowed_themes[] = trim($x); - - - $themes = array(); - $files = glob('view/theme/*'); - if($allowed_themes) { - foreach($allowed_themes as $th) { - $f = $th; - $is_experimental = file_exists('view/theme/' . $th . '/experimental'); - $unsupported = file_exists('view/theme/' . $th . '/unsupported'); - $is_mobile = file_exists('view/theme/' . $th . '/mobile'); - $is_library = file_exists('view/theme/'. $th . '/library'); - $mobile_themes["---"] = t("No special theme for mobile devices"); - - if (!$is_experimental or ($is_experimental && (get_config('experimentals','exp_themes')==1 or get_config('experimentals','exp_themes')===false))){ - $theme_name = (($is_experimental) ? sprintf(t('%s - (Experimental)'), $f) : $f); - if (! $is_library) { - if($is_mobile) { - $mobile_themes[$f] = $themes[$f] = $theme_name . ' (' . t('mobile') . ')'; - } - else { - $mobile_themes[$f] = $themes[$f] = $theme_name; - } - } - } - - } - } - $theme_selected = (!x($_SESSION,'theme')? $default_theme : $_SESSION['theme']); - $mobile_theme_selected = (!x($_SESSION,'mobile_theme')? $default_mobile_theme : $_SESSION['mobile_theme']); - - $preload_images = get_pconfig(local_channel(),'system','preload_images'); - $preload_images = (($preload_images===false)? '0': $preload_images); // default if not set: 0 - - $user_scalable = get_pconfig(local_channel(),'system','user_scalable'); - $user_scalable = (($user_scalable===false)? '1': $user_scalable); // default if not set: 1 - - $browser_update = intval(get_pconfig(local_channel(), 'system','update_interval')); - $browser_update = (($browser_update == 0) ? 80 : $browser_update / 1000); // default if not set: 40 seconds - - $itemspage = intval(get_pconfig(local_channel(), 'system','itemspage')); - $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items - - $nosmile = get_pconfig(local_channel(),'system','no_smilies'); - $nosmile = (($nosmile===false)? '0': $nosmile); // default if not set: 0 - - $title_tosource = get_pconfig(local_channel(),'system','title_tosource'); - $title_tosource = (($title_tosource===false)? '0': $title_tosource); // default if not set: 0 - - $theme_config = ""; - if( ($themeconfigfile = $this->get_theme_config_file($theme_selected)) != null){ - require_once($themeconfigfile); - $theme_config = theme_content($a); - } - - $tpl = get_markup_template("settings_display.tpl"); - $o = replace_macros($tpl, array( - '$ptitle' => t('Display Settings'), - '$d_tset' => t('Theme Settings'), - '$d_ctset' => t('Custom Theme Settings'), - '$d_cset' => t('Content Settings'), - '$form_security_token' => get_form_security_token("settings_display"), - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$uid' => local_channel(), - - '$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false), - '$mobile_theme' => (($mobile_themes) ? array('mobile_theme', t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, '') : false), - '$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no), - '$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no), - '$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), - '$title_tosource' => array('title_tosource', t("Link post titles to source"), $title_tosource, '', $yes_no), - '$layout_editor' => t('System Page Layout Editor - (advanced)'), - '$theme_config' => $theme_config, - '$expert' => feature_enabled(local_channel(),'expert'), - '$channel_list_mode' => array('channel_list_mode', t('Use blog/list mode on channel page'), get_pconfig(local_channel(),'system','channel_list_mode'), t('(comments displayed separately)'), $yes_no), - '$network_list_mode' => array('network_list_mode', t('Use blog/list mode on grid page'), get_pconfig(local_channel(),'system','network_list_mode'), t('(comments displayed separately)'), $yes_no), - '$channel_divmore_height' => array('channel_divmore_height', t('Channel page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','channel_divmore_height')) ? get_pconfig(local_channel(),'system','channel_divmore_height') : 400), t('click to expand content exceeding this height')), - '$network_divmore_height' => array('network_divmore_height', t('Grid page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','network_divmore_height')) ? get_pconfig(local_channel(),'system','network_divmore_height') : 400) , t('click to expand content exceeding this height')), - - - )); - - return $o; - } - - if(argv(1) === 'channel') { - - require_once('include/acl_selectors.php'); - require_once('include/permissions.php'); - - - $p = q("SELECT * FROM `profile` WHERE `is_default` = 1 AND `uid` = %d LIMIT 1", - intval(local_channel()) - ); - if(count($p)) - $profile = $p[0]; - - load_pconfig(local_channel(),'expire'); - - $channel = \App::get_channel(); - - $global_perms = \Zotlabs\Access\Permissions::Perms(); - - $permiss = array(); - - $perm_opts = array( - array( t('Nobody except yourself'), 0), - array( t('Only those you specifically allow'), PERMS_SPECIFIC), - array( t('Approved connections'), PERMS_CONTACTS), - array( t('Any connections'), PERMS_PENDING), - array( t('Anybody on this website'), PERMS_SITE), - array( t('Anybody in this network'), PERMS_NETWORK), - array( t('Anybody authenticated'), PERMS_AUTHED), - array( t('Anybody on the internet'), PERMS_PUBLIC) - ); - - $limits = \Zotlabs\Access\PermissionLimits::Get(local_channel()); - - foreach($global_perms as $k => $perm) { - $options = array(); - foreach($perm_opts as $opt) { - $options[$opt[1]] = $opt[0]; - } - $permiss[] = array($k,$perm,$limits[$k],'',$options); - } - - - //logger('permiss: ' . print_r($permiss,true)); - - - - $username = $channel['channel_name']; - $nickname = $channel['channel_address']; - $timezone = $channel['channel_timezone']; - $notify = $channel['channel_notifyflags']; - $defloc = $channel['channel_location']; - - $maxreq = $channel['channel_max_friend_req']; - $expire = $channel['channel_expire_days']; - $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); - $sys_expire = get_config('system','default_expire_days'); - - // $unkmail = \App::$user['unkmail']; - // $cntunkmail = \App::$user['cntunkmail']; - - $hide_presence = intval(get_pconfig(local_channel(), 'system','hide_online_status')); - - - $expire_items = get_pconfig(local_channel(), 'expire','items'); - $expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1 - - $expire_notes = get_pconfig(local_channel(), 'expire','notes'); - $expire_notes = (($expire_notes===false)? '1' : $expire_notes); // default if not set: 1 - - $expire_starred = get_pconfig(local_channel(), 'expire','starred'); - $expire_starred = (($expire_starred===false)? '1' : $expire_starred); // default if not set: 1 - - $expire_photos = get_pconfig(local_channel(), 'expire','photos'); - $expire_photos = (($expire_photos===false)? '0' : $expire_photos); // default if not set: 0 - - $expire_network_only = get_pconfig(local_channel(), 'expire','network_only'); - $expire_network_only = (($expire_network_only===false)? '0' : $expire_network_only); // default if not set: 0 - - - $suggestme = get_pconfig(local_channel(), 'system','suggestme'); - $suggestme = (($suggestme===false)? '0': $suggestme); // default if not set: 0 - - $post_newfriend = get_pconfig(local_channel(), 'system','post_newfriend'); - $post_newfriend = (($post_newfriend===false)? '0': $post_newfriend); // default if not set: 0 - - $post_joingroup = get_pconfig(local_channel(), 'system','post_joingroup'); - $post_joingroup = (($post_joingroup===false)? '0': $post_joingroup); // default if not set: 0 - - $post_profilechange = get_pconfig(local_channel(), 'system','post_profilechange'); - $post_profilechange = (($post_profilechange===false)? '0': $post_profilechange); // default if not set: 0 - - $blocktags = get_pconfig(local_channel(),'system','blocktags'); - $blocktags = (($blocktags===false) ? '0' : $blocktags); - - $timezone = date_default_timezone_get(); - - $opt_tpl = get_markup_template("field_checkbox.tpl"); - if(get_config('system','publish_all')) { - $profile_in_dir = ''; - } - else { - $profile_in_dir = replace_macros($opt_tpl,array( - '$field' => array('profile_in_directory', t('Publish your default profile in the network directory'), $profile['publish'], '', $yes_no), - )); - } - - $suggestme = replace_macros($opt_tpl,array( - '$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no), - - )); - - $subdir = ((strlen(\App::get_path())) ? ' ' . $urltext . '' . $location . ' ' . $jj['access'] . ' ' . $jj['register'] . ' ' . ' ' . ucwords($jj['project']) . (($jj['version']) ? ' ' . $jj['version'] : '') . ' '; + if($rating_enabled) + $o .= '' . t('View') . ' ' . $rate_links ; + $o .= '
' . t('or') . ' ' . z_root() . '/channel/' . $nickname : ''); - - $tpl_addr = get_markup_template("settings_nick_set.tpl"); - - $prof_addr = replace_macros($tpl_addr,array( - '$desc' => t('Your channel address is'), - '$nickname' => $nickname, - '$subdir' => $subdir, - '$basepath' => \App::get_hostname() - )); - - $stpl = get_markup_template('settings.tpl'); - - $acl = new \Zotlabs\Access\AccessList($channel); - $perm_defaults = $acl->get(); - - require_once('include/group.php'); - $group_select = mini_group_select(local_channel(),$channel['channel_default_group']); - - require_once('include/menu.php'); - $m1 = menu_list(local_channel()); - $menu = false; - if($m1) { - $menu = array(); - $current = get_pconfig(local_channel(),'system','channel_menu'); - $menu[] = array('name' => '', 'selected' => ((! $current) ? true : false)); - foreach($m1 as $m) { - $menu[] = array('name' => htmlspecialchars($m['menu_name'],ENT_COMPAT,'UTF-8'), 'selected' => (($m['menu_name'] === $current) ? ' selected="selected" ' : false)); - } - } - - $evdays = get_pconfig(local_channel(),'system','evdays'); - if(! $evdays) - $evdays = 3; - - $permissions_role = get_pconfig(local_channel(),'system','permissions_role'); - if(! $permissions_role) - $permissions_role = 'custom'; - - $permissions_set = (($permissions_role != 'custom') ? true : false); - - $vnotify = get_pconfig(local_channel(),'system','vnotify'); - $always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices'); - if($vnotify === false) - $vnotify = (-1); - - $o .= replace_macros($stpl,array( - '$ptitle' => t('Channel Settings'), - - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$uid' => local_channel(), - '$form_security_token' => get_form_security_token("settings"), - '$nickname_block' => $prof_addr, - '$h_basic' => t('Basic Settings'), - '$username' => array('username', t('Full Name:'), $username,''), - '$email' => array('email', t('Email Address:'), $email, ''), - '$timezone' => array('timezone_select' , t('Your Timezone:'), $timezone, '', get_timezones()), - '$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')), - '$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no), - - '$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no), - - '$h_prv' => t('Security and Privacy Settings'), - '$permissions_set' => $permissions_set, - '$server_role' => \Zotlabs\Lib\System::get_server_role(), - '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), - - '$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), - - '$lbl_pmacro' => t('Simple Privacy Settings:'), - '$pmacro3' => t('Very Public - extremely permissive (should be used with caution)'), - '$pmacro2' => t('Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)'), - '$pmacro1' => t('Private - default private, never open or public'), - '$pmacro0' => t('Blocked - default blocked to/from everybody'), - '$permiss_arr' => $permiss, - '$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no), - - '$lbl_p2macro' => t('Advanced Privacy Settings'), - - '$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')), - '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')), - '$permissions' => t('Default Post and Publish Permissions'), - '$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'))), - '$allow_cid' => acl2json($perm_defaults['allow_cid']), - '$allow_gid' => acl2json($perm_defaults['allow_gid']), - '$deny_cid' => acl2json($perm_defaults['deny_cid']), - '$deny_gid' => acl2json($perm_defaults['deny_gid']), - '$suggestme' => $suggestme, - '$group_select' => $group_select, - '$role' => array('permissions_role' , t('Channel permissions category:'), $permissions_role, '', get_roles()), - - '$profile_in_dir' => $profile_in_dir, - '$hide_friends' => $hide_friends, - '$hide_wall' => $hide_wall, - '$unkmail' => $unkmail, - '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")), - - - '$h_not' => t('Notification Settings'), - '$activity_options' => t('By default post a status message when:'), - '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), - '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no), - '$post_profilechange' => array('post_profilechange', t('making an interesting profile change'), $post_profilechange, '', $yes_no), - '$lbl_not' => t('Send a notification email when:'), - '$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no), - '$notify2' => array('notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no), - '$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no), - '$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no), - '$notify5' => array('notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no), - '$notify6' => array('notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no), - '$notify7' => array('notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no), - '$notify8' => array('notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no), - - - '$lbl_vnot' => t('Show visual notifications including:'), - - '$vnotify1' => array('vnotify1', t('Unseen grid activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no), - '$vnotify2' => array('vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no), - '$vnotify3' => array('vnotify3', t('Unseen private messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no), - '$vnotify4' => array('vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no), - '$vnotify5' => array('vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no), - '$vnotify6' => array('vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no), - '$vnotify7' => array('vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no), - '$vnotify8' => array('vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no), - '$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no), - '$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), - '$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')), - - '$h_advn' => t('Advanced Account/Page Type Settings'), - '$h_descadvn' => t('Change the behaviour of this account for special situations'), - '$pagetype' => $pagetype, - '$expert' => feature_enabled(local_channel(),'expert'), - '$hint' => t('Please enable expert mode (in Settings > Additional features) to adjust!'), - '$lbl_misc' => t('Miscellaneous Settings'), - '$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')), - '$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')), - '$menus' => $menu, - '$menu_desc' => t('Personal menu to display in your channel pages'), - '$removeme' => t('Remove Channel'), - '$removechannel' => t('Remove this channel.'), - '$firefoxshare' => t('Firefox Share $Projectname provider'), - '$cal_first_day' => array('first_day', t('Start calendar week on monday'), ((get_pconfig(local_channel(),'system','cal_first_day')) ? 1 : ''), '', $yes_no), - )); - - call_hooks('settings_form',$o); - - //$o .= '' . "\r\n"; - - return $o; - } - } - - function get_theme_config_file($theme){ - - $base_theme = \App::$theme_info['extends']; - - if (file_exists("view/theme/$theme/php/config.php")){ - return "view/theme/$theme/php/config.php"; - } - if (file_exists("view/theme/$base_theme/php/config.php")){ - return "view/theme/$base_theme/php/config.php"; - } - return null; - } - - + } } + + diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php new file mode 100644 index 000000000..cd5ed1fca --- /dev/null +++ b/Zotlabs/Module/Settings/Account.php @@ -0,0 +1,135 @@ + t('Beginner/Basic'), + '1' => t('Novice - not skilled but willing to learn'), + '2' => t('Intermediate - somewhat comfortable'), + '3' => t('Advanced - very comfortable'), + '4' => t('Expert - I can write computer code'), + '5' => t('Wizard - I probably know more than you do') + ]; + + + $def_techlevel = \App::$account['account_level']; + $techlock = get_config('system','techlevel_lock'); + + $tpl = get_markup_template("settings_account.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_account"), + '$title' => t('Account Settings'), + '$origpass' => array('origpass', t('Current Password'), ' ',''), + '$password1'=> array('npassword', t('Enter New Password'), '', ''), + '$password2'=> array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')), + '$techlevel' => [ 'techlevel', t('Your technical skill level'), $def_techlevel, t('Used to provide a member experience matched to your comfort level'), $techlevels ], + '$techlock' => $techlock, + '$submit' => t('Submit'), + '$email' => array('email', t('Email Address:'), $email, ''), + '$removeme' => t('Remove Account'), + '$removeaccount' => t('Remove this account including all its channels'), + '$account_settings' => $account_settings + )); + return $o; + } + +} diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php new file mode 100644 index 000000000..a7d8b883f --- /dev/null +++ b/Zotlabs/Module/Settings/Channel.php @@ -0,0 +1,556 @@ + $v) { + \Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,intval($_POST[$k])); + } + $acl = new \Zotlabs\Access\AccessList($channel); + $acl->set_from_array($_POST); + $x = $acl->get(); + + $r = q("update channel set channel_allow_cid = '%s', channel_allow_gid = '%s', + channel_deny_cid = '%s', channel_deny_gid = '%s' where channel_id = %d", + dbesc($x['allow_cid']), + dbesc($x['allow_gid']), + dbesc($x['deny_cid']), + dbesc($x['deny_gid']), + intval(local_channel()) + ); + } + else { + $role_permissions = \Zotlabs\Access\PermissionRoles::role_perms($_POST['permissions_role']); + if(! $role_permissions) { + notice('Permissions category could not be found.'); + return; + } + $hide_presence = 1 - (intval($role_permissions['online'])); + if($role_permissions['default_collection']) { + $r = q("select hash from groups where uid = %d and gname = '%s' limit 1", + intval(local_channel()), + dbesc( t('Friends') ) + ); + if(! $r) { + require_once('include/group.php'); + group_add(local_channel(), t('Friends')); + group_add_member(local_channel(),t('Friends'),$channel['channel_hash']); + $r = q("select hash from groups where uid = %d and gname = '%s' limit 1", + intval(local_channel()), + dbesc( t('Friends') ) + ); + } + if($r) { + q("update channel set channel_default_group = '%s', channel_allow_gid = '%s', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d", + dbesc($r[0]['hash']), + dbesc('<' . $r[0]['hash'] . '>'), + intval(local_channel()) + ); + } + else { + notice( sprintf('Default privacy group \'%s\' not found. Please create and re-submit permission change.', t('Friends')) . EOL); + return; + } + } + // no default collection + else { + q("update channel set channel_default_group = '', channel_allow_gid = '', channel_allow_cid = '', channel_deny_gid = '', + channel_deny_cid = '' where channel_id = %d", + intval(local_channel()) + ); + } + + $x = \Zotlabs\Access\Permissions::FilledPerms($role_permissions['perms_connect']); + foreach($x as $k => $v) { + set_abconfig(local_channel(),$channel['channel_hash'],'my_perms',$k, $v); + if($role_permissions['perms_auto']) { + set_pconfig(local_channel(),'autoperms',$k,$v); + } + else { + del_pconfig(local_channel(),'autoperms',$k); + } + } + + if($role_permissions['limits']) { + foreach($role_permissions['limits'] as $k => $v) { + \Zotlabs\Access\PermissionLimits::Set(local_channel(),$k,$v); + } + } + if(array_key_exists('directory_publish',$role_permissions)) { + $publish = intval($role_permissions['directory_publish']); + } + } + + set_pconfig(local_channel(),'system','hide_online_status',$hide_presence); + set_pconfig(local_channel(),'system','permissions_role',$role); + } + + $username = ((x($_POST,'username')) ? notags(trim($_POST['username'])) : ''); + $timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); + $defloc = ((x($_POST,'defloc')) ? notags(trim($_POST['defloc'])) : ''); + $openid = ((x($_POST,'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); + $maxreq = ((x($_POST,'maxreq')) ? intval($_POST['maxreq']) : 0); + $expire = ((x($_POST,'expire')) ? intval($_POST['expire']) : 0); + $evdays = ((x($_POST,'evdays')) ? intval($_POST['evdays']) : 3); + $photo_path = ((x($_POST,'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : ''); + $attach_path = ((x($_POST,'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : ''); + + $channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : ''); + + $expire_items = ((x($_POST,'expire_items')) ? intval($_POST['expire_items']) : 0); + $expire_starred = ((x($_POST,'expire_starred')) ? intval($_POST['expire_starred']) : 0); + $expire_photos = ((x($_POST,'expire_photos'))? intval($_POST['expire_photos']) : 0); + $expire_network_only = ((x($_POST,'expire_network_only'))? intval($_POST['expire_network_only']) : 0); + + $allow_location = (((x($_POST,'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1: 0); + + $blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted! + $unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0); + $cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0); + $suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0); + + $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0); + $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0); + $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0); + $adult = (($_POST['adult'] == 1) ? 1 : 0); + + $cal_first_day = (((x($_POST,'first_day')) && (intval($_POST['first_day']) == 1)) ? 1: 0); + + $pageflags = $channel['channel_pageflags']; + $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); + if($adult != $existing_adult) + $pageflags = ($pageflags ^ PAGE_ADULT); + + + $notify = 0; + + if(x($_POST,'notify1')) + $notify += intval($_POST['notify1']); + if(x($_POST,'notify2')) + $notify += intval($_POST['notify2']); + if(x($_POST,'notify3')) + $notify += intval($_POST['notify3']); + if(x($_POST,'notify4')) + $notify += intval($_POST['notify4']); + if(x($_POST,'notify5')) + $notify += intval($_POST['notify5']); + if(x($_POST,'notify6')) + $notify += intval($_POST['notify6']); + if(x($_POST,'notify7')) + $notify += intval($_POST['notify7']); + if(x($_POST,'notify8')) + $notify += intval($_POST['notify8']); + + + $vnotify = 0; + + if(x($_POST,'vnotify1')) + $vnotify += intval($_POST['vnotify1']); + if(x($_POST,'vnotify2')) + $vnotify += intval($_POST['vnotify2']); + if(x($_POST,'vnotify3')) + $vnotify += intval($_POST['vnotify3']); + if(x($_POST,'vnotify4')) + $vnotify += intval($_POST['vnotify4']); + if(x($_POST,'vnotify5')) + $vnotify += intval($_POST['vnotify5']); + if(x($_POST,'vnotify6')) + $vnotify += intval($_POST['vnotify6']); + if(x($_POST,'vnotify7')) + $vnotify += intval($_POST['vnotify7']); + if(x($_POST,'vnotify8')) + $vnotify += intval($_POST['vnotify8']); + if(x($_POST,'vnotify9')) + $vnotify += intval($_POST['vnotify9']); + if(x($_POST,'vnotify10')) + $vnotify += intval($_POST['vnotify10']); + if(x($_POST,'vnotify11')) + $vnotify += intval($_POST['vnotify11']); + + $always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0; + + $err = ''; + + $name_change = false; + + if($username != $channel['channel_name']) { + $name_change = true; + require_once('include/channel.php'); + $err = validate_channelname($username); + if($err) { + notice($err); + return; + } + } + + if($timezone != $channel['channel_timezone']) { + if(strlen($timezone)) + date_default_timezone_set($timezone); + } + + set_pconfig(local_channel(),'system','use_browser_location',$allow_location); + set_pconfig(local_channel(),'system','suggestme', $suggestme); + set_pconfig(local_channel(),'system','post_newfriend', $post_newfriend); + set_pconfig(local_channel(),'system','post_joingroup', $post_joingroup); + set_pconfig(local_channel(),'system','post_profilechange', $post_profilechange); + set_pconfig(local_channel(),'system','blocktags',$blocktags); + set_pconfig(local_channel(),'system','channel_menu',$channel_menu); + set_pconfig(local_channel(),'system','vnotify',$vnotify); + set_pconfig(local_channel(),'system','always_show_in_notices',$always_show_in_notices); + set_pconfig(local_channel(),'system','evdays',$evdays); + set_pconfig(local_channel(),'system','photo_path',$photo_path); + set_pconfig(local_channel(),'system','attach_path',$attach_path); + set_pconfig(local_channel(),'system','cal_first_day',$cal_first_day); + + $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), + intval($pageflags), + dbesc($timezone), + dbesc($defloc), + intval($notify), + intval($unkmail), + intval($maxreq), + intval($expire), + intval(local_channel()) + ); + if($r) + info( t('Settings updated.') . EOL); + + if(! is_null($publish)) { + $r = q("UPDATE profile SET publish = %d WHERE is_default = 1 AND uid = %d", + intval($publish), + intval(local_channel()) + ); + } + + if($name_change) { + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", + dbesc($username), + dbesc(datetime_convert()), + dbesc($channel['channel_hash']) + ); + $r = q("update profile set fullname = '%s' where uid = %d and is_default = 1", + dbesc($username), + intval($channel['channel_id']) + ); + } + + \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel())); + + build_sync_packet(); + + + if($email_changed && \App::$config['system']['register_policy'] == REGISTER_VERIFY) { + + // FIXME - set to un-verified, blocked and redirect to logout + // Why? Are we verifying people or email addresses? + + } + + goaway(z_root() . '/settings' ); + return; // NOTREACHED + } + + function get() { + + require_once('include/acl_selectors.php'); + require_once('include/permissions.php'); + + + $yes_no = array(t('No'),t('Yes')); + + + $p = q("SELECT * FROM `profile` WHERE `is_default` = 1 AND `uid` = %d LIMIT 1", + intval(local_channel()) + ); + if(count($p)) + $profile = $p[0]; + + load_pconfig(local_channel(),'expire'); + + $channel = \App::get_channel(); + + $global_perms = \Zotlabs\Access\Permissions::Perms(); + + $permiss = array(); + + $perm_opts = array( + array( t('Nobody except yourself'), 0), + array( t('Only those you specifically allow'), PERMS_SPECIFIC), + array( t('Approved connections'), PERMS_CONTACTS), + array( t('Any connections'), PERMS_PENDING), + array( t('Anybody on this website'), PERMS_SITE), + array( t('Anybody in this network'), PERMS_NETWORK), + array( t('Anybody authenticated'), PERMS_AUTHED), + array( t('Anybody on the internet'), PERMS_PUBLIC) + ); + + $limits = \Zotlabs\Access\PermissionLimits::Get(local_channel()); + + foreach($global_perms as $k => $perm) { + $options = array(); + foreach($perm_opts as $opt) { + if((! strstr($perm,'view')) && $opt[1] == PERMS_PUBLIC) + continue; + $options[$opt[1]] = $opt[0]; + } + $permiss[] = array($k,$perm,$limits[$k],'',$options); + } + + + //logger('permiss: ' . print_r($permiss,true)); + + + + $username = $channel['channel_name']; + $nickname = $channel['channel_address']; + $timezone = $channel['channel_timezone']; + $notify = $channel['channel_notifyflags']; + $defloc = $channel['channel_location']; + + $maxreq = $channel['channel_max_friend_req']; + $expire = $channel['channel_expire_days']; + $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); + $sys_expire = get_config('system','default_expire_days'); + +// $unkmail = \App::$user['unkmail']; +// $cntunkmail = \App::$user['cntunkmail']; + + $hide_presence = intval(get_pconfig(local_channel(), 'system','hide_online_status')); + + + $expire_items = get_pconfig(local_channel(), 'expire','items'); + $expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1 + + $expire_notes = get_pconfig(local_channel(), 'expire','notes'); + $expire_notes = (($expire_notes===false)? '1' : $expire_notes); // default if not set: 1 + + $expire_starred = get_pconfig(local_channel(), 'expire','starred'); + $expire_starred = (($expire_starred===false)? '1' : $expire_starred); // default if not set: 1 + + $expire_photos = get_pconfig(local_channel(), 'expire','photos'); + $expire_photos = (($expire_photos===false)? '0' : $expire_photos); // default if not set: 0 + + $expire_network_only = get_pconfig(local_channel(), 'expire','network_only'); + $expire_network_only = (($expire_network_only===false)? '0' : $expire_network_only); // default if not set: 0 + + + $suggestme = get_pconfig(local_channel(), 'system','suggestme'); + $suggestme = (($suggestme===false)? '0': $suggestme); // default if not set: 0 + + $post_newfriend = get_pconfig(local_channel(), 'system','post_newfriend'); + $post_newfriend = (($post_newfriend===false)? '0': $post_newfriend); // default if not set: 0 + + $post_joingroup = get_pconfig(local_channel(), 'system','post_joingroup'); + $post_joingroup = (($post_joingroup===false)? '0': $post_joingroup); // default if not set: 0 + + $post_profilechange = get_pconfig(local_channel(), 'system','post_profilechange'); + $post_profilechange = (($post_profilechange===false)? '0': $post_profilechange); // default if not set: 0 + + $blocktags = get_pconfig(local_channel(),'system','blocktags'); + $blocktags = (($blocktags===false) ? '0' : $blocktags); + + $timezone = date_default_timezone_get(); + + $opt_tpl = get_markup_template("field_checkbox.tpl"); + if(get_config('system','publish_all')) { + $profile_in_dir = ''; + } + else { + $profile_in_dir = replace_macros($opt_tpl,array( + '$field' => array('profile_in_directory', t('Publish your default profile in the network directory'), $profile['publish'], '', $yes_no), + )); + } + + $suggestme = replace_macros($opt_tpl,array( + '$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no), + + )); + + $subdir = ((strlen(\App::get_path())) ? '
' . t('or') . ' ' . z_root() . '/channel/' . $nickname : ''); + + $tpl_addr = get_markup_template("settings_nick_set.tpl"); + + $prof_addr = replace_macros($tpl_addr,array( + '$desc' => t('Your channel address is'), + '$nickname' => $nickname, + '$subdir' => $subdir, + '$basepath' => \App::get_hostname() + )); + + $stpl = get_markup_template('settings.tpl'); + + $acl = new \Zotlabs\Access\AccessList($channel); + $perm_defaults = $acl->get(); + + require_once('include/group.php'); + $group_select = mini_group_select(local_channel(),$channel['channel_default_group']); + + require_once('include/menu.php'); + $m1 = menu_list(local_channel()); + $menu = false; + if($m1) { + $menu = array(); + $current = get_pconfig(local_channel(),'system','channel_menu'); + $menu[] = array('name' => '', 'selected' => ((! $current) ? true : false)); + foreach($m1 as $m) { + $menu[] = array('name' => htmlspecialchars($m['menu_name'],ENT_COMPAT,'UTF-8'), 'selected' => (($m['menu_name'] === $current) ? ' selected="selected" ' : false)); + } + } + + $evdays = get_pconfig(local_channel(),'system','evdays'); + if(! $evdays) + $evdays = 3; + + $permissions_role = get_pconfig(local_channel(),'system','permissions_role'); + if(! $permissions_role) + $permissions_role = 'custom'; + + $permissions_set = (($permissions_role != 'custom') ? true : false); + + $perm_roles = \Zotlabs\Access\PermissionRoles::roles(); + if((get_account_techlevel() < 4) && $permissions_role !== 'custom') + unset($perm_roles[t('Other')]); + + $vnotify = get_pconfig(local_channel(),'system','vnotify'); + $always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices'); + if($vnotify === false) + $vnotify = (-1); + + $o .= replace_macros($stpl,array( + '$ptitle' => t('Channel Settings'), + + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$uid' => local_channel(), + '$form_security_token' => get_form_security_token("settings"), + '$nickname_block' => $prof_addr, + '$h_basic' => t('Basic Settings'), + '$username' => array('username', t('Full Name:'), $username,''), + '$email' => array('email', t('Email Address:'), $email, ''), + '$timezone' => array('timezone_select' , t('Your Timezone:'), $timezone, '', get_timezones()), + '$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')), + '$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no), + + '$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no), + + '$h_prv' => t('Security and Privacy Settings'), + '$permissions_set' => $permissions_set, + '$server_role' => \Zotlabs\Lib\System::get_server_role(), + '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), + + '$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), + + '$lbl_pmacro' => t('Simple Privacy Settings:'), + '$pmacro3' => t('Very Public - extremely permissive (should be used with caution)'), + '$pmacro2' => t('Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)'), + '$pmacro1' => t('Private - default private, never open or public'), + '$pmacro0' => t('Blocked - default blocked to/from everybody'), + '$permiss_arr' => $permiss, + '$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no), + + '$lbl_p2macro' => t('Channel Permission Limits'), + + '$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')), + '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')), + '$permissions' => t('Default Access Control List (ACL)'), + '$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'))), + '$allow_cid' => acl2json($perm_defaults['allow_cid']), + '$allow_gid' => acl2json($perm_defaults['allow_gid']), + '$deny_cid' => acl2json($perm_defaults['deny_cid']), + '$deny_gid' => acl2json($perm_defaults['deny_gid']), + '$suggestme' => $suggestme, + '$group_select' => $group_select, + '$role' => array('permissions_role' , t('Channel permissions category:'), $permissions_role, '', $perm_roles), + + '$profile_in_dir' => $profile_in_dir, + '$hide_friends' => $hide_friends, + '$hide_wall' => $hide_wall, + '$unkmail' => $unkmail, + '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")), + + + '$h_not' => t('Notification Settings'), + '$activity_options' => t('By default post a status message when:'), + '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), + '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no), + '$post_profilechange' => array('post_profilechange', t('making an interesting profile change'), $post_profilechange, '', $yes_no), + '$lbl_not' => t('Send a notification email when:'), + '$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no), + '$notify2' => array('notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no), + '$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no), + '$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no), + '$notify5' => array('notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no), + '$notify6' => array('notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no), + '$notify7' => array('notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no), + '$notify8' => array('notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no), + + + '$lbl_vnot' => t('Show visual notifications including:'), + + '$vnotify1' => array('vnotify1', t('Unseen grid activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no), + '$vnotify2' => array('vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no), + '$vnotify3' => array('vnotify3', t('Unseen private messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no), + '$vnotify4' => array('vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no), + '$vnotify5' => array('vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no), + '$vnotify6' => array('vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no), + '$vnotify7' => array('vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no), + '$vnotify8' => array('vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no), + '$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no), + '$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), + '$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')), + + '$h_advn' => t('Advanced Account/Page Type Settings'), + '$h_descadvn' => t('Change the behaviour of this account for special situations'), + '$pagetype' => $pagetype, + '$lbl_misc' => t('Miscellaneous Settings'), + '$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')), + '$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')), + '$menus' => $menu, + '$menu_desc' => t('Personal menu to display in your channel pages'), + '$removeme' => t('Remove Channel'), + '$removechannel' => t('Remove this channel.'), + '$firefoxshare' => t('Firefox Share $Projectname provider'), + '$cal_first_day' => array('first_day', t('Start calendar week on monday'), ((get_pconfig(local_channel(),'system','cal_first_day')) ? 1 : ''), '', $yes_no), + )); + + call_hooks('settings_form',$o); + + //$o .= '' . "\r\n"; + + return $o; + } +} diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php new file mode 100644 index 000000000..8da875de7 --- /dev/null +++ b/Zotlabs/Module/Settings/Display.php @@ -0,0 +1,240 @@ + 100) + $itemspage = 100; + + if ($mobile_theme == "---") + del_pconfig(local_channel(),'system','mobile_theme'); + else { + set_pconfig(local_channel(),'system','mobile_theme',$mobile_theme); + } + + set_pconfig(local_channel(),'system','preload_images',$preload_images); + set_pconfig(local_channel(),'system','user_scalable',$user_scalable); + set_pconfig(local_channel(),'system','update_interval', $browser_update); + set_pconfig(local_channel(),'system','itemspage', $itemspage); + set_pconfig(local_channel(),'system','no_smilies',1-intval($nosmile)); + set_pconfig(local_channel(),'system','title_tosource',$title_tosource); + set_pconfig(local_channel(),'system','channel_list_mode', $channel_list_mode); + set_pconfig(local_channel(),'system','network_list_mode', $network_list_mode); + set_pconfig(local_channel(),'system','channel_divmore_height', $channel_divmore_height); + set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height); + + $newschema = ''; + if($theme == $existing_theme){ + // call theme_post only if theme has not been changed + if( ($themeconfigfile = $this->get_theme_config_file($theme)) != null){ + require_once($themeconfigfile); + if(class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { + $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; + $theme_config = new $clsname(); + $schemas = $theme_config->get_schemas(); + if(array_key_exists($_POST['schema'],$schemas)) + $newschema = $_POST['schema']; + if($newschema === '---') + $newschema = ''; + $theme_config->post(); + } + } + } + + logger('theme: ' . $theme . (($newschema) ? ':' . $newschema : '')); + + $_SESSION['theme'] = $theme . (($newschema) ? ':' . $newschema : ''); + + $r = q("UPDATE channel SET channel_theme = '%s' WHERE channel_id = %d", + dbesc($theme . (($newschema) ? ':' . $newschema : '')), + intval(local_channel()) + ); + + call_hooks('display_settings_post', $_POST); + build_sync_packet(); + goaway(z_root() . '/settings/display' ); + return; // NOTREACHED + } + + + function get() { + + $yes_no = array(t('No'),t('Yes')); + + $default_theme = get_config('system','theme'); + if(! $default_theme) + $default_theme = 'redbasic'; + + $themespec = explode(':', \App::$channel['channel_theme']); + $existing_theme = $themespec[0]; + $existing_schema = $themespec[1]; + + $theme = (($existing_theme) ? $existing_theme : $default_theme); + + $default_mobile_theme = get_config('system','mobile_theme'); + if(! $mobile_default_theme) + $mobile_default_theme = 'none'; + + $allowed_themes_str = get_config('system','allowed_themes'); + $allowed_themes_raw = explode(',',$allowed_themes_str); + $allowed_themes = array(); + if(count($allowed_themes_raw)) + foreach($allowed_themes_raw as $x) + if(strlen(trim($x)) && is_dir("view/theme/$x")) + $allowed_themes[] = trim($x); + + + $themes = array(); + $files = glob('view/theme/*'); + if($allowed_themes) { + foreach($allowed_themes as $th) { + $f = $th; + $is_experimental = file_exists('view/theme/' . $th . '/experimental'); + $unsupported = file_exists('view/theme/' . $th . '/unsupported'); + $is_mobile = file_exists('view/theme/' . $th . '/mobile'); + $is_library = file_exists('view/theme/'. $th . '/library'); + $mobile_themes["---"] = t("No special theme for mobile devices"); + + if (!$is_experimental or ($is_experimental && (get_config('experimentals','exp_themes')==1 or get_config('experimentals','exp_themes')===false))){ + $theme_name = (($is_experimental) ? sprintf(t('%s - (Experimental)'), $f) : $f); + if (! $is_library) { + if($is_mobile) { + $mobile_themes[$f] = $themes[$f] = $theme_name . ' (' . t('mobile') . ')'; + } + else { + $mobile_themes[$f] = $themes[$f] = $theme_name; + } + } + } + + } + } + + $theme_selected = ((array_key_exists('theme',$_SESSION) && $_SESSION['theme']) ? $_SESSION['theme'] : $theme); + + $mobile_theme_selected = (!x($_SESSION,'mobile_theme')? $default_mobile_theme : $_SESSION['mobile_theme']); + + $preload_images = get_pconfig(local_channel(),'system','preload_images'); + $preload_images = (($preload_images===false)? '0': $preload_images); // default if not set: 0 + + $user_scalable = get_pconfig(local_channel(),'system','user_scalable'); + $user_scalable = (($user_scalable===false)? '1': $user_scalable); // default if not set: 1 + + $browser_update = intval(get_pconfig(local_channel(), 'system','update_interval')); + $browser_update = (($browser_update == 0) ? 80 : $browser_update / 1000); // default if not set: 40 seconds + + $itemspage = intval(get_pconfig(local_channel(), 'system','itemspage')); + $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items + + $nosmile = get_pconfig(local_channel(),'system','no_smilies'); + $nosmile = (($nosmile===false)? '0': $nosmile); // default if not set: 0 + + $title_tosource = get_pconfig(local_channel(),'system','title_tosource'); + $title_tosource = (($title_tosource===false)? '0': $title_tosource); // default if not set: 0 + + $theme_config = ""; + if(($themeconfigfile = $this->get_theme_config_file($theme)) != null){ + require_once($themeconfigfile); + if(class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { + $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; + $thm_config = new $clsname(); + $schemas = $thm_config->get_schemas(); + $theme_config = $thm_config->get(); + } + } + + // logger('schemas: ' . print_r($schemas,true)); + + $tpl = get_markup_template("settings_display.tpl"); + $o = replace_macros($tpl, array( + '$ptitle' => t('Display Settings'), + '$d_tset' => t('Theme Settings'), + '$d_ctset' => t('Custom Theme Settings'), + '$d_cset' => t('Content Settings'), + '$form_security_token' => get_form_security_token("settings_display"), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$uid' => local_channel(), + + '$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false), + '$schema' => array('schema', t('Select scheme'), $existing_schema, '' , $schemas), + + '$mobile_theme' => (($mobile_themes) ? array('mobile_theme', t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, '') : false), + '$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no), + '$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no), + '$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), + '$title_tosource' => array('title_tosource', t("Link post titles to source"), $title_tosource, '', $yes_no), + '$layout_editor' => t('System Page Layout Editor - (advanced)'), + '$theme_config' => $theme_config, + '$expert' => feature_enabled(local_channel(),'advanced_theming'), + '$channel_list_mode' => array('channel_list_mode', t('Use blog/list mode on channel page'), get_pconfig(local_channel(),'system','channel_list_mode'), t('(comments displayed separately)'), $yes_no), + '$network_list_mode' => array('network_list_mode', t('Use blog/list mode on grid page'), get_pconfig(local_channel(),'system','network_list_mode'), t('(comments displayed separately)'), $yes_no), + '$channel_divmore_height' => array('channel_divmore_height', t('Channel page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','channel_divmore_height')) ? get_pconfig(local_channel(),'system','channel_divmore_height') : 400), t('click to expand content exceeding this height')), + '$network_divmore_height' => array('network_divmore_height', t('Grid page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','network_divmore_height')) ? get_pconfig(local_channel(),'system','network_divmore_height') : 400) , t('click to expand content exceeding this height')), + + + )); + + call_hooks('display_settings',$o); + return $o; + } + + + function get_theme_config_file($theme){ + + $base_theme = \App::$theme_info['extends']; + + if (file_exists("view/theme/$theme/php/config.php")){ + return "view/theme/$theme/php/config.php"; + } + if (file_exists("view/theme/$base_theme/php/config.php")){ + return "view/theme/$base_theme/php/config.php"; + } + return null; + } + + + + +} \ No newline at end of file diff --git a/Zotlabs/Module/Settings/Featured.php b/Zotlabs/Module/Settings/Featured.php new file mode 100644 index 000000000..7d7b1a734 --- /dev/null +++ b/Zotlabs/Module/Settings/Featured.php @@ -0,0 +1,37 @@ + get_form_security_token("settings_featured"), + '$title' => t('Feature/Addon Settings'), + '$settings_addons' => $settings_addons + )); + return $o; + } + +} \ No newline at end of file diff --git a/Zotlabs/Module/Settings/Features.php b/Zotlabs/Module/Settings/Features.php new file mode 100644 index 000000000..5b642acc3 --- /dev/null +++ b/Zotlabs/Module/Settings/Features.php @@ -0,0 +1,53 @@ + $v) { + foreach($v as $f) + $all_features[] = $f[0]; + } + foreach($all_features as $k) { + if(x($_POST,"feature_$k")) + set_pconfig(local_channel(),'feature',$k, 1); + else + set_pconfig(local_channel(),'feature',$k, 0); + } + build_sync_packet(); + return; + } + + function get() { + $arr = array(); + $features = get_features(); + + foreach($features as $fname => $fdata) { + $arr[$fname] = array(); + $arr[$fname][0] = $fdata[0]; + foreach(array_slice($fdata,1) as $f) { + $arr[$fname][1][] = array('feature_' .$f[0],$f[1],((intval(feature_enabled(local_channel(),$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On'))); + } + } + + $tpl = get_markup_template("settings_features.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_features"), + '$title' => t('Additional Features'), + '$features' => $arr, + '$submit' => t('Submit'), + )); + + return $o; + } + +} diff --git a/Zotlabs/Module/Settings/Oauth.php b/Zotlabs/Module/Settings/Oauth.php new file mode 100644 index 000000000..c612c7667 --- /dev/null +++ b/Zotlabs/Module/Settings/Oauth.php @@ -0,0 +1,160 @@ + 2) && (argv(2) === 'edit' || argv(2) === 'add') && x($_POST,'submit')) { + + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); + + $name = ((x($_POST,'name')) ? $_POST['name'] : ''); + $key = ((x($_POST,'key')) ? $_POST['key'] : ''); + $secret = ((x($_POST,'secret')) ? $_POST['secret'] : ''); + $redirect = ((x($_POST,'redirect')) ? $_POST['redirect'] : ''); + $icon = ((x($_POST,'icon')) ? $_POST['icon'] : ''); + $ok = true; + if($name == '') { + $ok = false; + notice( t('Name is required') . EOL); + } + if($key == '' || $secret == '') { + $ok = false; + notice( t('Key and Secret are required') . EOL); + } + + if($ok) { + if ($_POST['submit']==t("Update")){ + $r = q("UPDATE clients SET + client_id='%s', + pw='%s', + clname='%s', + redirect_uri='%s', + icon='%s', + uid=%d + WHERE client_id='%s'", + dbesc($key), + dbesc($secret), + dbesc($name), + dbesc($redirect), + dbesc($icon), + intval(local_channel()), + dbesc($key)); + } else { + $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid) + VALUES ('%s','%s','%s','%s','%s',%d)", + dbesc($key), + dbesc($secret), + dbesc($name), + dbesc($redirect), + dbesc($icon), + intval(local_channel()) + ); + $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", + dbesc($key), + intval(local_channel()), + dbesc('all') + ); + } + } + goaway(z_root()."/settings/oauth/"); + return; + } + } + + function get() { + + if((argc() > 2) && (argv(2) === 'add')) { + $tpl = get_markup_template("settings_oauth_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$title' => t('Add application'), + '$submit' => t('Submit'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), '', t('Name of application')), + '$key' => array('key', t('Consumer Key'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), + '$icon' => array('icon', t('Icon url'), '', t('Optional')), + )); + return $o; + } + + if((argc() > 3) && (argv(2) === 'edit')) { + $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d", + dbesc(argv(3)), + local_channel()); + + if (!count($r)){ + notice(t('Application not found.')); + return; + } + $app = $r[0]; + + $tpl = get_markup_template("settings_oauth_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$title' => t('Add application'), + '$submit' => t('Update'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), $app['clname'] , ''), + '$key' => array('key', t('Consumer Key'), $app['client_id'], ''), + '$secret' => array('secret', t('Consumer Secret'), $app['pw'], ''), + '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''), + '$icon' => array('icon', t('Icon url'), $app['icon'], ''), + )); + return $o; + } + + if((argc() > 3) && (argv(2) === 'delete')) { + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth', 't'); + + $r = q("DELETE FROM clients WHERE client_id='%s' AND uid=%d", + dbesc(argv(3)), + local_channel()); + goaway(z_root()."/settings/oauth/"); + return; + } + + + $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my + FROM clients + LEFT JOIN tokens ON clients.client_id=tokens.client_id + WHERE clients.uid IN (%d,0)", + local_channel(), + local_channel()); + + + $tpl = get_markup_template("settings_oauth.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$baseurl' => z_root(), + '$title' => t('Connected Apps'), + '$add' => t('Add application'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$consumerkey' => t('Client key starts with'), + '$noname' => t('No name'), + '$remove' => t('Remove authorization'), + '$apps' => $r, + )); + return $o; + + } + +} \ No newline at end of file diff --git a/Zotlabs/Module/Settings/Tokens.php b/Zotlabs/Module/Settings/Tokens.php new file mode 100644 index 000000000..e63fed128 --- /dev/null +++ b/Zotlabs/Module/Settings/Tokens.php @@ -0,0 +1,172 @@ += $max_tokens) { + notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL); + return; + } + } + } + if($token_errs) { + notice( t('Name and Password are required.') . EOL); + return; + } + if($atoken_id) { + $r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s' + where atoken_id = %d and atoken_uid = %d", + dbesc($name), + dbesc($token), + dbesc($expires), + intval($atoken_id), + intval($channel['channel_id']) + ); + } + else { + $r = q("insert into atoken ( atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires ) + values ( %d, %d, '%s', '%s', '%s' ) ", + intval($channel['channel_account_id']), + intval($channel['channel_id']), + dbesc($name), + dbesc($token), + dbesc($expires) + ); + } + + $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $name; + + $all_perms = \Zotlabs\Access\Permissions::Perms(); + + if($all_perms) { + foreach($all_perms as $perm => $desc) { + if(array_key_exists('perms_' . $perm, $_POST)) { + set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,intval($_POST['perms_' . $perm])); + } + else { + set_abconfig($channel['channel_id'],$atoken_xchan,'my_perms',$perm,0); + } + } + } + + + info( t('Token saved.') . EOL); + return; + } + + + function get() { + + $channel = \App::get_channel(); + + $atoken = null; + $atoken_xchan = ''; + + if(argc() > 2) { + $id = argv(2); + + $atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d", + intval($id), + intval(local_channel()) + ); + + if($atoken) { + $atoken = $atoken[0]; + $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_name']; + } + + if($atoken && argc() > 3 && argv(3) === 'drop') { + atoken_delete($id); + $atoken = null; + $atoken_xchan = ''; + } + } + + $t = q("select * from atoken where atoken_uid = %d", + intval(local_channel()) + ); + + $desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'); + + $desc2 = t('You may also provide dropbox style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'); + + $global_perms = \Zotlabs\Access\Permissions::Perms(); + + $existing = get_all_perms(local_channel(),(($atoken_xchan) ? $atoken_xchan : '')); + + if($atoken_xchan) { + $theirs = q("select * from abconfig where chan = %d and xchan = '%s' and cat = 'their_perms'", + intval(local_channel()), + dbesc($atoken_xchan) + ); + $their_perms = array(); + if($theirs) { + foreach($theirs as $t) { + $their_perms[$t['k']] = $t['v']; + } + } + } + foreach($global_perms as $k => $v) { + $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k); +//fixme + + $checkinherited = \Zotlabs\Access\PermissionLimits::Get(local_channel(),$k); + + if($existing[$k]) + $thisperm = "1"; + + $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); + } + + + + $tpl = get_markup_template("settings_tokens.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_tokens"), + '$title' => t('Guest Access Tokens'), + '$desc' => $desc, + '$desc2' => $desc2, + '$tokens' => $t, + '$atoken' => $atoken, + '$url1' => z_root() . '/channel/' . $channel['channel_address'], + '$url2' => z_root() . '/photos/' . $channel['channel_address'], + '$name' => array('name', t('Login Name') . ' *', (($atoken) ? $atoken['atoken_name'] : ''),''), + '$token'=> array('token', t('Login Password') . ' *',(($atoken) ? $atoken['atoken_token'] : autoname(8)), ''), + '$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] > NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''), + '$them' => t('Their Settings'), + '$me' => t('My Settings'), + '$perms' => $perms, + '$inherited' => t('inherited'), + '$notself' => '1', + '$permlbl' => t('Individual Permissions'), + '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), + '$submit' => t('Submit') + )); + return $o; + } + +} \ No newline at end of file diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php index 4553b6866..88481b4b1 100644 --- a/Zotlabs/Module/Setup.php +++ b/Zotlabs/Module/Setup.php @@ -43,11 +43,12 @@ class Setup extends \Zotlabs\Web\Controller { killme(); } - if (x($_POST, 'pass')) + if (x($_POST, 'pass')) { $this->install_wizard_pass = intval($_POST['pass']); - else + } + else { $this->install_wizard_pass = 1; - + } } /** @@ -73,7 +74,9 @@ class Setup extends \Zotlabs\Web\Controller { $phpath = trim($_POST['phpath']); $adminmail = trim($_POST['adminmail']); $siteurl = trim($_POST['siteurl']); - $advanced = ((intval($_POST['advanced'])) ? 1 : 0); + $server_role = trim($_POST['server_role']); + if(! $server_role) + $server_role = 'standard'; // $siteurl should not have a trailing slash @@ -84,24 +87,26 @@ class Setup extends \Zotlabs\Web\Controller { $db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true); if(! \DBA::$dba->connected) { - echo 'Database Connect failed: ' . DBA::$dba->error; + echo 'Database Connect failed: ' . \DBA::$dba->error; killme(); } return; // implied break; case 4: $urlpath = \App::get_path(); - $dbhost = notags(trim($_POST['dbhost'])); - $dbport = intval(notags(trim($_POST['dbport']))); - $dbuser = notags(trim($_POST['dbuser'])); - $dbpass = notags(trim($_POST['dbpass'])); - $dbdata = notags(trim($_POST['dbdata'])); - $dbtype = intval(notags(trim($_POST['dbtype']))); - $phpath = notags(trim($_POST['phpath'])); - $timezone = notags(trim($_POST['timezone'])); - $adminmail = notags(trim($_POST['adminmail'])); - $siteurl = notags(trim($_POST['siteurl'])); - $advanced = ((intval($_POST['advanced'])) ? 'pro' : 'basic'); + $dbhost = trim($_POST['dbhost']); + $dbport = intval(trim($_POST['dbport'])); + $dbuser = trim($_POST['dbuser']); + $dbpass = trim($_POST['dbpass']); + $dbdata = trim($_POST['dbdata']); + $dbtype = intval(trim($_POST['dbtype'])); + $phpath = trim($_POST['phpath']); + $timezone = trim($_POST['timezone']); + $adminmail = trim($_POST['adminmail']); + $siteurl = trim($_POST['siteurl']); + $server_role = trim($_POST['server_role']); + if(! $server_role) + $server_role = 'standard'; if($siteurl != z_root()) { $test = z_fetch_url($siteurl."/setup/testrewrite"); @@ -130,7 +135,7 @@ class Setup extends \Zotlabs\Web\Controller { '$dbpass' => $dbpass, '$dbdata' => $dbdata, '$dbtype' => $dbtype, - '$server_role' => $advanced, + '$server_role' => $server_role, '$timezone' => $timezone, '$siteurl' => $siteurl, '$site_id' => random_string(), @@ -274,15 +279,15 @@ class Setup extends \Zotlabs\Web\Controller { case 2: { // Database config - $dbhost = ((x($_POST,'dbhost')) ? notags(trim($_POST['dbhost'])) : '127.0.0.1'); - $dbuser = notags(trim($_POST['dbuser'])); - $dbport = intval(notags(trim($_POST['dbport']))); - $dbpass = notags(trim($_POST['dbpass'])); - $dbdata = notags(trim($_POST['dbdata'])); - $dbtype = intval(notags(trim($_POST['dbtype']))); - $phpath = notags(trim($_POST['phpath'])); - $adminmail = notags(trim($_POST['adminmail'])); - $siteurl = notags(trim($_POST['siteurl'])); + $dbhost = ((x($_POST,'dbhost')) ? trim($_POST['dbhost']) : '127.0.0.1'); + $dbuser = trim($_POST['dbuser']); + $dbport = intval(trim($_POST['dbport'])); + $dbpass = trim($_POST['dbpass']); + $dbdata = trim($_POST['dbdata']); + $dbtype = intval(trim($_POST['dbtype'])); + $phpath = trim($_POST['phpath']); + $adminmail = trim($_POST['adminmail']); + $siteurl = trim($_POST['siteurl']); $tpl = get_markup_template('install_db.tpl'); $o .= replace_macros($tpl, array( @@ -315,18 +320,24 @@ class Setup extends \Zotlabs\Web\Controller { }; break; case 3: { // Site settings require_once('include/datetime.php'); - $dbhost = ((x($_POST,'dbhost')) ? notags(trim($_POST['dbhost'])) : '127.0.0.1'); - $dbport = intval(notags(trim($_POST['dbuser']))); - $dbuser = notags(trim($_POST['dbuser'])); - $dbpass = notags(trim($_POST['dbpass'])); - $dbdata = notags(trim($_POST['dbdata'])); - $dbtype = intval(notags(trim($_POST['dbtype']))); - $phpath = notags(trim($_POST['phpath'])); + $dbhost = ((x($_POST,'dbhost')) ? trim($_POST['dbhost']) : '127.0.0.1'); + $dbport = intval(trim($_POST['dbuser'])); + $dbuser = trim($_POST['dbuser']); + $dbpass = trim($_POST['dbpass']); + $dbdata = trim($_POST['dbdata']); + $dbtype = intval(trim($_POST['dbtype'])); + $phpath = trim($_POST['phpath']); - $adminmail = notags(trim($_POST['adminmail'])); - $siteurl = notags(trim($_POST['siteurl'])); + $adminmail = trim($_POST['adminmail']); + $siteurl = trim($_POST['siteurl']); $timezone = ((x($_POST,'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles'); + $server_roles = [ + 'basic' => t('Basic/Minimal Social Networking'), + 'standard' => t('Standard Configuration (default)'), + 'pro' => t('Professional') + ]; + $tpl = get_markup_template('install_settings.tpl'); $o .= replace_macros($tpl, array( '$title' => $install_title, @@ -344,7 +355,8 @@ class Setup extends \Zotlabs\Web\Controller { '$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Your account email address must match this in order to use the web admin panel.')), '$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Please use SSL (https) URL if available.')), - '$advanced' => array('advanced', t('Enable $Projectname advanced features?'), 1, t('Some advanced features, while useful - may be best suited for technically proficient audiences')), + + '$server_role' => array('server_role', t("Server Configuration/Role"), 'standard','',$server_roles), '$timezone' => array('timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones()), diff --git a/Zotlabs/Module/Theme_info.php b/Zotlabs/Module/Theme_info.php new file mode 100644 index 000000000..e27ec9444 --- /dev/null +++ b/Zotlabs/Module/Theme_info.php @@ -0,0 +1,71 @@ +get_theme_config_file($theme)) != null){ + require_once($themeconfigfile); + if(class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { + $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; + $th_config = new $clsname(); + $schemas = $th_config->get_schemas(); + if($schemas) { + foreach($schemas as $k => $v) { + $schemalist[] = [ 'key' => $k, 'val' => $v ]; + } + } + $theme_config = $th_config->get(); + } + } + $info = get_theme_info($theme); + if($info) { + // unfortunately there will be no translation for this string + $desc = $info['description']; + $version = $info['version']; + $credits = $info['credits']; + } + else { + $desc = ''; + $version = ''; + $credits = ''; + } + + $ret = [ + 'theme' => $theme, + 'img' => get_theme_screenshot($theme), + 'desc' => $desc, + 'version' => $version, + 'credits' => $credits, + 'schemas' => $schemalist, + 'config' => $theme_config + ]; + json_return_and_die($ret); + + } + + + function get_theme_config_file($theme){ + + $base_theme = \App::$theme_info['extends']; + + if (file_exists("view/theme/$theme/php/config.php")){ + return "view/theme/$theme/php/config.php"; + } + if (file_exists("view/theme/$base_theme/php/config.php")){ + return "view/theme/$base_theme/php/config.php"; + } + return null; + } + + +} \ No newline at end of file diff --git a/Zotlabs/Module/Update_channel.php b/Zotlabs/Module/Update_channel.php index b1b2d5103..46ad19805 100644 --- a/Zotlabs/Module/Update_channel.php +++ b/Zotlabs/Module/Update_channel.php @@ -67,4 +67,4 @@ function get() { killme(); } -} \ No newline at end of file +} diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php index 0a48d43c6..0da699c73 100644 --- a/Zotlabs/Module/Webpages.php +++ b/Zotlabs/Module/Webpages.php @@ -41,7 +41,6 @@ class Webpages extends \Zotlabs\Web\Controller { $uid = local_channel(); $owner = 0; - $channel = null; $observer = \App::get_observer(); $channel = \App::get_channel(); @@ -62,6 +61,28 @@ class Webpages extends \Zotlabs\Web\Controller { case 'importselected': $_SESSION['action'] = null; break; + case 'export_select_list': + $_SESSION['action'] = null; + if(!$uid) { + $_SESSION['export'] = null; + break; + } + require_once('include/import.php'); + + $pages = get_webpage_elements($channel, 'pages'); + $layouts = get_webpage_elements($channel, 'layouts'); + $blocks = get_webpage_elements($channel, 'blocks'); + $o .= replace_macros(get_markup_template('webpage_export_list.tpl'), array( + '$title' => t('Export Webpage Elements'), + '$exportbtn' => t('Export selected'), + '$action' => $_SESSION['export'], // value should be 'zipfile' or 'cloud' + '$pages' => $pages['pages'], + '$layouts' => $layouts['layouts'], + '$blocks' => $blocks['blocks'], + )); + $_SESSION['export'] = null; + return $o; + default : $_SESSION['action'] = null; break; @@ -115,9 +136,11 @@ class Webpages extends \Zotlabs\Web\Controller { 'deny_gid' => $channel['channel_deny_gid'] ); } - else - $channel_acl = array(); + else { + $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; + } + $is_owner = ($uid && $uid == $owner); $o = profile_tabs($a, $is_owner, \App::$profile['channel_address']); @@ -127,7 +150,7 @@ class Webpages extends \Zotlabs\Web\Controller { 'nickname' => \App::$profile['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' => (($is_owner) ? $channel_acl : ''), + 'permissions' => $channel_acl, 'showacl' => (($is_owner) ? true : false), 'visitor' => true, 'hide_location' => true, @@ -233,7 +256,6 @@ class Webpages extends \Zotlabs\Web\Controller { } function post() { - $action = $_REQUEST['action']; if( $action ){ switch ($action) { @@ -313,7 +335,8 @@ class Webpages extends \Zotlabs\Web\Controller { // If the website elements were imported from a zip file, delete the temporary decompressed files if ($cloud === false && $website && $elements) { - rrmdir($website); // Delete the temporary decompressed files + $_SESSION['tempimportpath'] = $website; + //rrmdir($website); // Delete the temporary decompressed files } break; @@ -381,16 +404,299 @@ class Webpages extends \Zotlabs\Web\Controller { if(!(empty($_SESSION['import_pages']) && empty($_SESSION['import_blocks']) && empty($_SESSION['import_layouts']))) { info( t('Import complete.') . EOL); } + if(isset($_SESSION['tempimportpath'])) { + rrmdir($_SESSION['tempimportpath']); // Delete the temporary decompressed files + unset($_SESSION['tempimportpath']); + } + break; + + case 'exportzipfile': + + if(isset($_POST['w_download'])) { + $_SESSION['action'] = 'export_select_list'; + $_SESSION['export'] = 'zipfile'; + if(isset($_POST['zipfilename']) && $_POST['zipfilename'] !== '') { + $filename = filter_var($_POST['zipfilename'], FILTER_SANITIZE_ENCODED); + } else { + $filename = 'website.zip'; + } + $_SESSION['zipfilename'] = $filename; + + } + + break; + + case 'exportcloud': + if(isset($_POST['exportcloudpath']) && $_POST['exportcloudpath'] !== '') { + $_SESSION['action'] = 'export_select_list'; + $_SESSION['export'] = 'cloud'; + $_SESSION['exportcloudpath'] = filter_var($_POST['exportcloudpath'], FILTER_SANITIZE_ENCODED); + } + + break; + + case 'cloud': + case 'zipfile': + + $channel = \App::get_channel(); + + $tmp_folder_name = random_string(10); + $zip_folder_name = random_string(10); + $zip_filename = $_SESSION['zipfilename']; + $tmp_folderpath = '/tmp/' . $tmp_folder_name; + $zip_folderpath = '/tmp/' . $zip_folder_name; + if (!mkdir($zip_folderpath, 0770, false)) { + logger('Error creating zip file export folder: ' . $zip_folderpath, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating zip file export folder')); + } + $zip_filepath = '/tmp/' . $zip_folder_name . '/' . $zip_filename; + + $checkedblocks = $_POST['block']; + $blocks = []; + if (!empty($checkedblocks)) { + foreach ($checkedblocks as $mid) { + $b = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + left join item on item.id = iconfig.iid + where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' order by iconfig.v asc limit 1", + dbesc($mid), + intval($channel['channel_id']) + ); + if($b) { + $b = $b[0]; + $blockinfo = array( + 'body' => $b['body'], + 'mimetype' => $b['mimetype'], + 'title' => $b['title'], + 'name' => $b['v'], + 'json' => array( + 'title' => $b['title'], + 'name' => $b['v'], + 'mimetype' => $b['mimetype'], + ) + ); + switch ($blockinfo['mimetype']) { + case 'text/html': + $block_ext = 'html'; + break; + case 'text/bbcode': + $block_ext = 'bbcode'; + break; + case 'text/markdown': + $block_ext = 'md'; + break; + case 'application/x-pdl': + $block_ext = 'pdl'; + break; + case 'application/x-php': + $block_ext = 'php'; + break; + default: + $block_ext = 'bbcode'; + break; + } + $block_filename = $blockinfo['name'] . '.' . $block_ext; + $tmp_blockfolder = $tmp_folderpath . '/blocks/' . $blockinfo['name']; + $block_filepath = $tmp_blockfolder . '/' . $block_filename; + $blockinfo['json']['contentfile'] = $block_filename; + $block_jsonpath = $tmp_blockfolder . '/block.json'; + if (!is_dir($tmp_blockfolder) && !mkdir($tmp_blockfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_blockfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($block_filepath, $blockinfo['body']); + file_put_contents($block_jsonpath, json_encode($blockinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + + $checkedlayouts = $_POST['layout']; + $layouts = []; + if (!empty($checkedlayouts)) { + foreach ($checkedlayouts as $mid) { + $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + left join item on item.id = iconfig.iid + where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", + dbesc($mid), + intval($channel['channel_id']) + ); + if($l) { + $l = $l[0]; + $layoutinfo = array( + 'body' => $l['body'], + 'mimetype' => $l['mimetype'], + 'description' => $l['title'], + 'name' => $l['v'], + 'json' => array( + 'description' => $l['title'], + 'name' => $l['v'], + 'mimetype' => $l['mimetype'], + ) + ); + switch ($layoutinfo['mimetype']) { + case 'text/bbcode': + default: + $layout_ext = 'bbcode'; + break; + } + $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; + $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; + $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; + $layoutinfo['json']['contentfile'] = $layout_filename; + $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; + if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($layout_filepath, $layoutinfo['body']); + file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + + $checkedpages = $_POST['page']; + $pages = []; + if (!empty($checkedpages)) { + foreach ($checkedpages as $mid) { + + $p = q("select * from iconfig left join item on iconfig.iid = item.id + where item.uid = %d and item.mid = '%s' and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d", + intval($channel['channel_id']), + dbesc($mid), + intval(ITEM_TYPE_WEBPAGE) + ); + + if($p) { + foreach ($p as $pp) { + // Get the associated layout + $layoutinfo = array(); + if($pp['layout_mid']) { + $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + left join item on item.id = iconfig.iid + where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", + dbesc($pp['layout_mid']), + intval($channel['channel_id']) + ); + if($l) { + $l = $l[0]; + $layoutinfo = array( + 'body' => $l['body'], + 'mimetype' => $l['mimetype'], + 'description' => $l['title'], + 'name' => $l['v'], + 'json' => array( + 'description' => $l['title'], + 'name' => $l['v'], + ) + ); + switch ($layoutinfo['mimetype']) { + case 'text/bbcode': + default: + $layout_ext = 'bbcode'; + break; + } + $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; + $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; + $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; + $layoutinfo['json']['contentfile'] = $layout_filename; + $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; + if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($layout_filepath, $layoutinfo['body']); + file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + switch ($pp['mimetype']) { + case 'text/html': + $page_ext = 'html'; + break; + case 'text/bbcode': + $page_ext = 'bbcode'; + break; + case 'text/markdown': + $page_ext = 'md'; + break; + case 'application/x-pdl': + $page_ext = 'pdl'; + break; + case 'application/x-php': + $page_ext = 'php'; + break; + default: + break; + } + $pageinfo = array( + 'title' => $pp['title'], + 'body' => $pp['body'], + 'pagelink' => $pp['v'], + 'mimetype' => $pp['mimetype'], + 'contentfile' => $pp['v'] . '.' . $page_ext, + 'layout' => ((x($layoutinfo,'name')) ? $layoutinfo['name'] : ''), + 'json' => array( + 'title' => $pp['title'], + 'pagelink' => $pp['v'], + 'mimetype' => $pp['mimetype'], + 'layout' => ((x($layoutinfo,'name')) ? $layoutinfo['name'] : ''), + ) + ); + $page_filename = $pageinfo['pagelink'] . '.' . $page_ext; + $tmp_pagefolder = $tmp_folderpath . '/pages/' . $pageinfo['pagelink']; + $page_filepath = $tmp_pagefolder . '/' . $page_filename; + $page_jsonpath = $tmp_pagefolder . '/page.json'; + $pageinfo['json']['contentfile'] = $page_filename; + if (!is_dir($tmp_pagefolder) && !mkdir($tmp_pagefolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_pagefolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($page_filepath, $pageinfo['body']); + file_put_contents($page_jsonpath, json_encode($pageinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + } + if($action === 'zipfile') { + // Generate the zip file + \Zotlabs\Lib\ExtendedZip::zipTree($tmp_folderpath, $zip_filepath, \ZipArchive::CREATE); + // Output the file for download + header('Content-disposition: attachment; filename="' . $zip_filename . '"'); + header("Content-Type: application/zip"); + $success = readfile($zip_filepath); + } elseif ($action === 'cloud') { // Only zipfile or cloud should be possible values for $action here + if(isset($_SESSION['exportcloudpath'])) { + require_once('include/attach.php'); + $cloudpath = urldecode($_SESSION['exportcloudpath']); + $channel = \App::get_channel(); + $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); + if(!$dirpath) { + $x = attach_mkdirp($channel, $channel['channel_hash'], array('pathname' => $cloudpath)); + $folder_hash = (($x['success']) ? $x['data']['hash'] : ''); + + if (!$x['success']) { + logger('Failed to create cloud file folder', LOGGER_NORMAL); + } + $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); + if (!is_dir($dirpath)) { + logger('Failed to create cloud file folder', LOGGER_NORMAL); + } + } + + $success = copy_folder_to_cloudfiles($channel, $channel['channel_hash'], $tmp_folderpath, $cloudpath); + } + } + if(!$success) { + logger('Error exporting webpage elements', LOGGER_NORMAL); + } + + rrmdir($zip_folderpath); rrmdir($tmp_folderpath); // delete temporary files + break; - default : break; } + } - - - } } diff --git a/Zotlabs/Module/Xrd.php b/Zotlabs/Module/Xrd.php index d71fae695..3ed19962b 100644 --- a/Zotlabs/Module/Xrd.php +++ b/Zotlabs/Module/Xrd.php @@ -43,7 +43,7 @@ class Xrd extends \Zotlabs\Web\Controller { header("Content-type: application/xrd+xml"); - $aliases = array('acct:' . $r[0]['channel_address'] . '@' . \App::get_hostname(), z_root() . '/channel/' . $r[0]['channel_address'], z_root() . '/~' . $r[0]['channel_address']); + $aliases = array('acct:' . channel_reddress($r[0]), z_root() . '/channel/' . $r[0]['channel_address'], z_root() . '/~' . $r[0]['channel_address']); for($x = 0; $x < count($aliases); $x ++) { if($aliases[$x] === $resource) diff --git a/Zotlabs/Render/Comanche.php b/Zotlabs/Render/Comanche.php index 820897ee9..562a9f791 100644 --- a/Zotlabs/Render/Comanche.php +++ b/Zotlabs/Render/Comanche.php @@ -99,18 +99,72 @@ class Comanche { } } - + function get_condition_var($v) { + if($v) { + $x = explode('.',$v); + if($x[0] == 'config') + return get_config($x[1],$x[2]); + elseif($x[0] === 'observer') { + if(count($x) > 1) { + $y = \App::get_observer(); + if(! $y) + return false; + if($x[1] == 'address') + return $y['xchan_addr']; + elseif($x[1] == 'name') + return $y['xchan_name']; + return false; + } + return get_observer_hash(); + } + else + return false; + } + return false; + } function test_condition($s) { - - // This is extensible. The first version of variable testing supports tests of the form + // 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') is the string 'baz'; + // [if $config.system.foo != baz] which will check if get_config('system','foo') is not the string 'baz'; + // You may check numeric entries, but these checks are evaluated as strings. + // [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("/[\$]config[\.](.*?)/",$s,$matches)) { - $x = explode('.',$s); - if(get_config($x[1],$x[2])) + 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(is_array($x) && in_array(trim($matches[2]),$x)) + return true; + return false; + } + + if(preg_match('/[\$](.*?)\s\{\*\}\s(.*?)$/',$s,$matches)) { + $x = $this->get_condition_var($matches[1]); + if(is_array($x) && array_key_exists(trim($matches[2]),$x)) + return true; + return false; + } + + if(preg_match('/[\$](.*?)$/',$s,$matches)) { + $x = $this->get_condition_var($matches[1]); + if($x) + return true; + return false; } return false; @@ -231,7 +285,7 @@ class Comanche { $path = 'library/bootstrap/js/bootstrap.min.js'; break; case 'foundation': - $path = 'library/foundation/js/foundation.min.js'; + $path = 'library/foundation/js/foundation.js'; $init = "\r\n" . ''; break; } @@ -403,4 +457,4 @@ class Comanche { return; } -} \ No newline at end of file +} diff --git a/Zotlabs/Render/SmartyTemplate.php b/Zotlabs/Render/SmartyTemplate.php index 532d6e42f..ffe58e286 100755 --- a/Zotlabs/Render/SmartyTemplate.php +++ b/Zotlabs/Render/SmartyTemplate.php @@ -15,7 +15,10 @@ class SmartyTemplate implements TemplateEngine { ? \App::$config['system']['smarty3_folder'] : ''); if (!$basecompiledir) $basecompiledir = str_replace('Zotlabs','',dirname(__dir__)) . "/" . TEMPLATE_BUILD_PATH; if (!is_dir($basecompiledir)) { - echo "ERROR: folder $basecompiledir does not exist."; killme(); + @os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true); + if (!is_dir($basecompiledir)) { + echo "ERROR: folder $basecompiledir does not exist."; killme(); + } } if(!is_writable($basecompiledir)){ echo "ERROR: folder $basecompiledir must be writable by webserver."; killme(); @@ -27,6 +30,13 @@ class SmartyTemplate implements TemplateEngine { public function replace_macros($s, $r) { $template = ''; + + // these are available for use in all templates + + $r['$z_baseurl'] = z_root(); + $r['$z_server_role'] = \Zotlabs\Lib\System::get_server_role(); + $r['$z_techlevel'] = get_account_techlevel(); + if(gettype($s) === 'string') { $template = $s; $s = new SmartyInterface(); diff --git a/Zotlabs/Render/Theme.php b/Zotlabs/Render/Theme.php index a8b86f371..9f9009d72 100644 --- a/Zotlabs/Render/Theme.php +++ b/Zotlabs/Render/Theme.php @@ -66,6 +66,8 @@ class Theme { $chosen_theme = $page_theme; } } + if(array_key_exists('theme_preview',$_GET)) + $chosen_theme = $_GET['theme_preview']; // Allow theme selection of the form 'theme_name:schema_name' @@ -112,7 +114,7 @@ class Theme { $theme = self::current(); $t = $theme[0]; - $s = ((count($theme) > 1) ? $t[1] : ''); + $s = ((count($theme) > 1) ? $theme[1] : ''); $opts = ''; $opts = ((\App::$profile_uid) ? '?f=&puid=' . \App::$profile_uid : ''); @@ -127,5 +129,12 @@ class Theme { return('view/theme/' . $t . '/css/style.css'); } + + 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 948f7c733..4a7e49e86 100644 --- a/Zotlabs/Storage/Browser.php +++ b/Zotlabs/Storage/Browser.php @@ -99,10 +99,10 @@ class Browser extends DAV\Browser\Plugin { $parent = $this->server->tree->getNodeForPath($path); $parentpath = array(); - // only show parent if not leaving /cloud/; TODO how to improve this? + // only show parent if not leaving /cloud/; TODO how to improve this? if ($path && $path != "cloud") { - list($parentUri) = \Sabre\HTTP\URLUtil::splitPath($path); - $fullPath = \Sabre\HTTP\URLUtil::encodePath($this->server->getBaseUri() . $parentUri); + list($parentUri) = \Sabre\Uri\split($path); + $fullPath = \Sabre\HTTP\encodePath($this->server->getBaseUri() . $parentUri); $parentpath['icon'] = $this->enableAssets ? '' : ''; $parentpath['path'] = $fullPath; @@ -114,9 +114,9 @@ class Browser extends DAV\Browser\Plugin { $type = null; // This is the current directory, we can skip it - if (rtrim($file['href'],'/') == $path) continue; + if (rtrim($file['href'], '/') == $path) continue; - list(, $name) = \Sabre\HTTP\URLUtil::splitPath($file['href']); + list(, $name) = \Sabre\Uri\split($file['href']); if (isset($file[200]['{DAV:}resourcetype'])) { $type = $file[200]['{DAV:}resourcetype']->getValue(); @@ -166,8 +166,7 @@ class Browser extends DAV\Browser\Plugin { $size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : ''; $lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : ''); - $fullPath = \Sabre\HTTP\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/')); - + $fullPath = \Sabre\HTTP\encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/')); $displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name; @@ -248,8 +247,8 @@ class Browser extends DAV\Browser\Plugin { $current_theme = \Zotlabs\Render\Theme::current(); - $theme_info_file = "view/theme/" . $current_theme[0] . "/php/theme.php"; - if (file_exists($theme_info_file)){ + $theme_info_file = 'view/theme/' . $current_theme[0] . '/php/theme.php'; + if (file_exists($theme_info_file)) { require_once($theme_info_file); if (function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) { $func = str_replace('-', '_', $current_theme[0]) . '_init'; @@ -279,15 +278,14 @@ class Browser extends DAV\Browser\Plugin { $aclselect = null; $lockstate = ''; - if($this->auth->owner_id) { + if ($this->auth->owner_id) { $channel = channelx_by_n($this->auth->owner_id); - if($channel) { + if ($channel) { $acl = new \Zotlabs\Access\AccessList($channel); $channel_acl = $acl->get(); $lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); $aclselect = ((local_channel() == $this->auth->owner_id) ? populate_acl($channel_acl,false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : ''); - } } @@ -316,7 +314,7 @@ class Browser extends DAV\Browser\Plugin { $quota['desc'] = $quotaDesc; $quota['warning'] = ((($limit) && ((round($used / $limit, 1) * 100) >= 90)) ? t('WARNING:') : ''); // 10485760 bytes = 100MB - $path = trim(str_replace('cloud/' . $this->auth->owner_nick, '', $path),'/'); + $path = trim(str_replace('cloud/' . $this->auth->owner_nick, '', $path), '/'); $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array( '$folder_header' => t('Create new folder'), @@ -354,7 +352,7 @@ class Browser extends DAV\Browser\Plugin { * * Given the owner, the parent folder and and attach name get the attachment * hash. - * + * * @param int $owner * The owner_id * @param string $hash @@ -363,14 +361,13 @@ class Browser extends DAV\Browser\Plugin { * The name of the attachment * @return string */ - protected function findAttachHash($owner, $parentHash, $attachName) { $r = q("SELECT hash FROM attach WHERE uid = %d AND folder = '%s' AND filename = '%s' ORDER BY edited DESC LIMIT 1", intval($owner), dbesc($parentHash), dbesc($attachName) ); - $hash = ""; + $hash = ''; if ($r) { foreach ($r as $rr) { $hash = $rr['hash']; diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php index 15e06e28f..de4d90da4 100644 --- a/Zotlabs/Storage/Directory.php +++ b/Zotlabs/Storage/Directory.php @@ -3,7 +3,6 @@ namespace Zotlabs\Storage; use Sabre\DAV; -use Sabre\HTTP; /** * @brief RedDirectory class. @@ -54,7 +53,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { logger('directory ' . $ext_path, LOGGER_DATA); $this->ext_path = $ext_path; // remove "/cloud" from the beginning of the path - $modulename = \App::$module; + $modulename = \App::$module; $this->red_path = ((strpos($ext_path, '/' . $modulename) === 0) ? substr($ext_path, strlen($modulename) + 1) : $ext_path); if (! $this->red_path) { $this->red_path = '/'; @@ -99,7 +98,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { /** * @brief Returns a child by name. * - * * @throw \Sabre\DAV\Exception\Forbidden * @throw \Sabre\DAV\Exception\NotFound * @param string $name @@ -160,7 +158,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { throw new DAV\Exception\Forbidden('Permission denied.'); } - list($parent_path, ) = HTTP\URLUtil::splitPath($this->red_path); + list($parent_path, ) = \Sabre\Uri\split($this->red_path); $new_path = $parent_path . '/' . $name; $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d", @@ -169,12 +167,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { intval($this->auth->owner_id) ); - $ch = channelx_by_n($this->auth->owner_id); - if($ch) { - $sync = attach_export_data($ch,$this->folder_hash); - if($sync) - build_sync_packet($ch['channel_id'],array('file' => array($sync))); + if ($ch) { + $sync = attach_export_data($ch, $this->folder_hash); + if ($sync) + build_sync_packet($ch['channel_id'], array('file' => array($sync))); } $this->red_path = $new_path; @@ -207,7 +204,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { throw new DAV\Exception\Forbidden('Permission denied.'); } - $mimetype = z_mime_content_type($name); $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", @@ -226,22 +222,22 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $direct = null; - if($this->folder_hash) { + if ($this->folder_hash) { $r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", dbesc($this->folder_hash), intval($c[0]['channel_id']) ); - if($r) + if ($r) $direct = $r[0]; } - if(($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) { + if (($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) { $allow_cid = $direct['allow_cid']; $allow_gid = $direct['allow_gid']; $deny_cid = $direct['deny_cid']; $deny_gid = $direct['deny_gid']; } - else { + else { $allow_cid = $c[0]['channel_allow_cid']; $allow_gid = $c[0]['channel_allow_gid']; $deny_cid = $c[0]['channel_deny_cid']; @@ -270,8 +266,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { dbesc($deny_gid) ); - - // returns the number of bytes that were written to the file, or FALSE on failure $size = file_put_contents($f, $data); // delete attach entry if file_put_contents() failed @@ -284,16 +278,13 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { // returns now $edited = datetime_convert(); - - $is_photo = 0; $x = @getimagesize($f); - logger('getimagesize: ' . print_r($x,true), LOGGER_DATA); - if(($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) { + logger('getimagesize: ' . print_r($x,true), LOGGER_DATA); + if (($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) { $is_photo = 1; } - // updates entry with filesize and timestamp $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($size), @@ -329,28 +320,26 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { } } - if($is_photo) { + if ($is_photo) { $album = ''; - if($this->folder_hash) { + if ($this->folder_hash) { $f1 = q("select filename from attach WHERE hash = '%s' AND uid = %d", dbesc($this->folder_hash), intval($c[0]['channel_id']) ); - if($f1) + if ($f1) $album = $f1[0]['filename']; } require_once('include/photos.php'); $args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct); - $p = photo_upload($c[0],\App::get_observer(),$args); + $p = photo_upload($c[0], \App::get_observer(), $args); } - $sync = attach_export_data($c[0],$hash); - - if($sync) - build_sync_packet($c[0]['channel_id'],array('file' => array($sync))); - + $sync = attach_export_data($c[0], $hash); + if ($sync) + build_sync_packet($c[0]['channel_id'], array('file' => array($sync))); } /** @@ -379,10 +368,10 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG); if($sync) { - build_sync_packet($r[0]['channel_id'],array('file' => array($sync))); + build_sync_packet($r[0]['channel_id'], array('file' => array($sync))); } } - else { + else { logger('error ' . print_r($result, true), LOGGER_DEBUG); } } @@ -391,7 +380,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { /** * @brief delete directory */ - public function delete() { logger('delete file ' . basename($this->red_path), LOGGER_DEBUG); @@ -408,13 +396,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { attach_delete($this->auth->owner_id, $this->folder_hash); $ch = channelx_by_n($this->auth->owner_id); - if($ch) { - $sync = attach_export_data($ch,$this->folder_hash,true); - if($sync) - build_sync_packet($ch['channel_id'],array('file' => array($sync))); + if ($ch) { + $sync = attach_export_data($ch, $this->folder_hash, true); + if ($sync) + build_sync_packet($ch['channel_id'], array('file' => array($sync))); } - - } @@ -573,14 +559,12 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { /** * @brief Array with all Directory and File DAV\Node items for the given path. * - * * @param string $file path to a directory * @param \Zotlabs\Storage\BasicAuth &$auth * @returns null|array \Sabre\DAV\INode[] * @throw \Sabre\DAV\Exception\Forbidden * @throw \Sabre\DAV\Exception\NotFound */ - function CollectionData($file, &$auth) { $ret = array(); @@ -649,7 +633,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { if ($errors) { if ($permission_error) { throw new DAV\Exception\Forbidden('Permission denied.'); - } + } else { throw new DAV\Exception\NotFound('A component of the request file path could not be found.'); } @@ -663,7 +647,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { $prefix = 'DISTINCT ON (filename)'; $suffix = 'ORDER BY filename'; - } + } else { $prefix = ''; $suffix = 'GROUP BY filename'; @@ -677,7 +661,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { //logger('filename: ' . $rr['filename'], LOGGER_DEBUG); if (intval($rr['is_dir'])) { $ret[] = new Directory($path . '/' . $rr['filename'], $auth); - } + } else { $ret[] = new File($path . '/' . $rr['filename'], $rr, $auth); } @@ -697,11 +681,10 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @param BasicAuth &$auth * @return array Directory[] */ - function ChannelList(&$auth) { $ret = array(); - $r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0 + $r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0 AND channel_system = 0 AND NOT (channel_pageflags & %d)>0", intval(PAGE_HIDDEN) ); @@ -720,8 +703,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { /** - * @brief - * + * @brief * * @param string $file * path to file or directory @@ -730,7 +712,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @return File|Directory|boolean|null * @throw \Sabre\DAV\Exception\Forbidden */ - function FileData($file, &$auth, $test = false) { logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA); @@ -739,12 +720,11 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $file = substr($file, 6); } else { - $x = strpos($file,'/dav'); + $x = strpos($file, '/dav'); if($x === 0) - $file = substr($file,4); + $file = substr($file, 4); } - if ((! $file) || ($file === '/')) { return new Directory('/', $auth); } @@ -780,7 +760,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $errors = false; - for ($x = 1; $x < count($path_arr); $x++) { + for ($x = 1; $x < count($path_arr); $x++) { $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms", dbesc($folder), dbesc($path_arr[$x]), @@ -792,7 +772,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $path = $path . '/' . $r[0]['filename']; } if (! $r) { - $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach + $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1", dbesc($folder), dbesc(basename($file)), @@ -801,7 +781,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { } if (! $r) { $errors = true; - $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach + $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1", dbesc($folder), dbesc(basename($file)), diff --git a/Zotlabs/Web/SubModule.php b/Zotlabs/Web/SubModule.php new file mode 100644 index 000000000..5f49b9292 --- /dev/null +++ b/Zotlabs/Web/SubModule.php @@ -0,0 +1,43 @@ +controller = new $modname(); + } + } + + function call($method) { + if(! $this->controller) + return false; + if(method_exists($this->controller,$method)) + return $this->controller->$method(); + return false; + } + +} + diff --git a/boot.php b/boot.php index 9f359d071..8160f8804 100755 --- a/boot.php +++ b/boot.php @@ -44,10 +44,10 @@ require_once('include/account.php'); define ( 'PLATFORM_NAME', 'hubzilla' ); -define ( 'STD_VERSION', '1.12.1' ); +define ( 'STD_VERSION', '1.14RC1' ); define ( 'ZOT_REVISION', '1.1' ); -define ( 'DB_UPDATE_VERSION', 1181 ); +define ( 'DB_UPDATE_VERSION', 1183 ); /** @@ -149,15 +149,6 @@ define ( 'MAX_IMAGE_LENGTH', -1 ); define ( 'DEFAULT_DB_ENGINE', 'MyISAM' ); -/** - * SSL redirection policies - */ - -define ( 'SSL_POLICY_NONE', 0 ); -define ( 'SSL_POLICY_FULL', 1 ); -define ( 'SSL_POLICY_SELFSIGN', 2 ); // NOT supported in Red - - /** * log levels */ @@ -168,6 +159,15 @@ define ( 'LOGGER_DEBUG', 2 ); define ( 'LOGGER_DATA', 3 ); define ( 'LOGGER_ALL', 4 ); + +/** + * Server roles + */ + +define ( 'SERVER_ROLE_BASIC', 0x0001 ); +define ( 'SERVER_ROLE_STANDARD', 0x0002 ); +define ( 'SERVER_ROLE_PRO', 0x0004 ); + /** * registration policies */ @@ -612,11 +612,11 @@ function sys_boot() { if(UNO) App::$config['system']['server_role'] = 'basic'; else - App::$config['system']['server_role'] = 'pro'; + App::$config['system']['server_role'] = 'standard'; } if(! (array_key_exists('server_role',App::$config['system']) && App::$config['system']['server_role'])) - App::$config['system']['server_role'] = 'pro'; + App::$config['system']['server_role'] = 'standard'; App::$timezone = ((App::$config['system']['timezone']) ? App::$config['system']['timezone'] : 'UTC'); date_default_timezone_set(App::$timezone); @@ -697,6 +697,7 @@ function startup() { class ZotlabsAutoloader { static public function loader($className) { + $debug = false; $filename = str_replace('\\', '/', $className) . ".php"; if(file_exists($filename)) { include($filename); @@ -760,7 +761,7 @@ class miniApp { class App { public static $install = false; // true if we are installing the software - + public static $role = 0; // server role (constant, not the string) public static $account = null; // account record of the logged-in account public static $channel = null; // channel record of the current channel of the logged-in account public static $observer = null; // xchan record of the page observer @@ -1044,6 +1045,31 @@ class App { } } + public static function get_role() { + if(! self::$role) + return self::set_role(); + return self::$role; + } + + public static function set_role() { + $role_str = \Zotlabs\Lib\System::get_server_role(); + switch($role_str) { + case 'basic': + $role = SERVER_ROLE_BASIC; + break; + case 'pro': + $role = SERVER_ROLE_PRO; + break; + case 'standard': + default: + $role = SERVER_ROLE_STANDARD; + break; + } + self::$role = $role; + return $role; + } + + public static function get_scheme() { return self::$scheme; } @@ -1583,13 +1609,13 @@ function fix_system_urls($oldurl, $newurl) { ); if($r) { - foreach($r as $rr) { - $channel_address = substr($rr['hubloc_addr'],0,strpos($rr['hubloc_addr'],'@')); + foreach($r as $rv) { + $channel_address = substr($rv['hubloc_addr'],0,strpos($rv['hubloc_addr'],'@')); // get the associated channel. If we don't have a local channel, do nothing for this entry. $c = q("select * from channel where channel_hash = '%s' limit 1", - dbesc($rr['hubloc_hash']) + dbesc($rv['hubloc_hash']) ); if(! $c) continue; @@ -1611,19 +1637,19 @@ function fix_system_urls($oldurl, $newurl) { // The xchan_url might point to another nomadic identity clone - $replace_xchan_url = ((strpos($rr['xchan_url'],$oldurl) !== false) ? true : false); + $replace_xchan_url = ((strpos($rv['xchan_url'],$oldurl) !== false) ? true : false); $x = q("update xchan set xchan_addr = '%s', xchan_url = '%s', xchan_connurl = '%s', xchan_follow = '%s', xchan_connpage = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'", dbesc($channel_address . '@' . $rhs), - dbesc(($replace_xchan_url) ? str_replace($oldurl,$newurl,$rr['xchan_url']) : $rr['xchan_url']), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_connurl'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_follow'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_connpage'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_l'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_m'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_s'])), + dbesc(($replace_xchan_url) ? str_replace($oldurl,$newurl,$rv['xchan_url']) : $rv['xchan_url']), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_connurl'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_follow'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_connpage'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_l'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_m'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_s'])), dbesc(datetime_convert()), - dbesc($rr['xchan_hash']) + dbesc($rv['xchan_hash']) ); $y = q("update hubloc set hubloc_addr = '%s', hubloc_url = '%s', hubloc_url_sig = '%s', hubloc_host = '%s', hubloc_callback = '%s' where hubloc_hash = '%s' and hubloc_url = '%s'", @@ -1632,13 +1658,13 @@ function fix_system_urls($oldurl, $newurl) { dbesc(base64url_encode(rsa_sign($newurl,$c[0]['channel_prvkey']))), dbesc($newhost), dbesc($newurl . '/post'), - dbesc($rr['xchan_hash']), + dbesc($rv['xchan_hash']), dbesc($oldurl) ); $z = q("update profile set photo = '%s', thumb = '%s' where uid = %d", - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_l'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_m'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_l'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_m'])), intval($c[0]['channel_id']) ); @@ -1666,12 +1692,12 @@ function fix_system_urls($oldurl, $newurl) { ); if($r) { - foreach($r as $rr) { + foreach($r as $rv) { $x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'", - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_l'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_m'])), - dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_s'])), - dbesc($rr['xchan_hash']) + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_l'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_m'])), + dbesc(str_replace($oldurl,$newurl,$rv['xchan_photo_s'])), + dbesc($rv['xchan_hash']) ); } } @@ -2029,8 +2055,8 @@ function load_contact_links($uid) { intval($uid) ); if($r) { - foreach($r as $rr){ - $ret[$rr['xchan_hash']] = $rr; + foreach($r as $rv){ + $ret[$rv['xchan_hash']] = $rv; } } else @@ -2211,6 +2237,9 @@ function construct_page(&$a) { $current_theme = Zotlabs\Render\Theme::current(); + // logger('current_theme: ' . print_r($current_theme,true)); + // Zotlabs\Render\Theme::debug(); + if (($p = theme_include($current_theme[0] . '.js')) != '') head_add_js($p); diff --git a/doc/Developers.md b/doc/Developers.md index b19b4fc2f..ef02c8327 100644 --- a/doc/Developers.md +++ b/doc/Developers.md @@ -18,7 +18,7 @@ to notify us to merge your work. **Translations** -Our translations are managed through Transifex. If you wish to help out translating the $Projectname to another language, sign up on transifex.com, visit [https://www.transifex.com/projects/p/red-matrix/](https://www.transifex.com/projects/p/red-matrix/) and request to join one of the existing language teams or create a new one. Notify one of the core developers when you have a translation update which requires merging, or ask about merging it yourself if you're comfortable with git and PHP. We have a string file called 'messages.po' which is gettext compliant and a handful of email templates, and from there we automatically generate the application's language files. +Our translations are managed through Transifex. If you wish to help out translating $Projectname to another language, sign up on transifex.com, visit [https://www.transifex.com/projects/p/red-matrix/](https://www.transifex.com/projects/p/red-matrix/) and request to join one of the existing language teams or create a new one. Notify one of the core developers when you have a translation update which requires merging, or ask about merging it yourself if you're comfortable with git and PHP. We have a string file called 'messages.po' which is gettext compliant and a handful of email templates, and from there we automatically generate the application's language files. [Translations - More Info](help/Translations) diff --git a/doc/Features.md b/doc/Features.md index 3c5105582..a43fd73fa 100644 --- a/doc/Features.md +++ b/doc/Features.md @@ -1,7 +1,7 @@ Extra Features ============== -The default interface of the $Projectname was designed to be uncluttered. There are a huge number of extra features (some of which are extremely useful) which you can turn on and get the most of the application. These are found under the [Extra Features](settings/features) link of your [Settings](settings) page. +The default interface of $Projectname was designed to be uncluttered. There are a huge number of extra features (some of which are extremely useful) which you can turn on and get the most of the application. These are found under the [Extra Features](settings/features) link of your [Settings](settings) page. **Content Expiration** diff --git a/doc/Plugins.md b/doc/Plugins.md index 90ff0fb7d..88b42185b 100644 --- a/doc/Plugins.md +++ b/doc/Plugins.md @@ -1,9 +1,9 @@ -Creating Plugins/Addons for the $Projectname +Creating Plugins/Addons for $Projectname ========================================== -So you want to make the $Projectname do something it doesn't already do. There are lots of ways. But let's learn how to write a plugin or addon. +So you want to make $Projectname do something it doesn't already do. There are lots of ways. But let's learn how to write a plugin or addon. In your $Projectname folder/directory, you will probably see a sub-directory called 'addon'. If you don't have one already, go ahead and create it. @@ -49,7 +49,7 @@ In our case, we'll call them randplace_load() and randplace_unload(), as that is * pluginname_uninstall() -Next we'll talk about **hooks**. Hooks are places in the $Projectname code where we allow plugins to do stuff. There are a [lot of these](help/Hooks), and they each have a name. What we normally do is use the pluginname_load() function to register a "handler function" for any hooks you are interested in. Then when any of these hooks are triggered, your code will be called. +Next we'll talk about **hooks**. Hooks are places in $Projectname code where we allow plugins to do stuff. There are a [lot of these](help/Hooks), and they each have a name. What we normally do is use the pluginname_load() function to register a "handler function" for any hooks you are interested in. Then when any of these hooks are triggered, your code will be called. We register hook handlers with the 'register_hook()' function. It takes 3 arguments. The first is the hook we wish to catch, the second is the filename of the file to find our handler function (relative to the base of your $Projectname installation), and the third is the function name of your handler function. So let's create our randplace_load() function right now. @@ -246,18 +246,18 @@ we will create an argc/argv list for use by your module functions ***Porting Friendica Plugins*** -The $Projectname uses a similar plugin architecture to the Friendica project. The authentication, identity, and permissions systems are completely different. Many Friendica can be ported reasonably easily by renaming a few functions - and then ensuring that the permissions model is adhered to. The functions which need to be renamed are: +$Projectname uses a similar plugin architecture to the Friendica project. The authentication, identity, and permissions systems are completely different. Many Friendica plugins can be ported reasonably easily by renaming a few functions - and then ensuring that the permissions model is adhered to. The functions which need to be renamed are: * Friendica's pluginname_install() is pluginname_load() * Friendica's pluginname_uninstall() is pluginname_unload() -The $Projectname has _install and _uninstall functions but these are used differently. +$Projectname has _install and _uninstall functions but these are used differently. * Friendica's "plugin_settings" hook is called "feature_settings" * Friendica's "plugin_settings_post" hook is called "feature_settings_post" -Changing these will often allow your plugin to function, but please double check all your permission and identity code because the concepts behind it are completely different in the $Projectname. Many structured data names (especially DB schema columns) are also quite different. +Changing these will often allow your plugin to function, but please double check all your permission and identity code because the concepts behind it are completely different in $Projectname. Many structured data names (especially DB schema columns) are also quite different. #include doc/macros/main_footer.bb; diff --git a/doc/Privacy.md b/doc/Privacy.md index 089977d7e..1ac019f5a 100644 --- a/doc/Privacy.md +++ b/doc/Privacy.md @@ -36,11 +36,11 @@ Any information or anything posted by you within $Projectname MAY be public or v Your profile photo, your channel name, and the location (URL or network address) of your channel are visible to anybody on the internet and privacy controls will not affect the display of these items. -You MAY additionally provide other profile information. Any information which you provide in your "default" or **public profile** MAY be transmitted to other hubs in the $Projectname and additionally MAY be displayed in the channel directory. You can restrict the viewing of this profile information. It may be restricted only to members of your hub, or only connections (friends), or other limited sets of viewers as you desire. If you wish for your profile to be restricted, you must set the appropriate privacy setting, or simply DO NOT provide additional information. +You MAY additionally provide other profile information. Any information which you provide in your "default" or **public profile** MAY be transmitted to other hubs in $Projectname and additionally MAY be displayed in the channel directory. You can restrict the viewing of this profile information. It may be restricted only to members of your hub, or only connections (friends), or other limited sets of viewers as you desire. If you wish for your profile to be restricted, you must set the appropriate privacy setting, or simply DO NOT provide additional information. **Content** -Content you provide (status posts, photos, files, etc.) belongs to you. The $Projectname default is to publish content openly and visible to anybody on the internet (PUBLIC). You MAY control this in your channel settings and restrict the default permissions or you MAY restrict the visibility of any single published item separately (PRIVATE). $Projectname developers will ensure that restricted content is ONLY visible to those in the restriction list - to the best of their ability. +Content you provide (status posts, photos, files, etc.) belongs to you. $Projectname default is to publish content openly and visible to anybody on the internet (PUBLIC). You MAY control this in your channel settings and restrict the default permissions or you MAY restrict the visibility of any single published item separately (PRIVATE). $Projectname developers will ensure that restricted content is ONLY visible to those in the restriction list - to the best of their ability. Content (especially status posts) that you share with other networks or that you have made visible to anybody on the internet (PUBLIC) cannot easily be taken back once it has been published. It MAY be shared with other networks and made available through RSS/Atom feeds. It may also be syndicated on other $Projectname sites. It MAY appear on other networks and websites and be visible in internet searches. If you do not wish this default behaviour please adjust your channel settings and restrict who can see your content. @@ -56,7 +56,7 @@ $Projectname developers will ensure that any content you provide which is design Privacy for your identity is another aspect. Because you have a decentralized identity in $Projectname, your privacy extends beyond your home hub. If you want to have complete control of your privacy and security you should run your own hub on a dedicated server. For many people, this is complicated and may stretch their technical abilities. So let's list a few precautions you can make to assure your privacy as much as possible. -A decentralized identity has a lot of advantages and gives you al lot of interesting features, but you should be aware of the fact that your identity is known by other hubs in the $Projectname network. One of those advantages is that other channels can serve you customized content and allow you to see private things (such as private photos which others wish to share with you). Because of this those channels need to know who you are. But we understand that sometimes those other channels know more from you than you might desire. For instance the plug-in Visage that can tell a channel owner the last time you visit their profile. You can easily OPT-OUT of this low level and we think, harmless tracking. +A decentralized identity has a lot of advantages and gives you al lot of interesting features, but you should be aware of the fact that your identity is known by other hubs in $Projectname network. One of those advantages is that other channels can serve you customized content and allow you to see private things (such as private photos which others wish to share with you). Because of this those channels need to know who you are. But we understand that sometimes those other channels know more from you than you might desire. For instance the plug-in Visage that can tell a channel owner the last time you visit their profile. You can easily OPT-OUT of this low level and we think, harmless tracking. * You can enable [Do Not Track (DNT)](http://donottrack.us/) in your web browser. We respect this new privacy policy proposal. All modern browsers support DNT. You will find it in the privacy settings of your browsers or else you can consult the web browser's manual. This will not affect the functionality of $Projectname. This setting is probably enough for most people. diff --git a/doc/Translations.md b/doc/Translations.md index 226fa2e1a..654ba1b83 100644 --- a/doc/Translations.md +++ b/doc/Translations.md @@ -1,4 +1,4 @@ -Translating the $Projectname +Translating $Projectname ========================== Translation Process diff --git a/doc/account_basics.bb b/doc/account_basics.bb index ba2380df7..664949d6e 100644 --- a/doc/account_basics.bb +++ b/doc/account_basics.bb @@ -10,7 +10,7 @@ Please provide a valid email address. Your email address is never published. Thi [b]Password[/b] -Enter a password of your choice, and repeat it in the second box to ensure it was typed correctly. As the $Projectname offers a decentralised identity, your account can log you in to many other websites. +Enter a password of your choice, and repeat it in the second box to ensure it was typed correctly. As $Projectname offers a decentralised identity, your account can log you in to many other websites. [b]Terms Of Service[/b] diff --git a/doc/addons_gnusocial.bb b/doc/addons_gnusocial.bb index dfdce5f6a..d9aed9ac5 100644 --- a/doc/addons_gnusocial.bb +++ b/doc/addons_gnusocial.bb @@ -8,7 +8,7 @@ https://yourgnusocialinstance.org/settings/oauthapps Next, click the link to Register a new application. That brings up the new application form. Here's what to do on each field. -Icon. I uploaded the $Projectname icon located at this link, after saving it to my computer: +Icon. I uploaded $Projectname icon located at this link, after saving it to my computer: https://github.com/redmatrix/hubzilla/blob/master/images/rm-32.png @@ -39,7 +39,7 @@ Then click on the icon or the name of the application for the information you'll Now open up a new tab or window and go to your $Projectname account, to Settings > Feature settings. Find the StatusNet Posting Settings. -Insert the strings of numbers given on the GNUsocial site into the $Projectname fields for Consumer Key and Consumer Secret. +Insert the strings of numbers given on the GNUsocial site into $Projectname fields for Consumer Key and Consumer Secret. The Base API Path (remember the trailing /) will be your instance domain, plus the /api/ following. It will probably look like this: @@ -51,9 +51,9 @@ StatusNet application name: Insert the name you gave to the application over on Click Submit. -A button will appear for you to "Sign in to StatusNet." Click it and that will open a tab or window on the GNUsocial site for you to click "Allow." Once clicked and successfully authorized, a security code number will appear. Copy it and go back to the $Projectname app you just left and insert it in the field: "Copy the security code from StatusNet here." Click Submit. +A button will appear for you to "Sign in to StatusNet." Click it and that will open a tab or window on the GNUsocial site for you to click "Allow." Once clicked and successfully authorized, a security code number will appear. Copy it and go back to $Projectname app you just left and insert it in the field: "Copy the security code from StatusNet here." Click Submit. -If successful, your information from the GNUsocial instance should appear in the $Projectname app. +If successful, your information from the GNUsocial instance should appear in $Projectname app. You now have several options to choose, if you desire, and those will need to be confirmed by clicking "Submit" also. The most interesting is "Send public postings to StatusNet by default." This option automatically sends any post of yours made in your $Projectname account to your GNUsocial instance. diff --git a/doc/ca/general.bb b/doc/ca/general.bb index f7d556130..dace92775 100644 --- a/doc/ca/general.bb +++ b/doc/ca/general.bb @@ -2,7 +2,7 @@ [zrl=[baseurl]/help/Privacy]Politica de Privacitat[/zrl] -[zrl=[baseurl]/help/history]Història de $Projectname[/zrl] +[zrl=[baseurl]/help/project/history]Història de $Projectname[/zrl] [h3]Recursos Externs[/h3] [zrl=[baseurl]/help/external-resource-links]Enllaços a Recursos Externs[/zrl] diff --git a/doc/campaign.bb b/doc/campaign.bb index 48f28f0c0..750412ba3 100644 --- a/doc/campaign.bb +++ b/doc/campaign.bb @@ -4,7 +4,7 @@ [b][color= grey][size=18]Single-click sign on, nomadic identity, censorship-resistance, privacy, self-hosting[/size][/color][/b] -We started the $Projectname project by asking ourselves a few questions: +We started $Projectname project by asking ourselves a few questions: - Imagine if it was possible to just access the content of different web sites, without the need to enter usernames and passwords for every site. Such a feature would permit Single-Click user identification: the ability to access sites simply by clicking on links to remote sites. Authentication just happens automagically behind the scenes. Forget about remembering multiple user names with multiple passwords when accessing different sites online. @@ -52,7 +52,7 @@ Think of it this way: the internet is nothing, but a bunch of permissions and a [b][color= grey][size=20]The Matrix is Born![/size][/color][/b] -After asking and striving to answer a number of such questions, we realized that we were imagining a general purpose communication network with a number of unique, and potentially game-changing, features. We called it the $Projectname and started thinking of it as an over-lay on top of the internet as it exists today; an operating system re-invented as a communication network, with its own permissions, access control lists, protocol, connectors to others services, and open-ended possibilities via its API. The sum of the matrix is greater than it's parts. We're not building website, but a way for websites to link together and grow into something that is unique and ever-changing, with autonomy and privacy. +After asking and striving to answer a number of such questions, we realized that we were imagining a general purpose communication network with a number of unique, and potentially game-changing, features. We called it $Projectname and started thinking of it as an over-lay on top of the internet as it exists today; an operating system re-invented as a communication network, with its own permissions, access control lists, protocol, connectors to others services, and open-ended possibilities via its API. The sum of the matrix is greater than it's parts. We're not building website, but a way for websites to link together and grow into something that is unique and ever-changing, with autonomy and privacy. It's a lot of work, for anyone. So far, we've got a team of a handful of volunteers, code geeks, brave early adopters, system administrators and other good people, willing to give the project a shot. We're motivated by our commitment to a free web, where privacy is built-in, and corporations don't have a stranglehold on our daily communication. @@ -60,7 +60,7 @@ We need your help to finish it and release it to the world! [b][color= grey][size=20]What have we written so far[/size][/color][/b] -As of the today, the $Projectname is in developer preview (alpha) state. It is not ready for everyday use, but some of the initial set of core features are implemented (again, in alpha state). These include: +As of the today, $Projectname is in developer preview (alpha) state. It is not ready for everyday use, but some of the initial set of core features are implemented (again, in alpha state). These include: - Zot, the protocol powering the matrix - Single-signon logins. @@ -71,7 +71,7 @@ As of the today, the $Projectname is in developer preview (alpha) state. It is [b][color= grey][size=20]Our TO-DO List[/size][/color][/b] -However, in addition to finishing and polishing the above, there are a number of features that have to implemented to make the $Projectname ready for daily use. If we meet our fundraising goal, we hope to dive into the following road map, by order of priority: +However, in addition to finishing and polishing the above, there are a number of features that have to implemented to make $Projectname ready for daily use. If we meet our fundraising goal, we hope to dive into the following road map, by order of priority: - A professionally designed user interface (UI), interface that is adaptive to any user level, from end users who want to use the Matrix as a social network, to tinkerers who will put together a customized blog using Comanche, to hackers who will develop and extend the matrix using a built-in code editor, that hooks to the API and the git. @@ -145,7 +145,7 @@ You get one of your $Projectname t-shirts, as well as our undying gratitude. Each contributor at this level gets their own $Projectname virtual private server, installed, hosted and supported by us for a period of 1 year. -[b][color= grey][size=20]Why are we so excited about the $Projectname?[/size][/color][/b] +[b][color= grey][size=20]Why are we so excited about $Projectname?[/size][/color][/b] {SOMETHING ABOUT THE POTENTIAL IMPACT OF RED, ITS INNOVATIONS, ETC> @@ -167,7 +167,7 @@ Perhaps you're good at writing and documenting stuff. Grab an account at one of [b]1. Is Red a social network?[/b] -The $Projectname is not a social network. We're thinking of it as a general purpose communication network, with sharing, and public/private communications built into the matrix. +$Projectname is not a social network. We're thinking of it as a general purpose communication network, with sharing, and public/private communications built into the matrix. [b]2. What is the difference between Red and Friendica?[/b] @@ -177,7 +177,7 @@ Friendica is really, really good at sending postcards. It can do all sorts of th What Friendica can't do, is wave a postcard at somebody and expect them to believe that holding this postcard prove you are who you say you are. Sure, if you've been sending somebody postcards, they might accept that it is you in the picture, but somebody who has never heard of you will not accept ownership of a postcard as proof of identity. -The $Projectname offers a passport. +$Projectname offers a passport. You can still use it to send postcards. At the same time, when you wave your passport at somebody, they do accept it as proof of identity. No longer do you need to register at every single site you use. You already have an account - it's just not necessarily at our site - so we'll ask to see your passport instead. @@ -194,7 +194,7 @@ We use MySQL as our database (this include any forks such as, MariaDB or Percona [b]5. How is the Affinity Slider different from Mozilla's Persona?[/b] {COMPLETE} -[b]6. Does the $Projectname use encryption? Details please![/b] +[b]6. Does $Projectname use encryption? Details please![/b] Yes, we do our best to use free and open source encryption libraries to help achieve privacy from general, mass surveillance. @@ -207,7 +207,7 @@ For more info on our initial implementation of encrypted communication, check ou [b]7. What do you mean by decentralization? [/b] -[b]8. Can I build my own website with in the $Projectname?[/b] +[b]8. Can I build my own website with in $Projectname?[/b] Yes. The short explanation: We've got this spiffy idea we're calling "Comanche", which will allow non-programmers to build complete custom websites, and any such website will be able to connect to any other website or channel in the matrix. The goal of Comanche is to hide the technical complexities of communicating in the matrix, while encouraging people to use their creativity and put together their own unique presence on the matrix. diff --git a/doc/channels.bb b/doc/channels.bb index 14d588266..eca8dd0e6 100644 --- a/doc/channels.bb +++ b/doc/channels.bb @@ -28,7 +28,7 @@ Once you have done this, your channel is ready to use. At [observer=1][observer. [h3]The grid, permissions and delegation[/h3] -The "Grid" page contains all recent posts from across the $Projectname network, again in reverse chronologial order. The exact posts that appear here depend largely on your permissions. At their most permissive, you will receive posts from complete strangers. At the other end of the scale, you may see posts from only your friends - or if you're feeling really anti-social, only your own posts. +The "Grid" page contains all recent posts from across $Projectname network, again in reverse chronologial order. The exact posts that appear here depend largely on your permissions. At their most permissive, you will receive posts from complete strangers. At the other end of the scale, you may see posts from only your friends - or if you're feeling really anti-social, only your own posts. As mentioned at the start, many other kinds of channel are possible, however, the creation procedure is the same. The difference between channels lies primarily in the permissions assigned. For example, a channel for sharing documents with colleagues at work would probably want more permissive settings for "Can write to my "public" file storage" than a personal account. For more information, see the [zrl=[baseurl]/help/roles]permissions section[/zrl]. diff --git a/doc/cloud.bb b/doc/cloud.bb index 3e0ac1fd3..2ad22806b 100644 --- a/doc/cloud.bb +++ b/doc/cloud.bb @@ -1,6 +1,6 @@ [b]Personal Cloud Storage[/b] -The $Projectname provides an ability to store privately and/or share arbitrary files with friends. +$Projectname provides an ability to store privately and/or share arbitrary files with friends. You may either upload files from your computer into your storage area, or copy them directly from the operating system using the WebDAV protocol. diff --git a/doc/comanche.bb b/doc/comanche.bb index 6a96d5251..4b198d657 100644 --- a/doc/comanche.bb +++ b/doc/comanche.bb @@ -65,17 +65,23 @@ By default, $nav is placed in the "nav" page region and $content is pl To select a theme for your page, use the 'theme' tag. [code] - [theme]apw[/theme] + [theme]suckerberg[/theme] [/code] -This will select the theme named "apw". By default your channel's preferred theme will be used. +This will select the theme named "suckerberg". By default your channel's preferred theme will be used. [code] - [theme=passion]apw[/theme] + [theme=passion]suckerberg[/theme] [/code] -This will select the theme named "apw" and select the "passion" schema (theme variant). +This will select the theme named "suckerberg" and select the "passion" schema (theme variant). Alternatively it may be possible to use a condensed theme notation for this. +[code] + [theme]suckerberg:passion[/theme] + +[/code] + +The condensed notation isn't part of Comanche itself but is recognised by $Projectname platform as a theme specifier. [b]Regions[/b] Each region has a name, as noted above. You will specify the region of interest using a 'region' tag, which includes the name. Any content you wish placed in this region should be placed between the opening region tag and the closing tag. @@ -164,7 +170,42 @@ The 'comment' tag is used to delimit comments. These comments will not appear on [comment]This is a comment[/comment] [/code] - + +[b]Conditional Execution[/b] +You can use an 'if' construct to make decisions. These are currently based on system configuration variable or the current observer. + +[code] + [if $config.system.foo] + ... the configuration variable system.foo evaluates to 'true'. + [else] + ... the configuration variable system.foo evaluates to 'false'. + [/if] + + [if $observer] + ... this content will only be show to authenticated viewers + [/if] + +[/code] + + The 'else' clause is optional. + + Several tests are supported besides boolean evaluation. + +[code] + [if $config.system.foo == bar] + ... the configuration variable system.foo is equal to the string 'bar' + [/if] + [if $config.system.foo != bar] + ... the configuration variable system.foo is not equal to the string 'bar' + [/if] + [if $config.system.foo {} bar ] + ... the configuration variable system.foo is a simple array containing a value 'bar' + [/if] + [if $config.system.foo {*} bar] + ... the configuration variable system.foo is a simple array containing a key named 'bar' + [/if] +[/code] + [b]Complex Example[/b] [code] [comment]use an existing page template which provides a banner region plus 3 columns beneath it[/comment] diff --git a/doc/connecting_to_channels.bb b/doc/connecting_to_channels.bb index be37eb25c..291323f75 100644 --- a/doc/connecting_to_channels.bb +++ b/doc/connecting_to_channels.bb @@ -1,6 +1,6 @@ [b]Connecting To Channels[/b] -Connections in the $Projectname can take on a great many different meanings. But let's keep it simple, you want to be friends with somebody like you are familiar with from social networking. How do you do it? +Connections in $Projectname can take on a great many different meanings. But let's keep it simple, you want to be friends with somebody like you are familiar with from social networking. How do you do it? First, you need to find some channels to connect to. There are two primary ways of doing this. Firstly, setting the "Can send me their channel stream and posts" permission to "Anybody in this network" will bring posts from complete strangers to your matrix. This will give you a lot of public content and should hopefully help you find interesting, entertaing people, forums, and channels. diff --git a/doc/connecting_to_channels.md b/doc/connecting_to_channels.md index 60834c244..349f58b67 100644 --- a/doc/connecting_to_channels.md +++ b/doc/connecting_to_channels.md @@ -1,6 +1,6 @@ # Connecting To Channels # -Connections in the $Projectname can take on a great many different meanings. But let's keep it simple, you want to be friends with somebody like you are familiar with from social networking. How do you do it? +Connections in $Projectname can take on a great many different meanings. But let's keep it simple, you want to be friends with somebody like you are familiar with from social networking. How do you do it? First, you need to find some channels to connect to. There are two primary ways of doing this. Firstly, setting the "Can send me their channel stream and posts" permission to "Anybody in this network" will bring posts from complete strangers to your matrix. This will give you a lot of public content and should hopefully help you find interesting, entertaing people, forums, and channels. diff --git a/doc/context/en/connedit/help.html b/doc/context/en/connedit/help.html new file mode 100644 index 000000000..9eb62ecc7 --- /dev/null +++ b/doc/context/en/connedit/help.html @@ -0,0 +1,12 @@ +
+
diff --git a/doc/context/en/settings/features/help.html b/doc/context/en/settings/features/help.html new file mode 100644 index 000000000..86e4f5dae --- /dev/null +++ b/doc/context/en/settings/features/help.html @@ -0,0 +1,12 @@ +- General
+- This page allows you to change or edit any individual settings for a particular connection or delete a connection completely. You may have arrived at this page after creating or approving a new connection. If so, you are not required to do anything. Your connection has already been established. You may wish to add them to a group or adjust special permissions, and this page is presented so that you may do this while the opportunity is fresh.
+- Connection Tools
+- The Connection Tools menu access several settings. View Profile, View Recent Activity, Refresh Permissions, set or reset flags (Block, Ignore, Archive, Hide) and Delete the connection.
+- Privacy Groups
+- Each connection may be assigned to one or more Privacy Groups for grouping collections of friends with access to specific posts, media and other content. You may add them to an existing privacy group here, or create a new privacy group. When you add them to an existing group the action is immediate and you are not required to submit a form.
+- Individual Permissions
+- Granting of permissions is usually automatic and require no action on your part. However you may wish to adjust specific permsisions for this connection which are different than for others.
+- Feature Specific Settings
+- A number of individual settings are controlled through additional features which may or may not be activated on your hub or for your channel. Several optional features have settings for each connection, and those may be set on this page through additional form tabs which may be present.
++
\ No newline at end of file diff --git a/doc/context/es-es/settings/features/help.html b/doc/context/es-es/settings/features/help.html new file mode 100644 index 000000000..a9c3c2d6c --- /dev/null +++ b/doc/context/es-es/settings/features/help.html @@ -0,0 +1,12 @@ +- General
+- This page allows you to configure settings for the many additional features of Hubzilla.
+- General Features
+- General feature settings include options relevant to your channel, such as webpage and wiki hosting.
+- Post Composition Features
+- The post composition features provide extra options and capabilities when composing new posts.
+- Network and Stream Filtering
+- These settings modify features associated with filtering and controlling your view of incoming posts.
+- Post/Comment Tools
+- These provide additional tools for categorizing posts and allowing additional commenting methods such as emoji or community tagging.
++
\ No newline at end of file diff --git a/doc/contributor/covenant.html b/doc/contributor/covenant.html new file mode 100644 index 000000000..4facac24e --- /dev/null +++ b/doc/contributor/covenant.html @@ -0,0 +1,106 @@ + + + + + +- General
+- Esta página le permite configurar los ajustes para muchas funcionalidades adicionales de Hubzilla.
+- Funcionalidades básicas
+- Las ajustes de las funcionalidades básicas incluyen opciones importantes para su canal, tales como el hospedaje de páginas web y wikis.
+- Opciones para la redacción de entradas
+- Los ajustes de la redacción de entradas incluyen opciones adicionales para la composición de nuevas publicaciones.
+- Filtrado del contenido
+- Estos ajustes modifican funcionalidades asociadas al filtrado del contenido y a cómo ver las publicaciones nuevas.
+- Gestión de entradas y comentarios
+- Estos ajustes proporcionan herramientas adicionales para establecer el tema de las entradas y permiten métodos adicionales para los comentarios, tales como los emojis y el etiquetado de la comunidad.
+Contributor Covenant 1.4.0 + + + + + + + + + + + + + + + + + +Contributor Covenant Code of Conduct
+ +Our Pledge
+ +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation.
+ +Our Standards
+ +Examples of behavior that contributes to creating a positive environment +include:
+ ++
+ +- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+Examples of unacceptable behavior by participants include:
+ ++
+ +- The use of sexualized language or imagery and unwelcome sexual attention or advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a professional setting
+Our Responsibilities
+ +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior.
+ +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful.
+ +Scope
+ +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers.
+ +Enforcement
+ +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at project@hubzilla.org. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately.
+ +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership.
+ +Attribution
+ +This Code of Conduct is adapted from the Contributor Covenant, version 1.4, +available at http://contributor-covenant.org/version/1/4.
+ + + diff --git a/doc/de/general.bb b/doc/de/general.bb index eb1c0f158..6660370d7 100644 --- a/doc/de/general.bb +++ b/doc/de/general.bb @@ -2,7 +2,7 @@ [zrl=[baseurl]/help/Privacy]Informationen zum Datenschutz[/zrl] -[zrl=[baseurl]/help/history]Zur Geschichte von $Projectname[/zrl] +[zrl=[baseurl]/help/project/history]Zur Geschichte von $Projectname[/zrl] [h3]Externe Ressourcen[/h3] [zrl=[baseurl]/help/external-resource-links]Links zu externen Ressourcen[/zrl] diff --git a/doc/develop.bb b/doc/develop.bb index ef3ea5bd0..20e987a5a 100644 --- a/doc/develop.bb +++ b/doc/develop.bb @@ -20,12 +20,12 @@ [zrl=[baseurl]/help/api_posting]Posting to $Projectname using the API[/zrl] [zrl=[baseurl]/help/developer_function_primer]Red Functions 101[/zrl] [zrl=[baseurl]/doc/html/]Code Reference (Doxygen generated - sets cookies)[/zrl] -[zrl=[baseurl]/help/to_do_doco]To-Do list for the $Projectname Documentation Project[/zrl] +[zrl=[baseurl]/help/to_do_doco]To-Do list for $Projectname Documentation Project[/zrl] [zrl=[baseurl]/help/to_do_code]To-Do list for Developers[/zrl] [zrl=[baseurl]/help/roadmap]Roadmap[/zrl] [zrl=[baseurl]/help/git_for_non_developers]Git for Non-Developers[/zrl] [zrl=[baseurl]/help/dev_beginner]Step-for-step manual for beginning developers[/zrl] [h3]External Resources[/h3] -[url=https://zothub.com/channel/one]Development Channel[/url] +[url=https://grid.reticu.li/channel/hubzilla]Development Channel[/url] [url=https://federated.social/channel/postgres]Postgres-specific $Projectname Admin Support Channel[/url] diff --git a/doc/developers.bb b/doc/developers.bb index 6f7752577..f8489640b 100644 --- a/doc/developers.bb +++ b/doc/developers.bb @@ -1,6 +1,6 @@ [b]$Projectname Developer Guide[/b] -We're pretty relaxed when it comes to developers. We don't have a lot of rules. Some of us are over-worked and if you want to help we're happy to let you help. That said, attention to a few guidelines will make the process smoother and make it easier to work together. We have developers from across the globe with different abilities and different cultural backgrounds and different levels of patience. Our primary rule is to respect others. Sometimes this is hard and sometimes we have very different opinions of how things should work, but if everybody makes an effort, we'll get along just fine. +We're pretty relaxed when it comes to developers. We don't have a lot of rules. Some of us are over-worked and if you want to help we're happy to let you help. That said, attention to a few guidelines will make the process smoother and make it easier to work together. All developers are expected to abide by our [zrl=[baseurl]/help/contributor/covenant]code of conduct[/zrl]. We have developers from across the globe with different abilities and different cultural backgrounds and different levels of patience. Our primary rule is to respect others. Sometimes this is hard and sometimes we have very different opinions of how things should work, but if everybody makes an effort, we'll get along just fine. [b]Here is how you can join us.[/b] @@ -19,7 +19,7 @@ to notify us to merge your work. [b]Translations[/b] -Our translations are managed through Transifex. If you wish to help out translating the $Projectname to another language, sign up on transifex.com, visit [url=https://www.transifex.com/projects/p/red-matrix/]https://www.transifex.com/projects/p/red-matrix/[/url] and request to join one of the existing language teams or create a new one. Notify one of the core developers when you have a translation update which requires merging, or ask about merging it yourself if you're comfortable with git and PHP. We have a string file called 'messages.po' which is gettext compliant and a handful of email templates, and from there we automatically generate the application's language files. +Our translations are managed through Transifex. If you wish to help out translating $Projectname to another language, sign up on transifex.com, visit [url=https://www.transifex.com/projects/p/red-matrix/]https://www.transifex.com/projects/p/red-matrix/[/url] and request to join one of the existing language teams or create a new one. Notify one of the core developers when you have a translation update which requires merging, or ask about merging it yourself if you're comfortable with git and PHP. We have a string file called 'messages.po' which is gettext compliant and a handful of email templates, and from there we automatically generate the application's language files. [zrl=[baseurl]/help/Translations]Translations - More Info[/zrl] diff --git a/doc/diaspora_compat.bb b/doc/diaspora_compat.bb new file mode 100644 index 000000000..f27a63b9d --- /dev/null +++ b/doc/diaspora_compat.bb @@ -0,0 +1,68 @@ +[h3]Diaspora Compatibility[/h3] + +The Diaspora Protocol addon allows a site to communicate using the Diaspora protocol, which allows communications and connections to be made with Diaspora members (and also Friendica members, since that network also provides the Diaspora Protocol). + +This addon is available in the 'basic' and 'standard' server configurations. It is not available with and the plugin is disabled completely when you are using the 'pro' server configuration. The reason for this is that the Diaspora protocol is not very sophisticated and many $projectname features do not work well with it. + +Members will have to be aware of limitations of the protocol or limit their own activities to those which are compatible with Diaspora. The 'pro' server configuration is free from these limitations and you may use all of the project features and abilities without regard for how they translate to other networks. Many features are unique to $Projectname and are supported by the "Zot" protocol, which is our native communications language between servers/hubs. + +If you are using a configuration which allows direct Diaspora communications you should be aware of the limitations presented here. + +[ul] +[*]Private mail retraction (unsend) is not possible for Diaspora connections. + +[*]Private posts and their associated comments are sent in plaintext email notifications in Diaspora and Friendica. This is a major privacy issue and affects any private communications you have where *any* member of the conversation is on another network. Be aware of it. + +[*]Access control only works on posts and comments. Diaspora members will get permission denied trying to access any other access controlled hubzilla objects such as files, photos, webpages, chatrooms, etc. In the case of private photos that are linked to posts, they will see a "prohibited sign" instead of the photo. Diaspora has no concept of private media and provides an illusion of photo privacy by using obscured URLs rather than protecting the photo from snooping by unauthorised viewers. + +There is no workaround except to make your media resources public (to everybody on the internet). + + +[*]Edited posts will not be delivered. Diaspora members will see the original post/comment without edits. There is no mechanism in the protocol to update an existing post. We cannot delete it and submit another invisibly because the message-id will change and we need to keep the same message-id on our own network. The only workaround is to delete the post/comment and do it over. (If this is a post, this will delete any existing likes/comments). We may eventually provide a way to delete the out of date copy only from Diaspora and keep it intact on networks that can handle edits. + +[*]Nomadic identity ($projectname 'standard' only) will not work with Diaspora. We may eventually provide an **option** which will allow you to "start sharing" from all of your clones when you make the first connection. The Diaspora person does not have to accept this, but it will allow your communications to continue if they accept this connection. Without this option, if you go to another server from where you made the connection originally or you make the connection before creating the clone, you will need to connect with them again from the new location. + +[*]Post expiration is not supported on Diaspora. We may provide you an option to not send expiring posts to that network. In the future this may be provided with a remote delete request. + +[*]End-to-end encryption is not supported. We will translate these posts into a lock icon, which can never be unlocked from the Diaspora side. + +[*]Message verification will eventually be supported. + +[*]Multiple profiles are not supported. Diaspora members can only see your default profile. + +[*]Birthday events will not appear in Diaspora. Other events will be translated and sent as a post, but all times will either be in the origination channel's timezone or in GMT. We do not know the recipient's timezone because Diaspora doesn't have this concept. + +[*]We currently allow tags to be hijacked by default. An option is provided to allow you to prevent the other end of the network from hijacking your tags and point them at its own resources. + +[*]Community tags will not work. We will send a tagging activity as a comment. It won't do anything. + +[*]Privacy tags (@!somebody) will not be available to Diaspora members. These tags may have to be stripped or obscured to prevent them from being hijacked - which could result in privacy issues. + +[*]Plus-tagged hubzilla forums should work from Diaspora. + + +[*]You cannot use Diaspora channels as channel sources. + + +[*]Dislikes of posts will be converted to comments and you will have the option to send these as comments or not send them to Diaspora (which does not provide dislike). Currently they are not sent. + +[*]We will do the same for both likes and dislikes of [b][i]comments[/i][/b]. They can either be sent as comments or you will have the ability to prevent them from being transmitted to Diaspora. Currently they are not sent. + +[*]Emojis are currently untranslated. + +[*]"observer tags" will be converted to empty text. + + +[*]Embedded apps will be translated into links. + + +[*]Embedded page design elements (work in progress) will be either stripped or converted to an error message. + +[*]Diaspora members will not appear in the directory. + + +[*]There are differences in oembed compatibility between the networks. Some embedded resources will turn into a link on one side or the other. + +[/ul] + +#include doc/macros/main_footer.bb; diff --git a/doc/diaspora_compat.md b/doc/diaspora_compat.md deleted file mode 100644 index 255b565a2..000000000 --- a/doc/diaspora_compat.md +++ /dev/null @@ -1,60 +0,0 @@ -##Diaspora Compatibility - -Diaspora protocol compatibility is presently considered an ***experimental*** feature. It may not be available on all sites and presents some serious compatibility issues with hubzilla. At the moment these compatibility issues will be shared with "Friendica-over-Diaspora" protocol communications. - -Private mail retraction (unsend) will not be possible on Diaspora. - -Private posts and their associated comments are sent in plaintext email notifications in Diaspora and Friendica. This is a major privacy issue and affects any private communications you have where *any* member of the conversation is on another network. Be aware of it. - -Access control only works on posts and comments. Diaspora members will get permission denied trying to access any other access controlled hubzilla objects such as files, photos, webpages, chatrooms, etc. In the case of private photos that are linked to posts, they will see a "prohibited sign" instead of the photo. Diaspora has no concept of private media. There is no workaround except to make your media resources public (to everybody on the internet). - - -Edited posts will not be delivered. Diaspora members will see the original post/comment without edits. There is no mechanism in the protocol to update an existing post. We cannot delete it and submit another invisibly because the message-id will change and we need to keep the same message-id on our own network. The only workaround is to delete the post/comment and do it over. We may eventually provide a way to delete the out of date copy only from Diaspora and keep it intact on networks that can handle edits. - -Some comments from external services will not deliver to Diaspora, as they have no Diaspora service discovery. Currently this applies to comments from WordPress blogs which are imported into your stream; but will extend to most any service that has no Diaspora discover mechanism. - - -Nomadic identity will not work with Diaspora. We will eventually provide an **option** which will allow you to "start sharing" from all of your clones when you make the first connection. The Diaspora person does not have to accept this, but it will allow your communications to continue if they accept this connection. Without this option, if you go to another server from where you made the connection originally or you make the connection before creating the clone, you will need to make friends with them again from the new location. - -Post expiration is not supported on Diaspora. We will provide you an option to not send expiring posts to that network. In the future this may be provided with a remote delete request. - -End-to-end encryption is not supported. We will translate these posts into a lock icon, which can never be unlocked from the Diaspora side. - -Message verification will eventually be supported. - -Multiple profiles are not supported. Diaspora members can only see your default profile. - -Birthday events will not appear in Diaspora. Other events will be translated and sent as a post, but all times will either be in the origination channel's timezone or in GMT. We do not know the recipient's timezone because Diaspora doesn't have this concept. - -We currently allow tags to be hijacked by default. We will provide an option to allow you to prevent the other end of the network from hijacking your tags and point them at its own resources. - -Community tags will not work. We will send a tagging activity as a comment. It won't do anything. - -Privacy tags (@!somebody) will not be available to Diaspora members. These tags may have to be stripped or obscured to prevent them from being hijacked - which could result in privacy issues. - -Plus-tagged hubzilla forums should work from Diaspora. - -Premium channel redirects will not be sent. If you allow Diaspora connections, they will not see that you have a premium channel. - -You cannot use Diaspora channels as channel sources. - - -Dislikes of posts will be converted to comments and you will have the option to send these as comments or not send them to Diaspora (which does not provide dislike). Currently they are not sent. - -We will do the same for both likes and dislikes of comments. They can either be sent as comments or you will have the ability to prevent them from being transmitted to Diaspora. Currently they are not sent. - - -"observer tags" will be converted to empty text. - - -Embedded apps will be translated into links. - - -Embedded page design elements (work in progress) will be either stripped or converted to an error message. - -Diaspora members will not appear in the directory. - - -There are differences in oembed compatibility between the networks. Some embedded resources will turn into a link on one side or the other. - -#include doc/macros/main_footer.bb; diff --git a/doc/extra_features.bb b/doc/extra_features.bb index 9fb43d9a1..0044a06a7 100644 --- a/doc/extra_features.bb +++ b/doc/extra_features.bb @@ -1,7 +1,7 @@ // multiple of these have been enabled by default. should we note this here somewhere, move it or remove them from this file? [b]Features[/b] -The default interface of the $Projectname was designed to be uncluttered. There are a huge number of extra features (some of which are extremely useful) which you can turn on and get the most of the application. These are found under the Extra Features link of your Settings page. +The default interface of $Projectname was designed to be uncluttered. There are a huge number of extra features (some of which are extremely useful) which you can turn on and get the most of the application. These are found under the Extra Features link of your Settings page. [b]Content Expiration[/b] diff --git a/doc/faq_admins.bb b/doc/faq_admins.bb index 63418c1dc..0b54a41de 100644 --- a/doc/faq_admins.bb +++ b/doc/faq_admins.bb @@ -1,4 +1,4 @@ -[size=large][b]The $Projectname FAQ[/b][/size] +[size=large][b]$Projectname FAQ[/b][/size] [toc] diff --git a/doc/faq_members.bb b/doc/faq_members.bb index 7af61df9b..c7f50314d 100644 --- a/doc/faq_members.bb +++ b/doc/faq_members.bb @@ -1,11 +1,11 @@ -[size=large][b]The $Projectname FAQ[/b][/size] +[size=large][b]$Projectname FAQ[/b][/size] [toc] [h3]I am able to edit a post's text after I saved it, but is there a way to change the permissions?[/h3] Short anser: No, there isn't. There are reasons. You are able to change permissons to your files, photos and the likes, but not to posts after you have saved them. The main reason is: Once you have saved a post it is being distributed either to the public channel and from there to other $Projectname servers or to those you intended it to go. Just like you cannot reclaim something you gave to another person, you cannot change permissions to $Projectname posts. We would need to track everywhere your posting goes, keep track of everyone you allowed to see it and then keep track of from whom to delete it. -If a posting is public this is even harder, as the $Projectname is a global network and there is no way to follow a post, let alone reclaim it reliably. Other networks that may receive your post have no reliable way to delete or reclaim the post. +If a posting is public this is even harder, as $Projectname is a global network and there is no way to follow a post, let alone reclaim it reliably. Other networks that may receive your post have no reliable way to delete or reclaim the post. [h3]I downloaded my channel and imported it (cloned my identity) to another site but there is no content, no posts, no photos. What is wrong???[/h3] Posts and photos/files are provided separately from the channel basic information. This is due to memory limitations dealing with years of conversations and photo archives. Posts and conversations can be synced separately from the basic channel information. Photos and file archives can be transferred using a plugin tool such as 'redfiles', which is currently listed as "experimental". When creating this feature we thought that keeping all your contacts was the most important task. Your friends have already seen your old content. Posts/conversations were next in priority and these may now be synced. Files and photos are the last bit to get completely working. Once we find someone willing to finish implementing this, it will be done. :) diff --git a/doc/feature/access_tokens.bb b/doc/feature/access_tokens.bb new file mode 100644 index 000000000..eb5c03717 --- /dev/null +++ b/doc/feature/access_tokens.bb @@ -0,0 +1,47 @@ +Feature: Zot Access Tokens +Status: Draft +Date: 15 July 2016 + + +Purpose: + +In order to facilitate sharing of private resources with non-members or members of federation nodes with limited identification discovery, Hubzilla should provide members with a mechanism to create and manage temporary ("throwaway") logins, aka "Zot Access Tokens". These tokens/credentials may be used to authenticate to a hubzilla site for the sole purpose of accessing privileged or access controlled resources (files, photos, posts, webpages, chatrooms, etc.). + + +Scope: + +Zot Access Tokens do not convey membership in the site or network. In particular, they do not provide an account or channel; which may be necessary to interact with the hub owner or with others in the network or federation of networks. In most cases they can only be used to consume restricted resources and do not have an ability to create those resources, however this ability may be provided by custom configurations or in future releases or addons. + +For instance the ability for a temporary login to access a chatroom may provide suitable permission to create chat messages inside that chatroom. + + +Implementation: + +Zot Access Tokens are managed through a "tab" of the settings page. Access to this tab may be controlled by site configuration. On this page, channels may create, edit, list, and remove any access tokens under their control. + +The form to create/edit accepts three parameters, a human readable name, a password or access token, and an optional expiration. Once expired, the access token is no longer valid, may no longer be used, and will be automatically purged from the list of temporary accounts. The password field in the create/edit forms displays the text of the access token and not an obscured password. By default we will create a token using the autoname() function, which generally produces a random character sequence which is "pronounceable", hence easy to convey or remember. This can be changed to any other character sequence which is acceptable to the site password complexity policy. (In most Hubzilla installations this imposes a minimum of three characters, but may be extended by plugin or site policy). + + +Usage: + +We do not specify mechanisms for sharing these tokens with others. Any communication method may be used. Any tokens you have created are added to the Access Control List selector and may be used anywhere that Access Control Lists are provided. + + Example: A visitor arrives at your site. She has an access token you have provided, and attempts to visit one of your photo albums (which is restricted to be viewed only by yourself and one temporary identity). Permission is denied. + +The visitor now selects "Login" from the menu navigation bar. This presents a login page. She enters the name and password you have provided her, and she can now view the restricted photo album. + + +Alternatively, you may share a link to a protected file by adding a parameter "&zat=abc123" to the URL, where the string "abc123" is the access token or password for the temporary login. No further negotiation is required, and the file is presented. + +Zot Acess Tokens are represented internally as an authenticated "observer". Querying the observer in code should return a pseudo or system generated xchan with an unknown protocol and a default profile photo. It will match (successfully) any access control rule which allows authenticated observers. + +Security Considerations: + +The URL form of authentication is inherently less secure than using a login, but may be preferable for some uses of this feature. It probably should not be transmitted over non-SSL links. + + +Future development: + +It might be desirable for future implementations to provide an options for single-use, where the access token is removed promptly following first use. + + \ No newline at end of file diff --git a/doc/feature/saved_search.bb b/doc/feature/saved_search.bb new file mode 100644 index 000000000..1e75f5a85 --- /dev/null +++ b/doc/feature/saved_search.bb @@ -0,0 +1,19 @@ +[h2]Saved Searches[/h2] + +In order to quickly find information, the 'saved search' widget may be used. This widget may be presented as a sidebar tool on your network page and possibly from your channel page. It is differentiated from the 'navigation bar' search tool in that it does not search the entire site, but only the subset of information available to your channel. + +Additionally the search terms you provide may activate a one-tme search or be saved in a list for re-use. Saving the search item also invokes the search in addition to adding it to the saved list (which is displayed below the search text entry box). Any item in the list may be discarded if it is no longer needed. + +The saved search widget will provide autocompletion of channels (the results are prefixed with '@'), and hashtags (prefixed with '#'). You do not need to enter these tags; although entering the desired tag will reduce the autocomplete results to only hold the relevant information. The behaviour maps as follows: + +[ul] + +[li]@name - search your network stream for posts or comments written by 'name'. This will also change the post editor permissions to include only 'name'; as if this was a privacy group.[/li] + +[li]#hashtag - search you network stream for posts containing #hashtag.[/li] + +[li]text - search your network stream for posts containing 'text'.[/li] + + +[/li] + diff --git a/doc/feature/techlevels.bb b/doc/feature/techlevels.bb new file mode 100644 index 000000000..9b07f086f --- /dev/null +++ b/doc/feature/techlevels.bb @@ -0,0 +1,15 @@ +[h2]Techlevels[/h2] + +Techlevels is a unique feature of Hubzilla 'pro'. It is not available in other server_roles, although it expands on the concepts introduced in Hubzilla 'basic'. + +[h3]Background[/h3] + +We've implemented several different mechanisms in order to reduce the apparent complexity and learning curve presented to new members. At the same time, we do not wish to limit any functionality for people who are able to grasp some slightly advanced technical technical features. The first mechanism was to move several features to an optional 'Features' page where they could be enabled at will; with the default interface kept somewhat lean. + +The problem we had now is that the number of features began to grow dramatically, and the Feature page is daunting in possibilities. There are also features present which probably should not be available to all members, but may be extremely useful to those with technical backgrounds. + +The techlevels seeeks to remedy this by grouping features within different levels of technical ability; starting at 0 (uncomfortable with technology), and up to 5 (Unix wizard or equivalent). + +When a new member registers, their account is provided a techlevel setting of 0. On the account settings page they may change this to any available level. A higher level opens more advanced features and possible interactions. + +The account administrator may also lock a particular level, lock a maximum level, or change/re-arrange the features available to any level. Those with the minimum level are typically not very exploratory and are unlikely to discover the advanced modes. This is by design. Those that look around and desire more interactions will find them. In the absence of administrator defaults they may choose any level. As they look at the features available to the level in question, it is generally expected that they will discover some features are beyond their comprehension and it is hoped they will back off to a level where the interface and features are comfortable to their skill level. This is somewhat experimental at present and for that reason is not part of the 'standard' server role. The standard server role is preset to level '5', and the basic server role is preset to level '0', with no possibility of change. Members in these roles may find themselves overwhelmed or underwhelmed by the feature set and complexity. diff --git a/doc/general.bb b/doc/general.bb index bbc85c900..cc5de5a56 100644 --- a/doc/general.bb +++ b/doc/general.bb @@ -1,7 +1,9 @@ [h2]Project and site information[/h2] [h3]$Projectname[/h3] [zrl=[baseurl]/help/Privacy]Privacy Policy[/zrl] -[zrl=[baseurl]/help/history]$Projectname history[/zrl] +[zrl=[baseurl]/help/project/governance]Project Governance[/zrl] +[zrl=[baseurl]/help/contributor/convenant]Project Covenant and Code of Conduct[/zrl] +[zrl=[baseurl]/help/project/history]$Projectname history[/zrl] [h3]External resources[/h3] [zrl=[baseurl]/help/external-resource-links]List of external resources[/zrl] [url=https://github.com/redmatrix/hubzilla]Main Website[/url] diff --git a/doc/hidden_configs.bb b/doc/hidden_configs.bb index 6e093dbfc..f34c253ce 100644 --- a/doc/hidden_configs.bb +++ b/doc/hidden_configs.bb @@ -41,7 +41,7 @@ Options are: [*= system.block_public_search ] Similar to block_public, except only blocks public access to search features. Useful for sites that want to be public, but keep getting hammered by search engines. [*= system.cron_hour ] Specify an hour in which to run cron_daily. By default with no config, this will run at midnight UTC. [*= system.default_permissions_role ] If set to a valid permissions role name, use that role for the first channel created by a new account and don't ask for the "Channel Type" on the channel creation form. Examples of valid names are: 'social', 'social_restricted', 'social_private', 'forum', 'forum_restricted' and 'forum_private'. Read more about permissions roles [zrl=[baseurl]/help/roles]here[/zrl]. - [*= system.default_photo_profile ] Set the profile photo that new channels start with. This should contain the name of a directory located under [font=courier]images/default_profile_photos/[/font], or be left unset. If not set then 'rainbow_man' is assumed. + [*= system.default_profile_photo ] Set the profile photo that new channels start with. This should contain the name of a directory located under [font=courier]images/default_profile_photos/[/font], or be left unset. If not set then 'rainbow_man' is assumed. [*= system.directorytags ] Set the number of keyword tags displayed on the directory page. Default is 50 unless set to a positive integer. [*= system.disable_directory_keywords ] If '1', do not show directory keywords. If the hub is a directory server, prevent returning tags to any directory clients. Please do not set this for directory servers in the RED_GLOBAL realm. [*= system.disable_discover_tab ] This allows you to completely disable the ability to discover public content from external sites. @@ -67,7 +67,7 @@ Options are: [*= system.paranoia ] As the pconfig, but on a site-wide basis. Can be overwritten by member settings. [*= system.photo_cache_time ] How long to cache photos, in seconds. Default is 86400 (1 day). Longer time increases performance, but it also means it takes longer for changed permissions to apply. [*= system.platform_name ] What to report as the platform name in webpages and statistics. (*) Must be set in .htconfig.php - [*= system.poco_rating_enable ] Distributed reputation reporting and data collection may be disabled. If your site does not participate in distributed reputation you will also not be able to make use of the data from your connections on other sites. By default and in the absence of any setting it is enabled. Individual members can opt out by restricting who can see their connections or by not providing any reputation information for their connections. + [*= system.rating_enabled ] Distributed reputation reporting and data collection. This feature is currently being re-worked. [*= system.poke_basic ] Reduce the number of poke verbs to exactly 1 ("poke"). Disable other verbs. [*= system.proc_run_use_exec ] If 1, use the exec system call in proc_run to run background tasks. By default we use proc_open and proc_close. On some (currently rare) systems this does not work well. [*= system.projecthome ] Display the project page on your home page for logged out viewers. diff --git a/doc/hook/bbcode.bb b/doc/hook/bbcode.bb index 2996a8528..f6b8711b0 100644 --- a/doc/hook/bbcode.bb +++ b/doc/hook/bbcode.bb @@ -1 +1,6 @@ [h2]bbcode[/h2] + + +Called at end of bbcode to html conversion. + +Hook argument contains the converted text string. diff --git a/doc/hook/bbcode_filter.bb b/doc/hook/bbcode_filter.bb new file mode 100644 index 000000000..efeb2e1b0 --- /dev/null +++ b/doc/hook/bbcode_filter.bb @@ -0,0 +1,7 @@ +[h2]bbcode_filter[/h2] + + +Called at beginning of bbcode to html conversion. + +Hook argument contains the text string to be converted. + diff --git a/doc/hook/event_store_event.bb b/doc/hook/event_store_event.bb new file mode 100644 index 000000000..7015a8322 --- /dev/null +++ b/doc/hook/event_store_event.bb @@ -0,0 +1,11 @@ +[h2]event_store_event[/h2] + +Called from event_store_event() when an event record is being stored. + +Hook info is an array + +'event' => the passed event details, ready for storage +'existing_event' => If the event already exists, a copy of the original event record from the database +'cancel' => false - set to true to cancel the operation. + + diff --git a/doc/hook/get_profile_photo.bb b/doc/hook/get_profile_photo.bb new file mode 100644 index 000000000..ab07179ae --- /dev/null +++ b/doc/hook/get_profile_photo.bb @@ -0,0 +1,18 @@ +[h2]get_profile_photo[/h2] + +Called when fetching the content of the default profile photo for a local channel in mod_photo. + + +Hook arguments: + +'imgscale' => integer resolution requested (4, 5, or 6) +'channel_id' => channel_id of requested profile photo +'default' => filename of default profile photo of this imgscale +'data' => empty string +'mimetype' => empty string + + +If 'data' is set, this data will be used instead of the data obtained from the database search for the profile photo. +If 'mimetype' is set, this mimetype will be used instead of the mimetype obtained from the database or the default profile photo mimetype. + + diff --git a/doc/hooklist.bb b/doc/hooklist.bb index 66ff1cf71..d190166f0 100644 --- a/doc/hooklist.bb +++ b/doc/hooklist.bb @@ -68,7 +68,10 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the called when converting bbcode to markdown [zrl=[baseurl]/help/hook/bbcode]bbcode[/zrl] - Called when converting bbcode to HTML + Called at end of converting bbcode to HTML + +[zrl=[baseurl]/help/hook/bbcode_filter]bbcode_filter[/zrl] + Called when beginning to convert bbcode to HTML [zrl=[baseurl]/help/hook/bb_translate_video]bb_translate_video[/zrl] Called when extracting embedded services from bbcode video elements (rarely used) @@ -184,6 +187,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the [zrl=[baseurl]/help/hook/event_created]event_created[/zrl] called when an event record is created +[zrl=[baseurl]/help/hook/event_store_event]event_store_event[/zrl] + called when an event record is created or updated + [zrl=[baseurl]/help/hook/event_updated]event_updated[/zrl] called when an event record is modified @@ -233,6 +239,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the [zrl=[baseurl]/help/hook/get_features]get_features[/zrl] Called when get_features() is called +[zrl=[baseurl]/help/hook/get_profile_photo]get_profile_photo[/zrl] + Called when local profile photo content is fetched in mod_photo + [zrl=[baseurl]/help/hook/get_role_perms]get_role_perms[/zrl] Called when get_role_perms() is called to obtain permissions for named permission roles diff --git a/doc/permissions.bb b/doc/permissions.bb index cc831dd61..0721c763d 100644 --- a/doc/permissions.bb +++ b/doc/permissions.bb @@ -28,7 +28,7 @@ We highly recommend that you use the "typical social network" settings when you [*= Anybody On This Hub ] Anybody with a channel on the same hub/website as you will have permission approved. Anybody who is registered at a different hub will have this permission denied. - [*= Anybody in this network ] Anybody in the $Projectname will have this permission approved. Even complete strangers. However, anybody not logged in/authenticated will have this permission denied. + [*= Anybody in this network ] Anybody in $Projectname will have this permission approved. Even complete strangers. However, anybody not logged in/authenticated will have this permission denied. [*= Anybody authenticated ] This is similar to "anybody in this network" except that it can include anybody who can authenticate by any means - and therefore [i]may[/i] include visitors from other networks. diff --git a/doc/plugins.bb b/doc/plugins.bb index f2f0b04e8..a320de790 100644 --- a/doc/plugins.bb +++ b/doc/plugins.bb @@ -45,7 +45,7 @@ In our case, we'll call them randplace_load() and randplace_unload(), as that is pluginname_uninstall() [/code] -Next we'll talk about [b]hooks[/b]. Hooks are places in the $Projectname code where we allow plugins to do stuff. There are a [url=[baseurl]/help/hooklist]lot of these[/url], and they each have a name. What we normally do is use the pluginname_load() function to register a "handler function" for any hooks you are interested in. Then when any of these hooks are triggered, your code will be called. +Next we'll talk about [b]hooks[/b]. Hooks are places in $Projectname code where we allow plugins to do stuff. There are a [url=[baseurl]/help/hooklist]lot of these[/url], and they each have a name. What we normally do is use the pluginname_load() function to register a "handler function" for any hooks you are interested in. Then when any of these hooks are triggered, your code will be called. We register hook handlers with the 'Zotlabs\Extend\Hook::register()' function. It typically takes 3 arguments. The first is the hook we wish to catch, the second is the filename of the file to find our handler function (relative to the base of your $Projectname installation), and the third is the function name of your handler function. So let's create our randplace_load() function right now. @@ -295,13 +295,13 @@ If you want to keep your plugin hidden from the siteinfo page, simply create a f ***Porting Friendica Plugins*** -The $Projectname uses a similar plugin architecture to the Friendica project. The authentication, identity, and permissions systems are completely different. Many Friendica can be ported reasonably easily by renaming a few functions - and then ensuring that the permissions model is adhered to. The functions which need to be renamed are: +$Projectname uses a similar plugin architecture to the Friendica project. The authentication, identity, and permissions systems are completely different. Many Friendica can be ported reasonably easily by renaming a few functions - and then ensuring that the permissions model is adhered to. The functions which need to be renamed are: [li] Friendica's pluginname_install() is pluginname_load()[/li] [li] Friendica's pluginname_uninstall() is pluginname_unload()[/li] -The $Projectname has _install and _uninstall functions but these are used differently. +$Projectname has _install and _uninstall functions but these are used differently. [li] Friendica's "plugin_settings" hook is called "feature_settings"[/li] diff --git a/doc/problems-following-an-update.bb b/doc/problems-following-an-update.bb index 3bc7e9a51..2d1fefc5b 100644 --- a/doc/problems-following-an-update.bb +++ b/doc/problems-following-an-update.bb @@ -28,7 +28,7 @@ We use the Smarty3 template engine to generate pages. These templates are compi [b]Theme Issues[/b] -There are many themes for The $Projectname. Only Redbasic is officialy supported by the core developers. This applies [i]even if a core developer happens to support an additional theme[/i]. This means new features are only guaranteed to work in Redbasic. +There are many themes for $Projectname. Only Redbasic is officialy supported by the core developers. This applies [i]even if a core developer happens to support an additional theme[/i]. This means new features are only guaranteed to work in Redbasic. Redbasic uses a few javascript libraries that are done differently, or entirely absent in other themes. This means new features may only work properly in Redbasic. Before reporting an issue, therefore, you should switch to Redbasic to see if it exists there. If the issue goes away, this is not a bug - it's a theme that isn't up to date. diff --git a/doc/project/governance.bb b/doc/project/governance.bb new file mode 100644 index 000000000..e13f6218c --- /dev/null +++ b/doc/project/governance.bb @@ -0,0 +1,45 @@ +[h2]$Projectname Governance[/h2] + +Governance relates to the management of a project and particularly how this relates to conflict resolution. + +This project uses a dual-governance model. + +The project as a whole and the repository were created initially by Mike Macgirvin; who controls the project copyright, and the project license, and manages the project as a Self Appointed Benevolent Dictator for Life. He holds veto power over any project proposal or decision and his word is final. + +That said, Mike has no interest in running the day to day activities of the project and influencing its direction, other than to protect his own work from sabotage. + +The internal project structure contains multiple "configurations" known as 'basic', 'standard', and 'pro'. Mike's veto power extends to any proposal or decision which he feels might adversely affect the 'pro' configuration. + +The 'basic and 'standard' configurations are controlled completely by the community. If the proposal or decision is crafted in such a way that its effects are limited to these configurations, Mike will consider relinquishing his power of veto and convert it to a normal community vote. + +Mario Vavti has done an incredible amount of work on the usability and theming of the project and holds veto power over any proposal or decision which might impact usability and "look and feel"; and his decision is also final. + +Mario's veto power is likewise restricted to anything using the standard project 'theme'. If a new theme is created and an otherwise vetoed decision is implemented entirely in this different theme and has no impact on the standard project theme, his veto [b]may[/b] also be turned into a normal community vote. + +This ability to work around a veto is at the discretion of Mike and Mario. They [b]may[/b] choose to relinquish their veto if the scope of the work is limited as described above, and in most circumstances they will leave the decision to the community. They are not obligated to do so. + +[h3]Community Governance[/h3] + +Beyond those two special cases, the project is maintained and decisions made by the 'community'. The governance structure is still evolving. Until the structure is finalised, decisions are made in the following order: + +[ol] +[*] Lazy Consensus + +If a project proposal is made to one of the community governance forums and there are no serious objections in a "reasonable" amount of time from date of proposal (we usually provide 2-3 days for all interested parties to weigh in), no vote needs to be taken and the proposal will be considered approved. Some concerns may be raised at this time, but if these are addressed during discussion and work-arounds provided, it will still be considered approved. + +[*] Veto + +If a proposal is vetoed, it is not necessarily the final word. See above on how to convert a veto into a normal community vote. This can be done by framing the proposal so that it does not impact the 'pro' configuration or the standard theme. + +[*] Community Vote + +A decision which does not have a clear mandate or clear consensus, but is not vetoed, can be taken to a community vote. At present this is a simple popular vote in one of the applicable community forums. At this time, popular vote decides the outcome. This may change in the future if the community adopts a 'council' governance model. This document will be updated at that time with the updated governance rules. +[/ol] + +Community Voting does not always provide a pleasant outcome and can generate polarised factions in the community (hence the reason why other models are under consideration). If the proposal is 'down voted' there are still several things which can be done and the proposal re-submitted with slightly different parameters (convert to an addon, convert to an optional feature which is disabled by default, etc.). If interest in the feature is high and the vote is "close", it can generate lots of bad feelings amongst the losing voters. On such close votes, it is [b]strongly recommended[/b] that the proposer take steps to address any concerns that were raised and re-submit. + + + + + + diff --git a/doc/history.md b/doc/project/history.md similarity index 91% rename from doc/history.md rename to doc/project/history.md index 7360c6b22..99cbfec7a 100644 --- a/doc/history.md +++ b/doc/project/history.md @@ -53,4 +53,22 @@ The Redmatrix community held a vote and the project was renamed "Hubzilla", with Mike stepped down as active coordinator for the project in early 2015 and turned management over to the community. He remains active as a Hubzilla developer. +##And Then... + +In 2016, the project was re-architected to support multiple server "roles". These correspond to sub-projects which can be isolated from each other in terms of supported feature sets, but all use and support the same code-base and developers are able to work together on common features and goals. The roles primarily differ in target audience, project [governance](help/project/governance) and decision making structures, and this results in slightly different features and idealogy. They all share a common code repository. + +Those roles are: + +### Basic + +Entry level server. Supported by and governed by the Hubzilla community. Most advanced or complex features have been stripped away to ease federation with external services. It is best suited as a FOSS social network tool. + +### Standard + +The standard Hubzilla server. This provides a wide range of useful features and is supported by and governed by the Hubzilla community. It is best suited as an open source community and cloud server. + +### Pro + +This is a specially crafted server with a unique feature set. It is supported by and governed by Mike Macgirvin dba "Zotlabs". Federation with external services has been stripped away in order to support a wide range of more technically advanced and complex features; and also includes features and modes which may not have the support or backing of the Hubzilla open source community. It is best suited for business and workplace applications. + #include doc/macros/main_footer.bb; diff --git a/doc/project/toc.html b/doc/project/toc.html new file mode 100644 index 000000000..b9489de3d --- /dev/null +++ b/doc/project/toc.html @@ -0,0 +1,6 @@ +Project Information
+ diff --git a/doc/project/versions.bb b/doc/project/versions.bb new file mode 100644 index 000000000..451cd0448 --- /dev/null +++ b/doc/project/versions.bb @@ -0,0 +1,30 @@ +[h2]Versions and Releases[/h2] + +$Projectname currently uses a standard version numbering sequence of $x.$y(.$z), for instance '1.12' or '1.12.1'. The first digit is the major version number. Major versions are released "roughly" once per year; often in December. + +The second digit is the minor release number. If this number is odd, it is a development version. If the number is even, it is a released version. Minor versions are released (moved from dev to master) typically once per month when development is 'stable', but this is likely to increase. Going forward minor releases will be made somewhere between one and three months; corresponding to a stable code point and when there is general community consensus that the current code base is stable enough to consider a release. + +The final digit is an interface or patch designator. + +The release process involves changing the version number (by definition the minor version number will be odd, and the minor number will be incremented). Once a year for a major release the major version will be incremented, and the minor number reset to 0. + +The release candidate is moved to a new branch; and testing will commence/continue for a period of 1-2 weeks afterward or until any significant issues have been resolved. This branch is usually labelled with RC (release candidate); for instance 1.8RC represents the pending release of version 1.8. At this time, the minor version number on the dev branch is incremented to the next odd number. (For instance 1.9). New development can then take place in the dev branch. + +Bug fixes should always be applied to 'dev' and from there merged forward (typically with git cherry-pick) to the RC branch and if necessary applied to the master or official release branch. + +At the time a release candidate is produced, the language strings file is frozen until a release is made. Translation work may continue, but all translations should be submitted to 'dev' and merged forward to RC. + + +Once RC testing is completed, RC is merged to 'master' and the RC version designator removed; resulting in one final checkin to change the version number. The CHANGELOG file should also be updated at or just prior to this time. If there are merge conflicts during this final merge, the merge will be abandoned; and 'git merge -s ours' applied. This results in a replacement of master with the contents of the RC branch. Conflicts often arise with string updates which were made to master after the last release and cannot easily be resolved without hand editing. Since this is a release of tested code, hand editing is discouraged, and the replacement merge strategy should be used instead. It is assumed that RC now contains the most recent well-tested code. + +Once the release is live and merged to master, the RC branch may be removed. + +Fixes may be made to master after release. Where possible these should be made to dev and 'git cherry-pick' used to merge forward; which preserves the commit info and prevents merge conflicts in the next cycle. Only rarely does a patch only apply to the master branch. If necessary this can be made. If the change is severe, the interface version number should be incremented. This is at the discretion of the community. In any event, a 'git pull' of the master branch should always result in the latest release with any post-release patches applied. + +The interface number (the $z in $x.$y.$z) should be incremented in dev whenever a change is made which changes the interfaces or API in incompatible ways so that any external packages (especially addons and API clients) relying on a the current behaviour can discover and change their own interfaces accordingly at the point that it changed. + + + + + + \ No newline at end of file diff --git a/doc/red2pi.bb b/doc/red2pi.bb index 18e7d325a..28db7dc70 100644 --- a/doc/red2pi.bb +++ b/doc/red2pi.bb @@ -1,4 +1,4 @@ -[b]How to install the $Projectname on a Raspberry Pi[/b] +[b]How to install $Projectname on a Raspberry Pi[/b] You just bought a Raspberry Pi and want to run the RED Matrix with your own domain name? diff --git a/doc/server_roles.bb b/doc/server_roles.bb new file mode 100644 index 000000000..ef6ec28ae --- /dev/null +++ b/doc/server_roles.bb @@ -0,0 +1,27 @@ +[h2]Server Roles[/h2] + +$Projectname can be configured in many different ways. One of the configurations available at installation is to select a 'server role'. There are currently three server roles. We highly recommend that you use 'standard' unless you have special needs. + + +[h3]Basic[/h3] + +The 'basic' server role is designed to be relatively simple, and it doesn't present options or complicated features. The hub admin may configure additional features at a site level. This role is designed for simple social networking and social network federation. Many features which do not federate easily have been removed, including (and this is somewhat important) "nomadic identity". You may move a channel to or from a basic server, but you may not clone it. Once moved, it becomes read-only on the origination site. No updates of any kind will be provided. It is recommended that after the move, the original channel be deleted - as it is no longer useable. The data remains only in case there are issues making a copy of the data. + +This role is supported by the hubzilla community. + +[h3]Standard[/h3] + + +The 'standard' server role is recommended for most sites. All features of the software are available to everybody unless locked by the hub administrator. Some features will not federate easily with other networks, so there is often an increased support burden explaining why sharing events with Diaspora (for instance) presents a different experience on that network. Additionally any member can enable "advanced" or "expert" features, and these may be beyond their technical skill level. This may also result in an increased support burden. + +This role is supported by the hubzilla community. + +[h3]Pro[/h3] + +The 'pro' server role is primarily designed for communities which want to present a uniform experience and be relieved of many federation support issues. In this role there is [b]no federation with other networks[/b]. Additional features [b]may[/b] be provided, such as channel ratings, premium channels, and e-commerce. + +By default a channel may set a "techlevel" appropriate to their technical skill. Higher levels provide more features. Everybody starts with techlevel 0 (similar to the 'basic' role) where all complicated features are hidden from view. Increasing the techlevel provides more advanced or complex features. + +The hub admin may also lock individual channels or their entire site at a defined techlevel which provides an installation with a selection of advanced features consistent with the perceived technical skills of the members. For instance, a community for horse racing might have a different techlevel than a community for Linux kernel developers. + +This role is not supported by the hubzilla community. \ No newline at end of file diff --git a/doc/sv/main.bb b/doc/sv/main.bb index a5c1d4f7a..27a7a742e 100644 --- a/doc/sv/main.bb +++ b/doc/sv/main.bb @@ -13,7 +13,7 @@ Zot är en fantastisk ny kommunikationsprotokoll uppfunnit speciellt för $Proje [h3]Kom igång[/h3] [zrl=[baseurl]/help/Privacy]Privacy Policy[/zrl] [zrl=[baseurl]/help/registration]Account Registration[/zrl] -[zrl=[baseurl]/help/accounts_profiles_channels_basics]You at the $Projectname: accounts, profiles and channels in short[/zrl] +[zrl=[baseurl]/help/accounts_profiles_channels_basics]You at $Projectname: accounts, profiles and channels in short[/zrl] [zrl=[baseurl]/help/profiles]Profiles[/zrl] [zrl=[baseurl]/help/channels]Channels[/zrl] [zrl=[baseurl]/help/sv/roles]Behörighetsförval för kanaler[/zrl] @@ -43,7 +43,7 @@ Zot är en fantastisk ny kommunikationsprotokoll uppfunnit speciellt för $Proje [zrl=[baseurl]/help/faq_admins]FAQ For Admins[/zrl] [h3]Teknisk dokumentation[/h3] -[zrl=[baseurl]/help/history]$Projectname history[/zrl] +[zrl=[baseurl]/help/project/history]$Projectname history[/zrl] [zrl=[baseurl]/help/Zot---A-High-Level-Overview]A high level overview of Zot[/zrl] [zrl=[baseurl]/help/zot]An introduction to Zot[/zrl] [zrl=[baseurl]/help/zot_structures]Zot Stuctures[/zrl] diff --git a/doc/toc.html b/doc/toc.html new file mode 100644 index 000000000..ac21959cf --- /dev/null +++ b/doc/toc.html @@ -0,0 +1,6 @@ + diff --git a/doc/zot.md b/doc/zot.md index 1e454e495..06c4d6083 100644 --- a/doc/zot.md +++ b/doc/zot.md @@ -57,7 +57,7 @@ In order to implement high performance communications, the data transfer format Bi-directional encryption is based on RSA 4096-bit keys expressed in DER/ASN.1 format using the PKCS#8 encoding variant, with AES-256-CBC used for block encryption of variable length or large items. -Some aspects of well known "federation protocols" (webfinger, salmon, activitystreams, portablecontacts, etc.) may be used in zot, but we are not tied to them and will not be bound by them. The $Projectname project is attempting some rather novel developments in decentralised communications and if there is any need to diverge from such "standard protocols" we will do so without question or hesitation. +Some aspects of well known "federation protocols" (webfinger, salmon, activitystreams, portablecontacts, etc.) may be used in zot, but we are not tied to them and will not be bound by them. $Projectname project is attempting some rather novel developments in decentralised communications and if there is any need to diverge from such "standard protocols" we will do so without question or hesitation. In order to create a globally unique ID, we will base it on a whirlpool hash of the identity URL of the origination node and a psuedo-random number, which should provide us with a 256 bit ID with an extremely low probability of collision (256 bits represents approximately 115 quattuorviginitillion or 1.16 X 10^77 unique numbers). This will be represented in communications as a base64url-encoded string. We will not depend on probabilities however and the ID must also be attached to a public key with public key cryptography used to provide an assurance of identity which has not been copied or somehow collided in whirlpool hash space. diff --git a/include/account.php b/include/account.php index 5c44f13ca..b78c3e56d 100644 --- a/include/account.php +++ b/include/account.php @@ -14,6 +14,13 @@ require_once('include/crypto.php'); require_once('include/channel.php'); +function get_account_by_id($account_id) { + $r = q("select * from account where account_id = %d", + intval($account_id) + ); + return (($r) ? $r[0] : false); +} + function check_account_email($email) { $result = array('error' => false, 'message' => ''); @@ -112,6 +119,7 @@ function create_account($arr) { $flags = ((x($arr,'account_flags')) ? intval($arr['account_flags']) : ACCOUNT_OK); $roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 ); $expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE); + $techlevel = ((array_key_exists('techlevel',$arr)) ? intval($arr['techlevel']) : intval(get_config('system','techlevel'))); $default_service_class = get_config('system','default_service_class'); @@ -171,16 +179,17 @@ function create_account($arr) { $r = q("INSERT INTO account ( account_parent, account_salt, account_password, account_email, account_language, - account_created, account_flags, account_roles, account_expires, account_service_class ) - VALUES ( %d, '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s' )", + account_created, account_flags, account_roles, account_level, account_expires, account_service_class ) + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s' )", intval($parent), dbesc($salt), dbesc($password_encoded), dbesc($email), dbesc(get_best_language()), dbesc(datetime_convert()), - dbesc($flags), - dbesc($roles), + intval($flags), + intval($roles), + intval($techlevel), dbesc($expires), dbesc($default_service_class) ); @@ -237,20 +246,23 @@ function verify_email_address($arr) { dbesc($arr['account']['account_language']) ); +//@fixme - get correct language template + $email_msg = replace_macros(get_intltext_template('register_verify_member.tpl'), array( '$sitename' => get_config('system','sitename'), - '$siteurl' => z_root(), + '$siteurl' => z_root(), '$email' => $arr['email'], '$uid' => $arr['account']['account_id'], '$hash' => $hash, '$details' => $details )); - $res = mail($arr['email'], email_header_encode(sprintf( t('Registration confirmation for %s'), get_config('system','sitename'))), - $email_msg, - 'From: ' . 'Administrator' . '@' . App::get_hostname() . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' + $res = z_mail( + [ + 'toEmail' => $arr['email'], + 'messageSubject' => sprintf( t('Registration confirmation for %s'), get_config('system','sitename')), + 'textVersion' => $email_msg, + ] ); if($res) @@ -312,11 +324,12 @@ function send_reg_approval_email($arr) { '$details' => $details )); - $res = mail($admin['email'], sprintf( t('Registration request at %s'), get_config('system','sitename')), - $email_msg, - 'From: ' . t('Administrator') . '@' . App::get_hostname() . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' + $res = z_mail( + [ + 'toEmail' => $admin['email'], + 'messageSubject' => sprintf( t('Registration request at %s'), get_config('system','sitename')), + 'textVersion' => $email_msg, + ] ); if($res) @@ -339,12 +352,14 @@ function send_register_success_email($email,$password) { '$password' => t('your registration password'), )); - $res = mail($email, sprintf( t('Registration details for %s'), get_config('system','sitename')), - $email_msg, - 'From: ' . t('Administrator') . '@' . App::get_hostname() . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' + $res = z_mail( + [ + 'toEmail' => $email, + 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')), + 'textVersion' => $email_msg, + ] ); + return($res ? true : false); } @@ -390,7 +405,7 @@ function account_allow($hash) { push_lang($register[0]['lang']); $email_tpl = get_intltext_template("register_open_eml.tpl"); - $email_tpl = replace_macros($email_tpl, array( + $email_msg = replace_macros($email_tpl, array( '$sitename' => get_config('system','sitename'), '$siteurl' => z_root(), '$username' => $account[0]['account_email'], @@ -399,11 +414,13 @@ function account_allow($hash) { '$uid' => $account[0]['account_id'] )); - $res = mail($account[0]['account_email'], sprintf( t('Registration details for %s'), get_config('system','sitename')), - $email_tpl, - 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n" - . 'Content-type: text/plain; charset=UTF-8' . "\n" - . 'Content-transfer-encoding: 8bit' ); + $res = z_mail( + [ + 'toEmail' => $account[0]['account_email'], + 'messageSubject' => sprintf( t('Registration details for %s'), get_config('system','sitename')), + 'textVersion' => $email_msg, + ] + ); pop_lang(); @@ -539,8 +556,8 @@ function account_approve($hash) { */ function downgrade_accounts() { - $r = q("select * from account where not ( account_flags & %d )>0 - and account_expires != '%s' + $r = q("select * from account where not ( account_flags & %d ) > 0 + and account_expires > '%s' and account_expires < %s ", intval(ACCOUNT_EXPIRED), dbesc(NULL_DATE), @@ -751,3 +768,23 @@ function upgrade_bool_message($bbcode = false) { $x = upgrade_link($bbcode); return t('This action is not available under your subscription plan.') . (($x) ? ' ' . $x : '') ; } + + +function get_account_techlevel($account_id = 0) { + + $role = \Zotlabs\Lib\System::get_server_role(); + if($role == 'basic') + return 0; + if($role == 'standard') + return 5; + + if(! $account_id) { + $x = \App::get_account(); + } + else { + $x = get_account_by_id($account_id); + } + + return (($x) ? intval($x['account_level']) : 0); + +} \ No newline at end of file diff --git a/include/acl_selectors.php b/include/acl_selectors.php index 148c67a6c..362776b44 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -13,7 +13,7 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) { $o .= "