diff options
Diffstat (limited to 'Zotlabs')
74 files changed, 1627 insertions, 722 deletions
diff --git a/Zotlabs/Access/AccessList.php b/Zotlabs/Access/AccessList.php index 6471b0b1d..7cf7b5587 100644 --- a/Zotlabs/Access/AccessList.php +++ b/Zotlabs/Access/AccessList.php @@ -3,10 +3,14 @@ namespace Zotlabs\Access; /** - * @brief AccessList class. + * @brief AccessList class which represents individual content ACLs. * * A class to hold an AccessList object with allowed and denied contacts and * groups. + * + * After evaluating @ref ::Zotlabs::Access::PermissionLimits "PermissionLimits" + * and @ref ::Zotlabs::Lib::Permcat "Permcat"s individual content ACLs are evaluated. + * These answer the question "Can Joe view *this* album/photo?". */ class AccessList { /** @@ -103,7 +107,7 @@ class AccessList { * @brief Return an array consisting of the current access list components * where the elements are directly storable. * - * @return Associative array with: + * @return array An associative array with: * * \e string \b allow_cid => string of allowed cids * * \e string \b allow_gid => string of allowed gids * * \e string \b deny_cid => string of denied cids diff --git a/Zotlabs/Access/PermissionLimits.php b/Zotlabs/Access/PermissionLimits.php index 8caeedb91..9ee0656b1 100644 --- a/Zotlabs/Access/PermissionLimits.php +++ b/Zotlabs/Access/PermissionLimits.php @@ -2,35 +2,90 @@ namespace Zotlabs\Access; -use \Zotlabs\Lib as ZLib; +use Zotlabs\Lib\PConfig; +/** + * @brief Permission limits. + * + * Permission limits are a very high level permission setting. They are hard + * limits by design. + * "Who can view my photos (at all)?" + * "Who can post photos in my albums (at all)?" + * + * For viewing permissions we generally set these to 'anybody' and for write + * permissions we generally set them to 'those I allow', though many people + * restrict the viewing permissions further for things like 'Can view my connections'. + * + * People get confused enough by permissions that we wanted a place to set their + * privacy expectations once and be done with it. + * + * Connection related permissions like "Can Joe view my photos?" are handled by + * @ref ::Zotlabs::Lib::Permcat "Permcat" and inherit from the channel's Permission + * limits. + * + * @see Permissions + */ class PermissionLimits { + /** + * @brief Get standard permission limits. + * + * Viewing permissions and post_comments permission are set to 'anybody', + * other permissions are set to 'those I allow'. + * + * The list of permissions comes from Permissions::Perms(). + * + * @return array + */ static public function Std_Limits() { + $limits = []; $perms = Permissions::Perms(); - $limits = array(); + foreach($perms as $k => $v) { - if(strstr($k,'view') || $k === 'post_comments') + if(strstr($k, 'view') || $k === 'post_comments') $limits[$k] = PERMS_PUBLIC; else $limits[$k] = PERMS_SPECIFIC; } + return $limits; } - static public function Set($channel_id,$perm,$perm_limit) { - ZLib\PConfig::Set($channel_id,'perm_limits',$perm,$perm_limit); + /** + * @brief Sets a permission limit for a channel. + * + * @param int $channel_id + * @param string $perm + * @param int $perm_limit one of PERMS_* constants + */ + static public function Set($channel_id, $perm, $perm_limit) { + PConfig::Set($channel_id, 'perm_limits', $perm, $perm_limit); } - static public function Get($channel_id,$perm = '') { + /** + * @brief Get a channel's permission limits. + * + * Return a channel's permission limits from PConfig. If $perm is set just + * return this permission limit, if not set, return an array with all + * permission limits. + * + * @param int $channel_id + * @param string $perm (optional) + * @return + * * \b boolean false if no perm_limits set for this channel + * * \b int if $perm is set, return one of PERMS_* constants for this permission + * * \b array with all permission limits, if $perm is not set + */ + static public function Get($channel_id, $perm = '') { if($perm) { - return Zlib\PConfig::Get($channel_id,'perm_limits',$perm); - } - else { - Zlib\PConfig::Load($channel_id); - if(array_key_exists($channel_id,\App::$config) && array_key_exists('perm_limits',\App::$config[$channel_id])) - return \App::$config[$channel_id]['perm_limits']; - return false; + return PConfig::Get($channel_id, 'perm_limits', $perm); } - } + + PConfig::Load($channel_id); + if(array_key_exists($channel_id, \App::$config) + && array_key_exists('perm_limits', \App::$config[$channel_id])) + return \App::$config[$channel_id]['perm_limits']; + + return false; + } }
\ No newline at end of file diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index d0175549b..ca6a7c08a 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -426,8 +426,10 @@ class Notifier { logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG); stringify_array_elms($recipients); - if(! $recipients) + if(! $recipients) { + logger('no recipients'); return; + } // logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG); diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index 9271cee85..d2a307fd5 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -221,6 +221,7 @@ class Apps { static public function translate_system_apps(&$arr) { $apps = array( 'Apps' => t('Apps'), + 'Articles' => t('Articles'), 'Cards' => t('Cards'), 'Admin' => t('Site Admin'), 'Report Bug' => t('Report Bug'), @@ -352,7 +353,7 @@ class Apps { break; default: if($config) - $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true); + $unset = ((get_config('system', $require[0]) === $require[1]) ? false : true); else $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true); if($unset) diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 697b57b6a..a7b4f28e8 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -804,6 +804,8 @@ class Enotify { 'when' => relative_date($item['created']), 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'), 'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])), + 'notify_id' => 'undefined', + 'thread_top' => (($item['item_thread_top']) ? true : false), 'message' => strip_tags(bbcode($itemem_text)) ); diff --git a/Zotlabs/Lib/Img_filesize.php b/Zotlabs/Lib/Img_filesize.php new file mode 100644 index 000000000..196697733 --- /dev/null +++ b/Zotlabs/Lib/Img_filesize.php @@ -0,0 +1,122 @@ +<?php + +namespace Zotlabs\Lib; + +class Img_filesize { + + private $url; + + function __construct($url) { + $this->url = $url; + } + + function getSize() { + $size = null; + + if(stripos($this->url,z_root() . '/photo') !== false) { + $size = self::getLocalFileSize($this->url); + } + if(! $size) { + $size = getRemoteFileSize($this->url); + } + + return $size; + } + + + static function getLocalFileSize($url) { + + $fname = basename($url); + $resolution = 0; + + if(strpos($fname,'.') !== false) + $fname = substr($fname,0,strpos($fname,'.')); + + if(substr($fname,-2,1) == '-') { + $resolution = intval(substr($fname,-1,1)); + $fname = substr($fname,0,-2); + } + + $r = q("SELECT filesize FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", + dbesc($fname), + intval($resolution) + ); + if($r) { + return $r[0]['filesize']; + } + return null; + } + +} + +/** + * Try to determine the size of a remote file by making an HTTP request for + * a byte range, or look for the content-length header in the response. + * The function aborts the transfer as soon as the size is found, or if no + * length headers are returned, it aborts the transfer. + * + * @return int|null null if size could not be determined, or length of content + */ +function getRemoteFileSize($url) +{ + $ch = curl_init($url); + + $headers = array( + 'Range: bytes=0-1', + 'Connection: close', + ); + + $in_headers = true; + $size = null; + + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2450.0 Iron/46.0.2450.0'); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_VERBOSE, 0); // set to 1 to debug + curl_setopt($ch, CURLOPT_STDERR, fopen('php://output', 'r')); + + curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $line) use (&$in_headers, &$size) { + $length = strlen($line); + + if (trim($line) == '') { + $in_headers = false; + } + + list($header, $content) = explode(':', $line, 2); + $header = strtolower(trim($header)); + + if ($header == 'content-range') { + // found a content-range header + list($rng, $s) = explode('/', $content, 2); + $size = (int)$s; + return 0; // aborts transfer + } else if ($header == 'content-length' && 206 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) { + // found content-length header and this is not a 206 Partial Content response (range response) + $size = (int)$content; + return 0; + } else { + // continue + return $length; + } + }); + + curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) use ($in_headers) { + if (!$in_headers) { + // shouldn't be here unless we couldn't determine file size + // abort transfer + return 0; + } + + // write function is also called when reading headers + return strlen($data); + }); + + curl_exec($ch); + curl_getinfo($ch); + curl_close($ch); + + return $size; +}
\ No newline at end of file diff --git a/Zotlabs/Lib/MarkdownSoap.php b/Zotlabs/Lib/MarkdownSoap.php index fa279b07c..a58a5753a 100644 --- a/Zotlabs/Lib/MarkdownSoap.php +++ b/Zotlabs/Lib/MarkdownSoap.php @@ -3,51 +3,66 @@ namespace Zotlabs\Lib; /** - * MarkdownSoap + * @brief MarkdownSoap class. + * * Purify Markdown for storage + * @code{.php} * $x = new MarkdownSoap($string_to_be_cleansed); * $text = $x->clean(); - * + * @endcode * What this does: * 1. extracts code blocks and privately escapes them from processing * 2. Run html purifier on the content * 3. put back the code blocks * 4. run htmlspecialchars on the entire content for safe storage * - * At render time: + * At render time: + * @code{.php} * $markdown = \Zotlabs\Lib\MarkdownSoap::unescape($text); * $html = \Michelf\MarkdownExtra::DefaultTransform($markdown); + * @endcode */ - - - class MarkdownSoap { + /** + * @var string + */ + private $str; + /** + * @var string + */ private $token; - private $str; function __construct($s) { - $this->str = $s; + $this->str = $s; $this->token = random_string(20); } - function clean() { $x = $this->extract_code($this->str); $x = $this->purify($x); - $x = $this->putback_code($x); + $x = $this->putback_code($x); $x = $this->escape($x); - + return $x; } + /** + * @brief Extracts code blocks and privately escapes them from processing. + * + * @see encode_code() + * @see putback_code() + * + * @param string $s + * @return string + */ function extract_code($s) { - + $text = preg_replace_callback('{ (?:\n\n|\A\n?) ( # $1 = the code block -- one or more lines, starting with a space/tab @@ -62,7 +77,7 @@ class MarkdownSoap { return $text; } - + function encode_code($matches) { return $this->token . ';' . base64_encode($matches[0]) . ';' ; } @@ -71,8 +86,17 @@ class MarkdownSoap { return base64_decode($matches[1]); } + /** + * @brief Put back the code blocks. + * + * @see extract_code() + * @see decode_code() + * + * @param string $s + * @return string + */ function putback_code($s) { - $text = preg_replace_callback('{' . $this->token . '\;(.*?)\;}xm',[ $this, 'decode_code' ], $s); + $text = preg_replace_callback('{' . $this->token . '\;(.*?)\;}xm', [ $this, 'decode_code' ], $s); return $text; } @@ -84,20 +108,25 @@ class MarkdownSoap { } function protect_autolinks($s) { - $s = preg_replace('/\<(https?\:\/\/)(.*?)\>/','[$1$2]($1$2)',$s); + $s = preg_replace('/\<(https?\:\/\/)(.*?)\>/', '[$1$2]($1$2)', $s); return $s; } function unprotect_autolinks($s) { return $s; - } function escape($s) { - return htmlspecialchars($s,ENT_QUOTES,'UTF-8',false); + return htmlspecialchars($s, ENT_QUOTES, 'UTF-8', false); } + /** + * @brief Converts special HTML entities back to characters. + * + * @param string $s + * @return string + */ static public function unescape($s) { - return htmlspecialchars_decode($s,ENT_QUOTES); + return htmlspecialchars_decode($s, ENT_QUOTES); } } diff --git a/Zotlabs/Lib/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php index 209a5ef3c..919c51276 100644 --- a/Zotlabs/Lib/NativeWikiPage.php +++ b/Zotlabs/Lib/NativeWikiPage.php @@ -68,6 +68,9 @@ class NativeWikiPage { return array('content' => null, 'message' => 'Error reading wiki', 'success' => false); } + // backslashes won't work well in the javascript functions + $name = str_replace('\\','',$name); + // create an empty activity $arr = []; @@ -351,6 +354,7 @@ class NativeWikiPage { // fetch the most recently saved revision. $item = self::load_page($arr); + if(! $item) { return array('message' => t('Page not found'), 'success' => false); } diff --git a/Zotlabs/Lib/Permcat.php b/Zotlabs/Lib/Permcat.php index 505ee2cfc..ca4aed9ed 100644 --- a/Zotlabs/Lib/Permcat.php +++ b/Zotlabs/Lib/Permcat.php @@ -2,12 +2,36 @@ namespace Zotlabs\Lib; -use \Zotlabs\Access as Zaccess; - +use Zotlabs\Access\PermissionRoles; +use Zotlabs\Access\Permissions; + +/** + * @brief Permission Categories. Permission rules for various classes of connections. + * + * Connection permissions answer the question "Can Joe view my photos?" + * + * Some permissions may be inherited from the channel's "privacy settings" + * (@ref ::Zotlabs::Access::PermissionLimits "PermissionLimits") "Who can view my + * photos (at all)?" which have higher priority than individual connection settings. + * We evaluate permission limits first, and then fall through to connection + * permissions if the permission limits didn't already make a definitive decision. + * + * After PermissionLimits and connection permissions are evaluated, individual + * content ACLs are evaluated (@ref ::Zotlabs::Access::AccessList "AccessList"). + * These answer the question "Can Joe view *this* album/photo?". + */ class Permcat { + /** + * @var array + */ private $permcats = []; + /** + * @brief Permcat constructor. + * + * @param int $channel_id + */ public function __construct($channel_id) { $perms = []; @@ -16,16 +40,16 @@ class Permcat { $role = get_pconfig($channel_id,'system','permissions_role'); if($role) { - $x = Zaccess\PermissionRoles::role_perms($role); + $x = PermissionRoles::role_perms($role); if($x['perms_connect']) { - $perms = Zaccess\Permissions::FilledPerms($x['perms_connect']); + $perms = Permissions::FilledPerms($x['perms_connect']); } } // if no role perms it may be a custom role, see if there any autoperms if(! $perms) { - $perms = Zaccess\Permissions::FilledAutoPerms($channel_id); + $perms = Permissions::FilledAutoPerms($channel_id); } // if no autoperms it may be a custom role with manual perms @@ -50,13 +74,13 @@ class Permcat { // nothing was found - create a filled permission array where all permissions are 0 if(! $perms) { - $perms = Zaccess\Permissions::FilledPerms([]); + $perms = Permissions::FilledPerms([]); } $this->permcats[] = [ 'name' => 'default', 'localname' => t('default','permcat'), - 'perms' => Zaccess\Permissions::Operms($perms), + 'perms' => Permissions::Operms($perms), 'system' => 1 ]; @@ -67,26 +91,39 @@ class Permcat { $this->permcats[] = [ 'name' => $p[$x][0], 'localname' => $p[$x][1], - 'perms' => Zaccess\Permissions::Operms(Zaccess\Permissions::FilledPerms($p[$x][2])), + 'perms' => Permissions::Operms(Permissions::FilledPerms($p[$x][2])), 'system' => intval($p[$x][3]) ]; } } } - + /** + * @brief Return array with permcats. + * + * @return array + */ public function listing() { return $this->permcats; } + /** + * @brief + * + * @param string $name + * @return array + * * \e array with permcats + * * \e bool \b error if $name not found in permcats true + */ public function fetch($name) { if($name && $this->permcats) { foreach($this->permcats as $permcat) { - if(strcasecmp($permcat['name'],$name) === 0) { + if(strcasecmp($permcat['name'], $name) === 0) { return $permcat; } } } + return ['error' => true]; } @@ -118,29 +155,32 @@ class Permcat { $permcats[] = [ $xv['k'], $xv['k'], $value, 0 ]; } } - } + } - call_hooks('permcats',$permcats); + /** + * @hooks permcats + * * \e array + */ + call_hooks('permcats', $permcats); return $permcats; - } - static public function find_permcat($arr,$name) { + static public function find_permcat($arr, $name) { if((! $arr) || (! $name)) return false; + foreach($arr as $p) if($p['name'] == $name) return $p['value']; } - static public function update($channel_id, $name,$permarr) { - PConfig::Set($channel_id,'permcat',$name,$permarr); + static public function update($channel_id, $name, $permarr) { + PConfig::Set($channel_id, 'permcat', $name, $permarr); } - static public function delete($channel_id,$name) { - PConfig::Delete($channel_id,'permcat',$name); + static public function delete($channel_id, $name) { + PConfig::Delete($channel_id, 'permcat', $name); } - }
\ No newline at end of file diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 67a507025..748edcdb7 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -38,7 +38,7 @@ class ThreadItem { $this->toplevel = ($this->get_id() == $this->get_data_value('parent')); // Prepare the children - if(count($data['children'])) { + if($data['children']) { foreach($data['children'] as $item) { /* @@ -105,7 +105,17 @@ class ThreadItem { $mode = $conv->get_mode(); - $edlink = (($item['item_type'] == ITEM_TYPE_CARD) ? 'card_edit' : 'editpost'); + switch($item['item_type']) { + case ITEM_TYPE_CARD: + $edlink = 'card_edit'; + break; + case ITEM_TYPE_ARTICLE: + $edlink = 'article_edit'; + break; + default: + $edlink = 'editpost'; + break; + } if(local_channel() && $observer['xchan_hash'] === $item['author_xchan']) $edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit')); @@ -186,7 +196,7 @@ class ThreadItem { $like_count = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid']] : ''); $like_list = ((x($conv_responses['like'],$item['mid'])) ? $conv_responses['like'][$item['mid'] . '-l'] : ''); - if (count($like_list) > MAX_LIKERS) { + if (($like_list) && (count($like_list) > MAX_LIKERS)) { $like_list_part = array_slice($like_list, 0, MAX_LIKERS); array_push($like_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { @@ -198,7 +208,7 @@ class ThreadItem { $dislike_count = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid']] : ''); $dislike_list = ((x($conv_responses['dislike'],$item['mid'])) ? $conv_responses['dislike'][$item['mid'] . '-l'] : ''); $dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun'); - if (count($dislike_list) > MAX_LIKERS) { + if (($dislike_list) && (count($dislike_list) > MAX_LIKERS)) { $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS); array_push($dislike_list_part, '<a class="dropdown-item" href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>'); } else { @@ -303,7 +313,7 @@ class ThreadItem { $comment_count_txt = sprintf( tt('%d comment','%d comments',$total_children),$total_children ); $list_unseen_txt = (($unseen_comments) ? sprintf('%d unseen',$unseen_comments) : ''); - + @@ -360,6 +370,7 @@ class ThreadItem { 'unverified' => $unverified, 'forged' => $forged, 'location' => $location, + 'divider' => get_pconfig($conv->get_profile_owner(),'system','item_divider'), 'attend_label' => t('Attend'), 'attend_title' => t('Attendance Options'), 'vote_label' => t('Vote'), diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php index 436723f8c..d0c964149 100644 --- a/Zotlabs/Lib/ThreadStream.php +++ b/Zotlabs/Lib/ThreadStream.php @@ -54,6 +54,14 @@ class ThreadStream { $this->profile_owner = local_channel(); $this->writable = true; break; + case 'pubstream': + $this->profile_owner = local_channel(); + $this->writable = ((local_channel()) ? true : false); + break; + case 'hq': + $this->profile_owner = local_channel(); + $this->writable = true; + break; case 'channel': $this->profile_owner = \App::$profile['profile_uid']; $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'); @@ -63,6 +71,11 @@ class ThreadStream { $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'); $this->reload = $_SESSION['return_url']; break; + case 'articles': + $this->profile_owner = \App::$profile['profile_uid']; + $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments'); + $this->reload = $_SESSION['return_url']; + break; case 'display': // in this mode we set profile_owner after initialisation (from conversation()) and then // pull some trickery which allows us to re-invoke this function afterward @@ -179,6 +192,10 @@ class ThreadStream { $item->set_commentable(can_comment_on_post($ob_hash,$item->data)); } } + if($this->mode === 'pubstream' && (! local_channel())) { + $item->set_commentable(false); + } + require_once('include/channel.php'); $item->set_conversation($this); diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php index ad1c8b8cd..fae7e2e44 100644 --- a/Zotlabs/Module/Acl.php +++ b/Zotlabs/Module/Acl.php @@ -1,36 +1,39 @@ <?php + namespace Zotlabs\Module; -/* - * ACL selector json backend +require_once 'include/acl_selectors.php'; +require_once 'include/group.php'; + +/** + * @brief ACL selector json backend. + * * This module provides JSON lists of connections and local/remote channels * (xchans) to populate various tools such as the ACL (AccessControlList) popup - * and various auto-complete functions (such as email recipients, search, and + * and various auto-complete functions (such as email recipients, search, and * mention targets. + * * There are two primary output structural formats. One for the ACL widget and * the other for auto-completion. - * Many of the behaviour variations are triggered on the use of single character keys - * however this functionality has grown in an ad-hoc manner and has gotten quite messy over time. + * + * Many of the behaviour variations are triggered on the use of single character + * keys however this functionality has grown in an ad-hoc manner and has gotten + * quite messy over time. */ - -require_once("include/acl_selectors.php"); -require_once("include/group.php"); - - class Acl extends \Zotlabs\Web\Controller { function init() { - + logger('mod_acl: ' . print_r($_REQUEST,true)); - + $start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0); $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500); $search = (x($_REQUEST,'search') ? $_REQUEST['search'] : ''); $type = (x($_REQUEST,'type') ? $_REQUEST['type'] : ''); - $noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false); + $noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false); - // $type = + // $type = // '' => standard ACL request // 'g' => Groups only ACL request // 'f' => forums only ACL request @@ -382,15 +385,13 @@ class Acl extends \Zotlabs\Web\Controller { 'count' => $count, 'items' => $items, ); - - - + echo json_encode($o); - + killme(); } - - + + function navbar_complete(&$a) { // logger('navbar_complete'); @@ -447,5 +448,5 @@ class Acl extends \Zotlabs\Web\Controller { } return array(); } - + } diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index eda97b591..60cb39277 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -29,12 +29,14 @@ class Site { $maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0); $register_policy = ((x($_POST,'register_policy')) ? intval(trim($_POST['register_policy'])) : 0); - + $minimum_age = ((x($_POST,'minimum_age')) ? intval(trim($_POST['minimum_age'])) : 13); $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'])) : ''); + $site_sellpage = ((x($_POST,'site_sellpage')) ? notags(trim($_POST['site_sellpage'])) : ''); + $site_location = ((x($_POST,'site_location')) ? notags(trim($_POST['site_location'])) : ''); $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']) : ''); @@ -76,6 +78,8 @@ class Site { set_config('system', 'poll_interval', $poll_interval); set_config('system', 'maxloadavg', $maxloadavg); set_config('system', 'frontpage', $frontpage); + set_config('system', 'sellpage', $site_sellpage); + set_config('system', 'site_location', $site_location); set_config('system', 'mirror_frontpage', $mirror_frontpage); set_config('system', 'sitename', $sitename); set_config('system', 'login_on_homepage', $login_on_homepage); @@ -123,6 +127,7 @@ class Site { set_config('system','maximagesize', $maximagesize); set_config('system','register_policy', $register_policy); + set_config('system','minimum_age', $minimum_age); set_config('system','invitation_only', $invite_only); set_config('system','access_policy', $access_policy); set_config('system','account_abandon_days', $abandon_days); @@ -251,6 +256,7 @@ class Site { ); $discover_tab = get_config('system','disable_discover_tab'); + // $disable public streams by default if($discover_tab === false) $discover_tab = 1; @@ -298,6 +304,7 @@ class Site { '$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.")), + '$minimum_age' => array('minimum_age', t("Minimum age"), (x(get_config('system','minimum_age'))?get_config('system','minimum_age'):13), t("Minimum age (in years) for who may register on this site.")), '$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.")), @@ -327,6 +334,12 @@ class Site { '$thumbnail_security' => array('thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.")), '$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")), '$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')), + + '$sellpage' => array('site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system','sellpage',''), sprintf( t('Create this page first. Default is %s/register'),z_root())), + + '$location' => array('site_location', t('Optional: site location'), get_config('system','site_location',''), t('Region or country')), + + '$form_security_token' => get_form_security_token("admin_site"), )); } diff --git a/Zotlabs/Module/Api.php b/Zotlabs/Module/Api.php index a2a1aac1d..aa0fca54d 100644 --- a/Zotlabs/Module/Api.php +++ b/Zotlabs/Module/Api.php @@ -39,10 +39,12 @@ class Api extends \Zotlabs\Web\Controller { // get consumer/client from request token try { - $request = OAuth1Request::from_request(); + $request = \OAuth1Request::from_request(); } catch(\Exception $e) { - echo "<pre>"; var_dump($e); killme(); + logger('OAuth exception: ' . print_r($e,true)); + // echo "<pre>"; var_dump($e); + killme(); } @@ -52,7 +54,7 @@ class Api extends \Zotlabs\Web\Controller { if (is_null($app)) return "Invalid request. Unknown token."; - $consumer = new OAuth1Consumer($app['client_id'], $app['pw'], $app['redirect_uri']); + $consumer = new \OAuth1Consumer($app['client_id'], $app['pw'], $app['redirect_uri']); $verifier = md5($app['secret'] . local_channel()); set_config('oauth', $verifier, local_channel()); @@ -63,7 +65,7 @@ class Api extends \Zotlabs\Web\Controller { $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)); + goaway($consumer->callback_url . $glue . "oauth_token=" . \OAuth1Util::urlencode_rfc3986($params['oauth_token']) . "&oauth_verifier=" . \OAuth1Util::urlencode_rfc3986($verifier)); killme(); } diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php index 2f61f2932..c672ea467 100644 --- a/Zotlabs/Module/Apps.php +++ b/Zotlabs/Module/Apps.php @@ -22,7 +22,8 @@ class Apps extends \Zotlabs\Web\Controller { if(local_channel()) { Zlib\Apps::import_system_apps(); $syslist = array(); - $list = Zlib\Apps::app_list(local_channel(), (($mode == 'edit') ? true : false), $_GET['cat']); + $cat = ((array_key_exists('cat',$_GET) && $_GET['cat']) ? [ escape_tags($_GET['cat']) ] : ''); + $list = Zlib\Apps::app_list(local_channel(), (($mode == 'edit') ? true : false), $cat); if($list) { foreach($list as $x) { $syslist[] = Zlib\Apps::app_encode($x); @@ -43,7 +44,7 @@ class Apps extends \Zotlabs\Web\Controller { return replace_macros(get_markup_template('myapps.tpl'), array( '$sitename' => get_config('system','sitename'), - '$cat' => ((array_key_exists('cat',$_GET) && $_GET['cat']) ? escape_tags($_GET['cat']) : ''), + '$cat' => $cat, '$title' => t('Apps'), '$apps' => $apps, '$authed' => ((local_channel()) ? true : false), diff --git a/Zotlabs/Module/Article_edit.php b/Zotlabs/Module/Article_edit.php new file mode 100644 index 000000000..758c1db2e --- /dev/null +++ b/Zotlabs/Module/Article_edit.php @@ -0,0 +1,138 @@ +<?php +namespace Zotlabs\Module; + +require_once('include/channel.php'); +require_once('include/acl_selectors.php'); +require_once('include/conversation.php'); + +class Article_edit extends \Zotlabs\Web\Controller { + + + function get() { + + // Figure out which post we're editing + $post_id = ((argc() > 1) ? intval(argv(1)) : 0); + + if(! $post_id) { + notice( t('Item not found') . EOL); + return; + } + + $itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1", + intval($post_id), + intval(ITEM_TYPE_ARTICLE) + ); + if($itm) { + $item_id = q("select * from iconfig where cat = 'system' and k = 'ARTICLE' and iid = %d limit 1", + intval($itm[0]['id']) + ); + if($item_id) + $card_title = $item_id[0]['v']; + } + else { + notice( t('Item not found') . EOL); + return; + } + + $owner = $itm[0]['uid']; + $uid = local_channel(); + + $observer = \App::get_observer(); + + $channel = channelx_by_n($owner); + if(! $channel) { + notice( t('Channel not found.') . EOL); + return; + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if(! perm_is_allowed($owner,$ob_hash,'write_pages')) { + notice( t('Permission denied.') . EOL); + return; + } + + $is_owner = (($uid && $uid == $owner) ? true : false); + + $o = ''; + + + + $category = ''; + $catsenabled = ((feature_enabled($owner,'categories')) ? 'categories' : ''); + + if ($catsenabled){ + $itm = fetch_post_tags($itm); + + $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); + + foreach ($cats as $cat) { + if (strlen($category)) + $category .= ', '; + $category .= $cat['term']; + } + } + + if($itm[0]['attach']) { + $j = json_decode($itm[0]['attach'],true); + if($j) { + foreach($j as $jj) { + $itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n"; + } + } + } + + + $mimetype = $itm[0]['mimetype']; + + $content = $itm[0]['body']; + + + + $rp = 'articles/' . $channel['channel_address']; + + $x = array( + 'nickname' => $channel['channel_address'], + 'bbco_autocomplete'=> 'bbcode', + 'return_path' => $rp, + 'webpage' => ITEM_TYPE_ARTICLE, + 'button' => t('Edit'), + 'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'), + 'weblink' => t('Insert web link'), + 'hide_voting' => false, + 'hide_future' => false, + 'hide_location' => false, + 'hide_expire' => false, + 'showacl' => true, + 'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')), + 'permissions' => $itm[0], + 'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'), + 'ptyp' => $itm[0]['type'], + 'mimeselect' => false, + 'mimetype' => $itm[0]['mimetype'], + 'body' => undo_post_tagging($content), + 'post_id' => $post_id, + 'visitor' => true, + 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + 'placeholdertitle' => t('Title (optional)'), + 'pagetitle' => $card_title, + 'profile_uid' => (intval($channel['channel_id'])), + 'catsenabled' => $catsenabled, + 'category' => $category, + 'bbcode' => (($mimetype == 'text/bbcode') ? true : false) + ); + + $editor = status_editor($a, $x); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Article'), + '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), + '$id' => $itm[0]['id'], + '$editor' => $editor + )); + + return $o; + + } + +} diff --git a/Zotlabs/Module/Articles.php b/Zotlabs/Module/Articles.php new file mode 100644 index 000000000..e2e0fed5d --- /dev/null +++ b/Zotlabs/Module/Articles.php @@ -0,0 +1,188 @@ +<?php +namespace Zotlabs\Module; + +require_once('include/channel.php'); +require_once('include/conversation.php'); +require_once('include/acl_selectors.php'); + + +class Articles extends \Zotlabs\Web\Controller { + + function init() { + + if(argc() > 1) + $which = argv(1); + else + return; + + profile_load($which); + + } + + function get($update = 0, $load = false) { + + if(observer_prohibited(true)) { + return login(); + } + + if(! \App::$profile) { + notice( t('Requested profile is not available.') . EOL ); + \App::$error = 404; + return; + } + + if(! feature_enabled(\App::$profile_uid,'articles')) { + return; + } + + nav_set_selected(t('Articles')); + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string), + 'title' => 'oembed' + ]); + + + $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : ''); + + if($category) { + $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $category, TERM_CATEGORY)); + } + + + $which = argv(1); + + $selected_card = ((argc() > 2) ? argv(2) : ''); + + $_SESSION['return_url'] = \App::$query_string; + + $uid = local_channel(); + $owner = \App::$profile_uid; + $observer = \App::get_observer(); + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if(! perm_is_allowed($owner,$ob_hash,'view_pages')) { + notice( t('Permission denied.') . EOL); + return; + } + + $is_owner = ($uid && $uid == $owner); + + $channel = channelx_by_n($owner); + + if($channel) { + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + } + else { + $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; + } + + + + if(perm_is_allowed($owner,$ob_hash,'write_pages')) { + + $x = [ + 'webpage' => ITEM_TYPE_ARTICLE, + 'is_owner' => true, + 'content_label' => t('Add Article'), + 'button' => t('Create'), + 'nickname' => $channel['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] + || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => (($is_owner) ? populate_acl($channel_acl, false, + \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')) : ''), + 'permissions' => $channel_acl, + 'showacl' => (($is_owner) ? true : false), + 'visitor' => true, + 'body' => '[summary][/summary]', + 'hide_location' => false, + 'hide_voting' => false, + 'profile_uid' => intval($owner), + 'mimetype' => 'text/bbcode', + 'mimeselect' => false, + 'layoutselect' => false, + 'expanded' => false, + 'novoting' => false, + 'catsenabled' => feature_enabled($owner,'categories'), + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true + ]; + + if($_REQUEST['title']) + $x['title'] = $_REQUEST['title']; + if($_REQUEST['body']) + $x['body'] = $_REQUEST['body']; + $editor = status_editor($a,$x); + + } + else { + $editor = ''; + } + + + $sql_extra = item_permissions_sql($owner); + + if($selected_card) { + $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.v = '%s' limit 1", + dbesc($selected_card) + ); + if($r) { + $sql_extra .= "and item.id = " . intval($r[0]['iid']) . " "; + } + } + + $r = q("select * from item + where item.uid = %d and item_type = %d + $sql_extra order by item.created desc", + intval($owner), + intval(ITEM_TYPE_ARTICLE) + ); + + $item_normal = " and item.item_hidden = 0 and item.item_type in (0,7) and item.item_deleted = 0 + and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 + and item.item_blocked = 0 "; + + if($r) { + + $parents_str = ids_to_querystr($r,'id'); + + $items = q("SELECT item.*, item.id AS item_id + FROM item + WHERE item.uid = %d $item_normal + AND item.parent IN ( %s ) + $sql_extra $sql_extra2 ", + intval(\App::$profile['profile_uid']), + dbesc($parents_str) + ); + if($items) { + xchan_query($items); + $items = fetch_post_tags($items, true); + $items = conv_sort($items,'updated'); + } + else + $items = []; + } + + $mode = 'articles'; + + $content = conversation($items,$mode,false,'traditional'); + + $o = replace_macros(get_markup_template('cards.tpl'), [ + '$title' => t('Articles'), + '$editor' => $editor, + '$content' => $content, + '$pager' => alt_pager($a,count($items)) + ]); + + return $o; + } + +} diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index 77052f97c..6737ac4ee 100644 --- a/Zotlabs/Module/Cdav.php +++ b/Zotlabs/Module/Cdav.php @@ -39,7 +39,7 @@ class Cdav extends \Zotlabs\Web\Controller { $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); if($sigblock) { - $keyId = $sigblock['keyId']; + $keyId = str_replace('acct:','',$sigblock['keyId']); if($keyId) { $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", dbesc($keyId) @@ -1250,7 +1250,7 @@ class Cdav extends \Zotlabs\Web\Controller { //create default addressbook $carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo); $properties = ['{DAV:}displayname' => t('Default Addressbook')]; - $carddavBackend->createAddressBook($uri, $default, $properties); + $carddavBackend->createAddressBook($uri, 'default', $properties); } } diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php index 0f7f9c47a..2215507ca 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -87,6 +87,10 @@ class Cloud extends \Zotlabs\Web\Controller { // $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth)); + // over-ride the default XML output on thrown exceptions + + $server->on('exception', [ $this, 'DAVException' ]); + // All we need to do now, is to fire up the server $server->exec(); @@ -97,4 +101,24 @@ class Cloud extends \Zotlabs\Web\Controller { killme(); } + + function DAVException($err) { + + if($err instanceof \Sabre\DAV\Exception\NotFound) { + notice( t('Not found') . EOL); + } + elseif($err instanceof \Sabre\DAV\Exception\Forbidden) { + notice( t('Permission denied') . EOL); + } + else { + notice( t('Unknown error') . EOL); + } + + construct_page(); + + killme(); + } + } + + diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 23c5282e3..8288886cd 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -567,7 +567,7 @@ class Connedit extends \Zotlabs\Web\Controller { $contact_id = \App::$poi['abook_id']; $contact = \App::$poi; - $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 order by xchan_name", + $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name", intval(local_channel()) ); @@ -866,7 +866,7 @@ class Connedit extends \Zotlabs\Web\Controller { $o .= replace_macros($tpl, [ '$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name'])), '$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no), - '$permcat' => [ 'permcat', t('Permission role'), '', '',$permcats ], + '$permcat' => [ 'permcat', t('Permission role'), '', '<span class="loading invisible">' . t('Loading') . '<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span></span>',$permcats ], '$permcat_new' => t('Add permission role'), '$permcat_enable' => feature_enabled(local_channel(),'permcats'), '$addr' => $contact['xchan_addr'], diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php index d506fe9f5..9f64e2fea 100644 --- a/Zotlabs/Module/Dav.php +++ b/Zotlabs/Module/Dav.php @@ -48,7 +48,7 @@ class Dav extends \Zotlabs\Web\Controller { $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); if($sigblock) { - $keyId = $sigblock['keyId']; + $keyId = str_replace('acct:','',$sigblock['keyId']); if($keyId) { $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", dbesc($keyId) diff --git a/Zotlabs/Module/Defperms.php b/Zotlabs/Module/Defperms.php index 9214331e4..422333a50 100644 --- a/Zotlabs/Module/Defperms.php +++ b/Zotlabs/Module/Defperms.php @@ -237,7 +237,7 @@ class Defperms extends \Zotlabs\Web\Controller { $o .= replace_macros($tpl, [ '$header' => t('Connection Default Permissions'), '$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no), - '$permcat' => [ 'permcat', t('Permission role'), '', '',$permcats ], + '$permcat' => [ 'permcat', t('Permission role'), '', '<span class="loading invisible">' . t('Loading') . '<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span></span>',$permcats ], '$permcat_new' => t('Add permission role'), '$permcat_enable' => feature_enabled(local_channel(),'permcats'), '$section' => $section, diff --git a/Zotlabs/Module/Dirsearch.php b/Zotlabs/Module/Dirsearch.php index e6cf5449a..53ec1a850 100644 --- a/Zotlabs/Module/Dirsearch.php +++ b/Zotlabs/Module/Dirsearch.php @@ -313,7 +313,7 @@ class Dirsearch extends \Zotlabs\Web\Controller { $ret['results'] = $entries; if($kw) { - $k = dir_tagadelic($kw); + $k = dir_tagadelic($kw, $hub); if($k) { $ret['keywords'] = array(); foreach($k as $kv) { diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index 266a5b6bf..6d895feb5 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -14,6 +14,7 @@ class Display extends \Zotlabs\Web\Controller { $module_format = 'html'; + if(argc() > 1) { $module_format = substr(argv(1),strrpos(argv(1),'.') + 1); if(! in_array($module_format,['atom','zot','json'])) @@ -30,7 +31,7 @@ class Display extends \Zotlabs\Web\Controller { return; } - if(argc() > 1 && argv(1) !== 'load') { + if(argc() > 1) { $item_hash = argv(1); if($module_format !== 'html') { $item_hash = substr($item_hash,0,strrpos($item_hash,'.')); @@ -260,7 +261,7 @@ class Display extends \Zotlabs\Web\Controller { elseif($update && !$load) { $r = null; - + require_once('include/channel.php'); $sys = get_sys_channel(); $sysid = $sys['channel_id']; @@ -285,7 +286,6 @@ class Display extends \Zotlabs\Web\Controller { // make that content unsearchable by ensuring the owner_xchan can't match if(! perm_is_allowed($sysid,$observer_hash,'view_stream')) $sysid = 0; - $r = q("SELECT item.parent AS item_id from item WHERE parent_mid = '%s' AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = '' @@ -315,7 +315,6 @@ class Display extends \Zotlabs\Web\Controller { WHERE parent in ( %s ) $item_normal ", dbesc($parents_str) ); - xchan_query($items); $items = fetch_post_tags($items,true); $items = conv_sort($items,'created'); diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php index c92af27d6..15cc68d7f 100644 --- a/Zotlabs/Module/Embedphotos.php +++ b/Zotlabs/Module/Embedphotos.php @@ -83,7 +83,7 @@ class Embedphotos extends \Zotlabs\Web\Controller { return ''; if($args['album']) - $album = $args['album']; + $album = (($args['album'] === '/') ? '' : $args['album']); if($args['title']) $title = $args['title']; diff --git a/Zotlabs/Module/Feed.php b/Zotlabs/Module/Feed.php index 06637b6d2..36869abbe 100644 --- a/Zotlabs/Module/Feed.php +++ b/Zotlabs/Module/Feed.php @@ -16,12 +16,15 @@ class Feed extends \Zotlabs\Web\Controller { $params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml'); $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0); $params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0); - $params['start'] = ((x($params,'start')) ? intval($params['start']) : 0); - $params['records'] = ((x($params,'records')) ? intval($params['records']) : 40); - $params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc'); + $params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0); + $params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 40); + $params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc'); $params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : ''); $params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 0); + if(! in_array($params['direction'],['asc','desc'])) { + $params['direction'] = 'desc'; + } if(argc() > 1) { diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php index 5c4b9a502..4d1cc4cda 100644 --- a/Zotlabs/Module/File_upload.php +++ b/Zotlabs/Module/File_upload.php @@ -10,7 +10,8 @@ class File_upload extends \Zotlabs\Web\Controller { function post() { - // logger('file upload: ' . print_r($_REQUEST,true)); + logger('file upload: ' . print_r($_REQUEST,true)); + logger('file upload: ' . print_r($_FILES,true)); $channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null); @@ -30,8 +31,8 @@ class File_upload extends \Zotlabs\Web\Controller { $_REQUEST['allow_cid'] = perms2str($_REQUEST['contact_allow']); $_REQUEST['allow_gid'] = perms2str($_REQUEST['group_allow']); - $_REQUEST['deny_cid'] = perms2str($_REQUEST['contact_deny']); - $_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']); + $_REQUEST['deny_cid'] = perms2str($_REQUEST['contact_deny']); + $_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']); if($_REQUEST['filename']) { $r = attach_mkdir($channel, get_observer_hash(), $_REQUEST); @@ -47,6 +48,51 @@ class File_upload extends \Zotlabs\Web\Controller { } } else { + + $matches = []; + $partial = false; + + + + if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); + if($pm) { + logger('Content-Range: ' . print_r($matches,true)); + $partial = true; + } + } + + if($partial) { + $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + + if($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($result); + } + else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } + else { + if(! array_key_exists('userfile',$_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + $r = attach_store($channel, get_observer_hash(), '', $_REQUEST); if($r['success']) { $sync = attach_export_data($channel,$r['data']['hash']); diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php index 55713027a..5c8557e5a 100644 --- a/Zotlabs/Module/Filestorage.php +++ b/Zotlabs/Module/Filestorage.php @@ -103,6 +103,11 @@ class Filestorage extends \Zotlabs\Web\Controller { attach_delete($owner, $f['hash']); + $sync = attach_export_data($channel, $f['hash'], true); + if($sync) { + build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } + goaway(dirname($url)); } diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php index 413a68e0c..abc9f50d9 100644 --- a/Zotlabs/Module/Getfile.php +++ b/Zotlabs/Module/Getfile.php @@ -28,17 +28,51 @@ class Getfile extends \Zotlabs\Web\Controller { function post() { - logger('post: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO); - + $header_verified = false; + $hash = $_POST['hash']; $time = $_POST['time']; $sig = $_POST['signature']; $resource = $_POST['resource']; $revision = intval($_POST['revision']); $resolution = (-1); - + if(! $hash) killme(); + + foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) { + if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') { + if($head !== 'HTTP_AUTHORIZATION') { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; + continue; + } + + $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]); + if($sigblock) { + $keyId = $sigblock['keyId']; + + if($keyId) { + $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash + where hubloc_addr = '%s' limit 1", + dbesc(str_replace('acct:','',$keyId)) + ); + if($r) { + $hubloc = $r[0]; + $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']); + if($verified && $verified['header_signed'] && $verified['header_valid'] && $hash == $hubloc['hubloc_hash']) { + $header_verified = true; + } + } + } + } + } + } + + + logger('post: ' . print_r($_POST,true),LOGGER_DEBUG,LOG_INFO); + if($header_verified) { + logger('HTTPSig verified'); + } $channel = channelx_by_hash($hash); @@ -59,16 +93,17 @@ class Getfile extends \Zotlabs\Web\Controller { $d1 = datetime_convert('UTC','UTC',"now + $slop minutes"); $d2 = datetime_convert('UTC','UTC',"now - $slop minutes"); - if(($time > $d1) || ($time < $d2)) { - logger('time outside allowable range'); - killme(); - } + if(! $header_verified) { + if(($time > $d1) || ($time < $d2)) { + logger('time outside allowable range'); + killme(); + } - if(! rsa_verify($hash . '.' . $time,base64url_decode($sig),$channel['channel_pubkey'])) { - logger('verify failed.'); - killme(); + if(! rsa_verify($hash . '.' . $time,base64url_decode($sig),$channel['channel_pubkey'])) { + logger('verify failed.'); + killme(); + } } - if($resolution > 0) { $r = q("select * from photo where resource_id = '%s' and uid = %d limit 1", diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php index 78087c0f9..a9c3bb8e2 100644 --- a/Zotlabs/Module/Hq.php +++ b/Zotlabs/Module/Hq.php @@ -10,6 +10,13 @@ require_once('include/items.php'); class Hq extends \Zotlabs\Web\Controller { + function init() { + if(! local_channel()) + return; + + \App::$profile_uid = local_channel(); + } + function post() { if(!local_channel()) @@ -43,33 +50,59 @@ class Hq extends \Zotlabs\Web\Controller { $item_normal_update = item_normal_update(); if(! $item_hash) { - $r = q("SELECT mid FROM item - WHERE uid = %d - AND item_thread_top = 1 - ORDER BY created DESC - limit 1", + WHERE uid = %d + AND mid = parent_mid + ORDER BY created DESC LIMIT 1", intval(local_channel()) ); - if(!$r[0]['mid']) { - \App::$error = 404; - notice( t('Item not found.') . EOL); - return; + if($r[0]['mid']) { + $item_hash = 'b64.' . base64url_encode($r[0]['mid']); } - - $item_hash = 'b64.' . base64url_encode($r[0]['mid']); } - if(strpos($item_hash,'b64.') === 0) - $decoded = @base64url_decode(substr($item_hash,4)); - if($decoded) - $item_hash = $decoded; - - $updateable = false; + if($item_hash) { - if(! $update) { + if(strpos($item_hash,'b64.') === 0) + $decoded = @base64url_decode(substr($item_hash,4)); + + if($decoded) + $item_hash = $decoded; + + $target_item = null; + + $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1", + dbesc($item_hash . '%') + ); + + if($r) { + $target_item = $r[0]; + } + + //if the item is to be moderated redirect to /moderate + if($target_item['item_blocked'] == ITEM_MODERATED) { + goaway(z_root() . '/moderate/' . $target_item['id']); + } + + $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); + + $simple_update = (($update) ? " AND item_unseen = 1 " : ''); + + if($update && $_SESSION['loadtime']) + $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; + + if($static && $simple_update) + $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + + $sys = get_sys_channel(); + $sql_extra = item_permissions_sql($sys['channel_id']); + + $sys_item = false; + + } + if(! $update) { $channel = \App::get_channel(); $channel_acl = [ @@ -91,66 +124,50 @@ class Hq extends \Zotlabs\Web\Controller { 'bang' => '', 'visitor' => true, 'profile_uid' => local_channel(), - 'return_path' => 'channel/' . $channel['channel_address'], + 'return_path' => 'hq', 'expanded' => true, 'editor_autocomplete' => true, 'bbco_autocomplete' => 'bbcode', 'bbcode' => true, 'jotnets' => true ]; - - $o = '<div id="jot-popup">'; - $o .= status_editor($a,$x); - $o .= '</div>'; - } - - $target_item = null; - $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1", - dbesc($item_hash . '%') - ); - - if($r) { - $target_item = $r[0]; - } + $o = replace_macros(get_markup_template("hq.tpl"), + [ + '$no_messages' => (($target_item) ? false : true), + '$no_messages_label' => [ t('Welcome to Hubzilla!'), t('You have got no unseen posts...') ], + '$editor' => status_editor($a,$x) + ] + ); - //if the item is to be moderated redirect to /moderate - if($target_item['item_blocked'] == ITEM_MODERATED) { - goaway(z_root() . '/moderate/' . $target_item['id']); } - - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - $simple_update = (($update) ? " AND item_unseen = 1 " : ''); - - if($update && $_SESSION['loadtime']) - $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; - if($load) - $simple_update = ''; - - if($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - if(! $update && ! $load) { - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); + nav_set_selected('HQ'); - // if the target item is not a post (eg a like) we want to address its thread parent + $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); - $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']); + if($target_item) { + // if the target item is not a post (eg a like) we want to address its thread parent + $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']); - // if we got a decoded hash we must encode it again before handing to javascript - if($decoded) - $mid = 'b64.' . base64url_encode($mid); + // if we got a decoded hash we must encode it again before handing to javascript + if($decoded) + $mid = 'b64.' . base64url_encode($mid); + } + else { + $mid = ''; + } - $o .= '<div id="live-display"></div>' . "\r\n"; + $o .= '<div id="live-hq"></div>' . "\r\n"; $o .= "<script> var profile_uid = " . local_channel() - . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n"; + . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . ";</script>\r\n"; \App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),[ '$baseurl' => z_root(), - '$pgtype' => 'display', - '$uid' => '0', + '$pgtype' => 'hq', + '$uid' => local_channel(), '$gid' => '0', '$cid' => '0', '$cmin' => '0', @@ -177,71 +194,94 @@ class Hq extends \Zotlabs\Web\Controller { '$net' => '', '$mid' => $mid ]); - } - if($load) { + $updateable = false; + + if($load && $target_item) { $r = null; - $r = q("SELECT item.id as item_id from item + $r = q("SELECT item.id AS item_id FROM item WHERE uid = %d - and mid = '%s' + AND mid = '%s' $item_normal - limit 1", + LIMIT 1", intval(local_channel()), dbesc($target_item['parent_mid']) ); + if($r) { $updateable = true; } + if(!$r) { + $sys_item = true; + + $r = q("SELECT item.id AS item_id FROM item + LEFT JOIN abook ON item.author_xchan = abook.abook_xchan + WHERE mid = '%s' AND item.uid = %d $item_normal + AND (abook.abook_blocked = 0 or abook.abook_flags is null) + $sql_extra LIMIT 1", + dbesc($target_item['parent_mid']), + intval($sys['channel_id']) + ); + } } - - elseif($update) { + elseif($update && $target_item) { $r = null; - $r = q("SELECT item.parent AS item_id from item + $r = q("SELECT item.parent AS item_id FROM item WHERE uid = %d - and parent_mid = '%s' + AND parent_mid = '%s' $item_normal_update $simple_update - limit 1", + LIMIT 1", intval(local_channel()), dbesc($target_item['parent_mid']) ); + if($r) { $updateable = true; } + if(!$r) { + $sys_item = true; + + $r = q("SELECT item.parent AS item_id FROM item + LEFT JOIN abook ON item.author_xchan = abook.abook_xchan + WHERE mid = '%s' AND item.uid = %d $item_normal_update $simple_update + AND (abook.abook_blocked = 0 or abook.abook_flags is null) + $sql_extra LIMIT 1", + dbesc($target_item['parent_mid']), + intval($sys['channel_id']) + ); + } + $_SESSION['loadtime'] = datetime_convert(); } - else { $r = []; } if($r) { - $parents_str = ids_to_querystr($r,'item_id'); - if($parents_str) { - $items = q("SELECT item.*, item.id AS item_id - FROM item - WHERE parent in ( %s ) $item_normal ", - dbesc($parents_str) - ); + $items = q("SELECT item.*, item.id AS item_id + FROM item + WHERE parent = '%s' $item_normal ", + dbesc($r[0]['item_id']) + ); - xchan_query($items); - $items = fetch_post_tags($items,true); - $items = conv_sort($items,'created'); - } + xchan_query($items,true,(($sys_item) ? local_channel() : 0)); + $items = fetch_post_tags($items,true); + $items = conv_sort($items,'created'); } else { $items = []; } - - $o .= conversation($items, 'display', $update, 'client'); + + $o .= conversation($items, 'hq', $update, 'client'); if($updateable) { - $x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ", + $x = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d AND parent = %d ", intval(local_channel()), intval($r[0]['item_id']) ); @@ -249,10 +289,6 @@ class Hq extends \Zotlabs\Web\Controller { $o .= '<div id="content-complete"></div>'; - if(($update && $load) && (! $items)) { - notice( t('Something went wrong.') . EOL ); - } - return $o; } diff --git a/Zotlabs/Module/Impel.php b/Zotlabs/Module/Impel.php index 77f488d26..0c372bd96 100644 --- a/Zotlabs/Module/Impel.php +++ b/Zotlabs/Module/Impel.php @@ -26,6 +26,8 @@ class Impel extends \Zotlabs\Web\Controller { if(! $j) json_return_and_die($ret); + // logger('element: ' . print_r($j,true)); + $channel = \App::get_channel(); $arr = array(); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index f2b850ffc..ad829137a 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -59,6 +59,7 @@ class Item extends \Zotlabs\Web\Controller { $profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0); require_once('include/channel.php'); + $sys = get_sys_channel(); if($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) { $uid = intval($sys['channel_id']); @@ -155,7 +156,7 @@ class Item extends \Zotlabs\Web\Controller { if(! x($_REQUEST,'type')) $_REQUEST['type'] = 'net-comment'; - if($obj_type == ACTIVITY_OBJ_POST) + if($obj_type == ACTIVITY_OBJ_NOTE) $obj_type = ACTIVITY_OBJ_COMMENT; if($parent) { @@ -171,7 +172,7 @@ class Item extends \Zotlabs\Web\Controller { ); } // if this isn't the real parent of the conversation, find it - if($r !== false && count($r)) { + if($r) { $parid = $r[0]['parent']; $parent_mid = $r[0]['mid']; if($r[0]['id'] != $r[0]['parent']) { @@ -179,9 +180,16 @@ class Item extends \Zotlabs\Web\Controller { intval($parid) ); } + + // if interacting with a pubstream item, + // create a copy of the parent in your stream + + if($r[0]['uid'] === $sys['channel_id'] && local_channel()) { + $r = [ copy_of_pubitem(\App::get_channel(), $r[0]['mid']) ]; + } } - - if(($r === false) || (! count($r))) { + + if(! $r) { notice( t('Unable to locate original post.') . EOL); if($api_source) return ( [ 'success' => false, 'message' => 'invalid post id' ] ); @@ -189,15 +197,12 @@ class Item extends \Zotlabs\Web\Controller { goaway(z_root() . "/" . $return_path ); killme(); } - - // can_comment_on_post() needs info from the following xchan_query - // This may be from the discover tab which means we need to correct the effective uid - xchan_query($r,true,(($r[0]['uid'] == local_channel()) ? 0 : local_channel())); - + xchan_query($r,true); + $parent_item = $r[0]; $parent = $r[0]['id']; - + // multi-level threading - preserve the info but re-parent to our single level threading $thr_parent = $parent_mid; @@ -499,7 +504,12 @@ class Item extends \Zotlabs\Web\Controller { $body = z_input_filter($body,$mimetype,$execflag); } - // Verify ability to use html or php!!! + + $arr = [ 'profile_uid' => $profile_uid, 'content' => $body, 'mimetype' => $mimetype ]; + call_hooks('post_content',$arr); + $body = $arr['content']; + $mimetype = $arr['mimetype']; + $gacl = $acl->get(); $str_contact_allow = $gacl['allow_cid']; @@ -511,13 +521,6 @@ class Item extends \Zotlabs\Web\Controller { require_once('include/text.php'); - if($uid && $uid == $profile_uid && feature_enabled($uid,'markdown')) { - require_once('include/markdown.php'); - $body = preg_replace_callback('/\[share(.*?)\]/ism','\share_shield',$body); - $body = markdown_to_bb($body,true,['preserve_lf' => true]); - $body = preg_replace_callback('/\[share(.*?)\]/ism','\share_unshield',$body); - - } // BBCODE alert: the following functions assume bbcode input // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) @@ -629,6 +632,9 @@ class Item extends \Zotlabs\Web\Controller { if($webpage == ITEM_TYPE_CARD) { $catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); } + elseif($webpage == ITEM_TYPE_ARTICLE) { + $catlink = z_root() . '/articles/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); + } else { $catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)); } @@ -733,6 +739,18 @@ class Item extends \Zotlabs\Web\Controller { } } + if($webpage == ITEM_TYPE_ARTICLE) { + $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : substr($mid,0,16)); + } + if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_ARTICLE)) { + $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.iid = %d limit 1", + intval($parent_item['id']) + ); + if($r) { + $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . $r[0]['v']; + } + } + if ((! $plink) && ($item_thread_top)) { $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid; } @@ -1119,7 +1137,29 @@ class Item extends \Zotlabs\Web\Controller { $ret['message'] = t('Unable to obtain post information from database.'); return $ret; } - + + // auto-upgrade beginner (techlevel 0) accounts - if they have at least two friends and ten posts + // and have uploaded something (like a profile photo), promote them to level 1. + + $a = q("select account_id, account_level from account where account_id = (select channel_account_id from channel where channel_id = %d limit 1)", + intval($channel_id) + ); + if((! intval($a[0]['account_level'])) && intval($r[0]['total']) > 10) { + $x = q("select count(abook_id) as total from abook where abook_channel = %d", + intval($channel_id) + ); + if($x && intval($x[0]['total']) > 2) { + $y = q("select count(id) as total from attach where uid = %d", + intval($channel_id) + ); + if($y && intval($y[0]['total']) > 1) { + q("update account set account_level = 1 where account_id = %d limit 1", + intval($a[0]['account_id']) + ); + } + } + } + if (!$iswebpage) { $max = engr_units_to_bytes(service_class_fetch($channel_id,'total_items')); if(! service_class_allows($channel_id,'total_items',$r[0]['total'])) { diff --git a/Zotlabs/Module/Layouts.php b/Zotlabs/Module/Layouts.php index 34d754029..19efb37fd 100644 --- a/Zotlabs/Module/Layouts.php +++ b/Zotlabs/Module/Layouts.php @@ -162,12 +162,12 @@ class Layouts extends \Zotlabs\Web\Controller { 'created' => $rr['created'], 'edited' => $rr['edited'], 'mimetype' => $rr['mimetype'], - 'pagetitle' => $rr['sid'], + 'pagetitle' => urldecode($rr['v']), 'mid' => $rr['mid'] ); $pages[$rr['iid']][] = array( 'url' => $rr['iid'], - 'title' => $rr['v'], + 'title' => urldecode($rr['v']), 'descr' => $rr['title'], 'mid' => $rr['mid'], 'created' => $rr['created'], diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php index 0abf111e0..b07824363 100644 --- a/Zotlabs/Module/Like.php +++ b/Zotlabs/Module/Like.php @@ -258,20 +258,27 @@ class Like extends \Zotlabs\Web\Controller { // get the item. Allow linked photos (which are normally hidden) to be liked $r = q("SELECT * FROM item WHERE id = %d - and (item_type = 0 or item_type = 6) and item_deleted = 0 and item_unpublished = 0 + and item_type in (0,6,7) and item_deleted = 0 and item_unpublished = 0 and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1", intval($item_id) ); + // if interacting with a pubstream item, + // create a copy of the parent in your stream. If not the conversation + // parent, copy that as well. + + if($r) { + if($r[0]['uid'] === $sys_channel['channel_id'] && local_channel()) { + $r = [ copy_of_pubitem(\App::get_channel(), $r[0]['mid']) ]; + } + } + if(! $item_id || (! $r)) { logger('like: no item ' . $item_id); killme(); } - // Use the $effective_uid option of xchan_query to sort out comment permission - // for public stream items - - xchan_query($r,true,(($r[0]['uid'] == $sys_channel_id) ? local_channel() : 0)); + xchan_query($r,true); $item = $r[0]; diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php index 4deb7c9e8..551303984 100644 --- a/Zotlabs/Module/Network.php +++ b/Zotlabs/Module/Network.php @@ -35,9 +35,12 @@ class Network extends \Zotlabs\Web\Controller { return login(false); } - if($load) + $o = ''; + + if($load) { $_SESSION['loadtime'] = datetime_convert(); - + } + $arr = array('query' => \App::$query_string); call_hooks('network_content_init', $arr); @@ -104,8 +107,10 @@ class Network extends \Zotlabs\Web\Controller { $def_acl = array('allow_gid' => '<' . $r[0]['hash'] . '>'); } - $o = ''; + $default_cmin = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0); + $default_cmax = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99); + // if no tabs are selected, defaults to comments @@ -115,8 +120,8 @@ class Network extends \Zotlabs\Web\Controller { $liked = ((x($_GET,'liked')) ? intval($_GET['liked']) : 0); $conv = ((x($_GET,'conv')) ? intval($_GET['conv']) : 0); $spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0); - $cmin = ((x($_GET,'cmin')) ? intval($_GET['cmin']) : 0); - $cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99); + $cmin = ((array_key_exists('cmin',$_GET)) ? intval($_GET['cmin']) : $default_cmin); + $cmax = ((array_key_exists('cmax',$_GET)) ? intval($_GET['cmax']) : $default_cmax); $file = ((x($_GET,'file')) ? $_GET['file'] : ''); $xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : ''); $net = ((x($_GET,'net')) ? $_GET['net'] : ''); @@ -404,7 +409,6 @@ class Network extends \Zotlabs\Web\Controller { if($cmax == 99) $sql_nets .= " OR abook.abook_closeness IS NULL ) "; - } $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : ''); @@ -473,7 +477,6 @@ class Network extends \Zotlabs\Web\Controller { if($load) { // Fetch a page full of parent items for this page - $r = q("SELECT distinct item.id AS item_id, $ordering FROM item left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) $net_query @@ -484,7 +487,6 @@ class Network extends \Zotlabs\Web\Controller { $net_query2 ORDER BY $ordering DESC $pager_sql " ); - } else { diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php index 5e06d3540..bb3a13b56 100644 --- a/Zotlabs/Module/Oep.php +++ b/Zotlabs/Module/Oep.php @@ -45,6 +45,8 @@ class Oep extends \Zotlabs\Web\Controller { $arr = $this->oep_profile_reply($_REQUEST); elseif(fnmatch('*/cards/*',$url)) $arr = $this->oep_cards_reply($_REQUEST); + elseif(fnmatch('*/articles/*',$url)) + $arr = $this->oep_articles_reply($_REQUEST); if($arr) { if($html) { @@ -232,6 +234,89 @@ class Oep extends \Zotlabs\Web\Controller { } + function oep_articles_reply($args) { + + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + if(preg_match('#//(.*?)/articles/(.*?)/(.*?)(&|\?|$)#',$url,$matches)) { + $nick = $matches[2]; + $res = $matches[3]; + } + if(! ($nick && $res)) + return $ret; + + $channel = channelx_by_nick($nick); + + if(! $channel) + return $ret; + + + if(! perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_pages')) + return $ret; + + $sql_extra = item_permissions_sql($channel['channel_id'],get_observer_hash()); + + $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.v = '%s' limit 1", + dbesc($res) + ); + if($r) { + $sql_extra = "and item.id = " . intval($r[0]['iid']) . " "; + } + else { + return $ret; + } + + $r = q("select * from item + where item.uid = %d and item_type = %d + $sql_extra order by item.created desc", + intval($channel['channel_id']), + intval(ITEM_TYPE_ARTICLE) + ); + + $item_normal = " and item.item_hidden = 0 and item.item_type in (0,7) and item.item_deleted = 0 + and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 + and item.item_blocked = 0 "; + + if($r) { + xchan_query($r); + $p = fetch_post_tags($r, true); + } + + $x = '2eGriplW^*Jmf4'; + + + $o = "[share author='".urlencode($p[0]['author']['xchan_name']). + "' profile='".$p[0]['author']['xchan_url'] . + "' avatar='".$p[0]['author']['xchan_photo_s']. + "' link='".$p[0]['plink']. + "' posted='".$p[0]['created']. + "' message_id='".$p[0]['mid']."']"; + if($p[0]['title']) + $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n"; + + $o .= $x; + $o .= "[/share]"; + $o = bbcode($o); + + $o = str_replace($x,bbcode($p[0]['body']),$o); + + $ret['type'] = 'rich'; + + $w = (($maxwidth) ? $maxwidth : 640); + $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); + + $ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>'; + + $ret['width'] = $w; + $ret['height'] = $h; + + return $ret; + + } + function oep_mid_reply($args) { diff --git a/Zotlabs/Module/Ofeed.php b/Zotlabs/Module/Ofeed.php index 58488d4af..d18a43ae5 100644 --- a/Zotlabs/Module/Ofeed.php +++ b/Zotlabs/Module/Ofeed.php @@ -17,12 +17,15 @@ class Ofeed extends \Zotlabs\Web\Controller { $params['type'] = ((stristr(argv(0),'json')) ? 'json' : 'xml'); $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0); $params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0); - $params['start'] = ((x($params,'start')) ? intval($params['start']) : 0); - $params['records'] = ((x($params,'records')) ? intval($params['records']) : 10); - $params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc'); + $params['start'] = ((x($_REQUEST,'start')) ? intval($_REQUEST['start']) : 0); + $params['records'] = ((x($_REQUEST,'records')) ? intval($_REQUEST['records']) : 10); + $params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc'); $params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : ''); $params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 1); + if(! in_array($params['direction'],['asc','desc'])) { + $params['direction'] = 'desc'; + } if(argc() > 1) { diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php index d58fd7a41..23ee14f39 100644 --- a/Zotlabs/Module/Owa.php +++ b/Zotlabs/Module/Owa.php @@ -31,19 +31,26 @@ class Owa extends \Zotlabs\Web\Controller { if($keyId) { $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash - where hubloc_addr = '%s' limit 1", + where hubloc_addr = '%s' ", dbesc(str_replace('acct:','',$keyId)) ); if($r) { - $hubloc = $r[0]; - $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']); - if($verified && $verified['header_signed'] && $verified['header_valid']) { - $ret['success'] = true; - $token = random_string(32); - \Zotlabs\Zot\Verify::create('owt',0,$token,$r[0]['hubloc_addr']); - $result = ''; - openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']); - $ret['encrypted_token'] = base64url_encode($result); + foreach($r as $hubloc) { + $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']); + if($verified && $verified['header_signed'] && $verified['header_valid']) { + logger('OWA header: ' . print_r($verified,true),LOGGER_DATA); + logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA); + $ret['success'] = true; + $token = random_string(32); + \Zotlabs\Zot\Verify::create('owt',0,$token,$hubloc['hubloc_addr']); + $result = ''; + openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']); + $ret['encrypted_token'] = base64url_encode($result); + break; + } + else { + logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']); + } } } } diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php index caef45d98..81af607ec 100644 --- a/Zotlabs/Module/Photos.php +++ b/Zotlabs/Module/Photos.php @@ -202,6 +202,11 @@ class Photos extends \Zotlabs\Web\Controller { ); if(($m) && ($m[0]['folder'] != $_POST['move_to_album'])) { attach_move($page_owner_uid,argv(2),$_POST['move_to_album']); + + $sync = attach_export_data(\App::$data['channel'],argv(2),true); + if($sync) + build_sync_packet($page_owner_uid,array('file' => array($sync))); + if(! ($_POST['desc'] && $_POST['newtag'])) goaway(z_root() . '/' . $_SESSION['photo_return']); } @@ -465,6 +470,51 @@ class Photos extends \Zotlabs\Web\Controller { $_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']); } + + $matches = []; + $partial = false; + + + + if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); + if($pm) { + logger('Content-Range: ' . print_r($matches,true)); + $partial = true; + } + } + + if($partial) { + $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + + if($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($result); + } + else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } + else { + if(! array_key_exists('userfile',$_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + $r = attach_store($channel,get_observer_hash(), '', $_REQUEST); if(! $r['success']) { @@ -557,8 +607,11 @@ class Photos extends \Zotlabs\Web\Controller { nav_set_selected('Photos'); - $o = ""; - + $o = '<script src="library/blueimp_upload/js/vendor/jquery.ui.widget.js"></script> + <script src="library/blueimp_upload/js/jquery.iframe-transport.js"></script> + <script src="library/blueimp_upload/js/jquery.fileupload.js"></script>'; + + $o .= "<script> var profile_uid = " . \App::$profile['profile_uid'] . "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n"; @@ -656,7 +709,7 @@ class Photos extends \Zotlabs\Web\Controller { '$uploader' => $ret['addon_text'], '$default' => (($ret['default_upload']) ? true : false), '$uploadurl' => $ret['post_url'], - '$submit' => t('Submit') + '$submit' => t('Upload') )); @@ -1052,7 +1105,7 @@ class Photos extends \Zotlabs\Web\Controller { } $comments = ''; - if(! count($r)) { + if(! $r) { if($observer && ($can_post || $can_comment)) { $commentbox = replace_macros($cmnt_tpl,array( '$return_path' => '', diff --git a/Zotlabs/Module/Ping.php b/Zotlabs/Module/Ping.php index 406e554d1..a3f6cdfec 100644 --- a/Zotlabs/Module/Ping.php +++ b/Zotlabs/Module/Ping.php @@ -140,7 +140,7 @@ class Ping extends \Zotlabs\Web\Controller { db_utcnow(), db_quoteinterval('3 MINUTE') ); - $discover_tab_on = ((get_config('system','disable_discover_tab') != 1) ? true : false); + $discover_tab_on = ((get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false) ? false : true); $notify_pubs = ((local_channel()) ? ($vnotify & VNOTIFY_PUBS) && $discover_tab_on : $discover_tab_on); if($notify_pubs) { @@ -279,8 +279,8 @@ class Ping extends \Zotlabs\Web\Controller { 'photo' => $tt['photo'], 'when' => relative_date($tt['created']), 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'), - 'b64mid' => $b64mid, - 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''), + 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'), + 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'), 'message' => $message ); } @@ -496,7 +496,7 @@ class Ping extends \Zotlabs\Web\Controller { $r = q("SELECT id, item_wall FROM item WHERE item_unseen = 1 and uid = %d $item_normal - AND author_xchan != '%s' $sql_extra ", + AND author_xchan != '%s'", intval(local_channel()), dbesc($ob_hash) ); diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php index 43106e3af..4235f0b97 100644 --- a/Zotlabs/Module/Profile.php +++ b/Zotlabs/Module/Profile.php @@ -109,7 +109,7 @@ class Profile extends \Zotlabs\Web\Controller { 'title' => 'oembed' ]); - $o .= advanced_profile($a); + $o .= advanced_profile(); call_hooks('profile_advanced',$o); return $o; diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php index 411518c61..45a606d5f 100644 --- a/Zotlabs/Module/Profile_photo.php +++ b/Zotlabs/Module/Profile_photo.php @@ -179,7 +179,10 @@ class Profile_photo extends \Zotlabs\Web\Controller { ); } - profiles_build_sync(local_channel()); + // set $send to false in profiles_build_sync() to return the data + // so that we only send one sync packet. + + $sync_profiles = profiles_build_sync(local_channel(),false); // We'll set the updated profile-photo timestamp even if it isn't the default profile, // so that browsers will do a cache update unconditionally @@ -201,7 +204,7 @@ class Profile_photo extends \Zotlabs\Web\Controller { $sync = attach_export_data($channel,$base_image['resource_id']); if($sync) - build_sync_packet($channel['channel_id'],array('file' => array($sync))); + build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles)); // Similarly, tell the nav bar to bypass the cache and update the avatar image. diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 0e6c2360f..c469a0eca 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -162,18 +162,16 @@ class Pubstream extends \Zotlabs\Web\Controller { $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : ''); - $simple_update = (($update) ? " and item.item_unseen = 1 " : ''); + $simple_update = (($_SESSION['loadtime']) ? " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' " : ''); - if($update && $_SESSION['loadtime']) - $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; if($load) $simple_update = ''; if($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; //logger('update: ' . $update . ' load: ' . $load); - + if($update) { $ordering = "commented"; @@ -214,17 +212,18 @@ class Pubstream extends \Zotlabs\Web\Controller { ); } else { - $r = q("SELECT distinct item.id AS item_id, $ordering FROM item + $r = q("SELECT distinct parent AS item_id, $ordering FROM item left join abook on item.author_xchan = abook.abook_xchan $net_query WHERE true $uids $item_normal_update - AND item.parent = item.id $simple_update + $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra3 $sql_extra $sql_nets $net_query2" ); } $_SESSION['loadtime'] = datetime_convert(); } + // Then fetch all the children of the parents that are on this page $parents_str = ''; $update_unseen = ''; @@ -254,7 +253,7 @@ class Pubstream extends \Zotlabs\Web\Controller { } // fake it - $mode = ('network'); + $mode = ('pubstream'); $o .= conversation($items,$mode,$update,$page_mode); diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php index 6cd79c952..6473317c7 100644 --- a/Zotlabs/Module/React.php +++ b/Zotlabs/Module/React.php @@ -6,15 +6,21 @@ namespace Zotlabs\Module; class React extends \Zotlabs\Web\Controller { function get() { + if(! local_channel()) return; + $sys = get_sys_channel(); + $channel = \App::get_channel(); + $postid = $_REQUEST['postid']; if(! $postid) return; $emoji = $_REQUEST['emoji']; + + if($_REQUEST['emoji']) { $i = q("select * from item where id = %d and uid = %d", @@ -22,10 +28,22 @@ class React extends \Zotlabs\Web\Controller { intval(local_channel()) ); - if(! $i) + if(! $i) { + $i = q("select * from item where id = %d and uid = %d", + intval($postid), + intval($sys['channel_id']) + ); + + if($i) { + $i = [ copy_of_pubitem($channel, $i[0]['mid']) ]; + $postid = (($i) ? $i[0]['id'] : 0); + } + } + + if(! $i) { return; + } - $channel = \App::get_channel(); $n = array(); $n['aid'] = $channel['channel_account_id']; @@ -40,8 +58,7 @@ class React extends \Zotlabs\Web\Controller { $x = item_store($n); - if(local_channel()) - retain_item($postid); + retain_item($postid); if($x['success']) { $nid = $x['item_id']; diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php index 95e3ca96f..deaee31bf 100644 --- a/Zotlabs/Module/Register.php +++ b/Zotlabs/Module/Register.php @@ -234,7 +234,11 @@ class Register extends \Zotlabs\Web\Controller { if(get_config('system','no_age_restriction')) $label_tos = sprintf( t('I accept the %s for this website'), $toslink); else - $label_tos = sprintf( t('I am over 13 years of age and accept the %s for this website'), $toslink); + $age = get_config('system','minimum_age'); + if(!$age) { + $age = 13; + } + $label_tos = sprintf( t('I am over %s years of age and accept the %s for this website'), $age, $toslink); $enable_tos = 1 - intval(get_config('system','no_termsofservice')); diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index 63370a141..5e9e88a6d 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -2,6 +2,8 @@ namespace Zotlabs\Module\Settings; +require_once('include/selectors.php'); + class Channel { @@ -148,7 +150,8 @@ class Channel { $defpermcat = ((x($_POST,'defpermcat')) ? notags(trim($_POST['defpermcat'])) : 'default'); $cal_first_day = (((x($_POST,'first_day')) && (intval($_POST['first_day']) == 1)) ? 1: 0); - $mailhost = ((array_key_exists('mailhost',$_POST)) ? notags(trim($_POST['mailhost'])) : ''); + $mailhost = ((array_key_exists('mailhost',$_POST)) ? notags(trim($_POST['mailhost'])) : ''); + $profile_assign = ((x($_POST,'profile_assign')) ? notags(trim($_POST['profile_assign'])) : ''); $pageflags = $channel['channel_pageflags']; @@ -203,7 +206,7 @@ class Channel { $vnotify += intval($_POST['vnotify11']); if(x($_POST,'vnotify12')) $vnotify += intval($_POST['vnotify12']); - if(x($_POST,'vnotify13') && (get_config('system', 'disable_discover_tab') != 1)) + if(x($_POST,'vnotify13')) $vnotify += intval($_POST['vnotify13']); $always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0; @@ -242,6 +245,7 @@ class Channel { set_pconfig(local_channel(),'system','cal_first_day',$cal_first_day); set_pconfig(local_channel(),'system','default_permcat',$defpermcat); set_pconfig(local_channel(),'system','email_notify_host',$mailhost); + set_pconfig(local_channel(),'system','profile_assign',$profile_assign); $r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d", dbesc($username), @@ -477,6 +481,8 @@ class Channel { $plugin = [ 'basic' => '', 'security' => '', 'notify' => '', 'misc' => '' ]; call_hooks('channel_settings',$plugin); + $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false; + $o .= replace_macros($stpl,array( '$ptitle' => t('Channel Settings'), @@ -515,6 +521,9 @@ class Channel { '$permissions' => t('Default Privacy Group'), '$permdesc' => t("\x28click to open/close\x29"), '$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))), + '$profseltxt' => t('Profile to assign new connections'), + '$profselect' => ((feature_enabled(local_channel(),'multi_profiles')) ? contact_profile_assign(get_pconfig(local_channel(),'system','profile_assign','')) : ''), + '$allow_cid' => acl2json($perm_defaults['allow_cid']), '$allow_gid' => acl2json($perm_defaults['allow_gid']), '$deny_cid' => acl2json($perm_defaults['deny_cid']), @@ -563,7 +572,7 @@ class Channel { '$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no), '$vnotify11' => array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no), '$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no), - '$vnotify13' => ((get_config('system', 'disable_discover_tab') != 1) ? array('vnotify13', t('Unseen public activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no) : array()), + '$vnotify13' => (($disable_discover_tab) ? array() : array('vnotify13', t('Unseen public activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no)), '$mailhost' => [ 'mailhost', t('Email notification hub (hostname)'), get_pconfig(local_channel(),'system','email_notify_host',\App::get_hostname()), sprintf( t('If your channel is mirrored to multiple hubs, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'),\App::get_hostname()) ], '$always_show_in_notices' => array('always_show_in_notices', t('Also show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no), diff --git a/Zotlabs/Module/Settings/Featured.php b/Zotlabs/Module/Settings/Featured.php index ebe2996d3..9c5a7b16c 100644 --- a/Zotlabs/Module/Settings/Featured.php +++ b/Zotlabs/Module/Settings/Featured.php @@ -11,15 +11,17 @@ class Featured { call_hooks('feature_settings_post', $_POST); if($_POST['affinity_slider-submit']) { - if(intval($_POST['affinity_cmax'])) { - set_pconfig(local_channel(),'affinity','cmax',intval($_POST['affinity_cmax'])); - } - if(intval($_POST['affinity_cmin'])) { - set_pconfig(local_channel(),'affinity','cmin',intval($_POST['affinity_cmin'])); - } - if(intval($_POST['affinity_cmax']) || intval($_POST['affinity_cmin'])) { - info( t('Affinity Slider settings updated.') . EOL); - } + $cmax = intval($_POST['affinity_cmax']); + if($cmax < 0 || $cmax > 99) + $cmax = 99; + $cmin = intval($_POST['affinity_cmin']); + if($cmin < 0 || $cmin > 99) + $cmin = 0; + set_pconfig(local_channel(),'affinity','cmin',$cmin); + set_pconfig(local_channel(),'affinity','cmax',$cmax); + + info( t('Affinity Slider settings updated.') . EOL); + } build_sync_packet(); @@ -40,12 +42,12 @@ class Featured { $cmax = intval(get_pconfig(local_channel(),'affinity','cmax')); $cmax = (($cmax) ? $cmax : 99); $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array( - '$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, '') + '$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, t('0-99 default 99')) )); $cmin = intval(get_pconfig(local_channel(),'affinity','cmin')); $cmin = (($cmin) ? $cmin : 0); $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array( - '$field' => array('affinity_cmin', t('Default minimum affinity level'), $cmin, '') + '$field' => array('affinity_cmin', t('Default minimum affinity level'), $cmin, t('0-99 - default 0')) )); $settings_addons .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( diff --git a/Zotlabs/Module/Subthread.php b/Zotlabs/Module/Subthread.php index dae8bf020..1a9caff6c 100644 --- a/Zotlabs/Module/Subthread.php +++ b/Zotlabs/Module/Subthread.php @@ -11,10 +11,13 @@ class Subthread extends \Zotlabs\Web\Controller { function get() { - if((! local_channel()) && (! remote_channel())) { + if(! local_channel()) { return; } + $sys = get_sys_channel(); + $channel = \App::get_channel(); + $item_id = ((argc() > 2) ? notags(trim(argv(2))) : 0); if(argv(1) === 'sub') @@ -23,10 +26,31 @@ class Subthread extends \Zotlabs\Web\Controller { $activity = ACTIVITY_UNFOLLOW; - $r = q("SELECT parent FROM item WHERE id = '%s'", - dbesc($item_id) + $i = q("select * from item where id = %d and uid = %d", + intval($item_id), + intval(local_channel()) ); - + + if(! $i) { + $i = q("select * from item where id = %d and uid = %d", + intval($postid), + intval($sys['channel_id']) + ); + + if($i) { + $i = [ copy_of_pubitem($channel, $i[0]['mid']) ]; + $item_id = (($i) ? $i[0]['id'] : 0); + } + } + + if(! $i) { + return; + } + + $r = q("SELECT parent FROM item WHERE id = %d", + intval($item_id) + ); + if($r) { $r = q("select * from item where id = parent and id = %d limit 1", dbesc($r[0]['parent']) diff --git a/Zotlabs/Module/Tagger.php b/Zotlabs/Module/Tagger.php index 98e901965..603a95f2b 100644 --- a/Zotlabs/Module/Tagger.php +++ b/Zotlabs/Module/Tagger.php @@ -11,10 +11,12 @@ class Tagger extends \Zotlabs\Web\Controller { function get() { - if(! local_channel() && ! remote_channel()) { + if(! local_channel()) { return; } + $sys = get_sys_channel(); + $observer_hash = get_observer_hash(); //strip html-tags $term = notags(trim($_GET['term'])); @@ -26,9 +28,29 @@ class Tagger extends \Zotlabs\Web\Controller { logger('tagger: tag ' . $term . ' item ' . $item_id); - - $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = '%s' and uid = %d LIMIT 1", - dbesc($item_id), + $r = q("select * from item where id = %d and uid = %d limit 1", + intval($item_id), + intval(local_channel()) + ); + + if(! $r) { + $r = q("select * from item where id = %d and uid = %d limit 1", + intval($item_id), + intval($sys['channel_id']) + ); + if($r) { + $r = [ copy_of_pubitem($channel, $i[0]['mid']) ]; + $item_id = (($r) ? $r[0]['id'] : 0); + } + } + + if(! $r) { + notice( t('Post not found.') . EOL); + return; + } + + $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = %d and uid = %d LIMIT 1", + intval($item_id), intval(local_channel()) ); diff --git a/Zotlabs/Module/Update.php b/Zotlabs/Module/Update.php new file mode 100644 index 000000000..b3252f8b9 --- /dev/null +++ b/Zotlabs/Module/Update.php @@ -0,0 +1,43 @@ +<?php +namespace Zotlabs\Module; + + +class Update extends \Zotlabs\Web\Controller { + + function get() { + + $profile_uid = intval($_GET['p']); + + // it's probably safe to do this for all modules and not just a limited subset, + // but it needs to be verified. + + if((! $profile_uid) && in_array(argv(1),['display','search','pubstream','home'])) + $profile_uid = (-1); + + if(argc() < 2) { + killme(); + } + + // These modules don't have a completely working liveUpdate implementation currently + + if(in_array(strtolower(argv(1)),['articles','cards'])) + killme(); + + $module = "\\Zotlabs\\Module\\" . ucfirst(argv(1)); + $load = (((argc() > 2) && (argv(2) == 'load')) ? 1 : 0); + + $mod = new $module; + + header("Content-type: text/html"); + + \App::$argv = [ argv(1) ]; + \App::$argc = 1; + + echo "<!DOCTYPE html><html><body><section>\r\n"; + echo $mod->get($profile_uid, $load); + echo "</section></body></html>\r\n"; + + killme(); + + } +} diff --git a/Zotlabs/Module/Update_cards.php b/Zotlabs/Module/Update_cards.php deleted file mode 100644 index bb87357e8..000000000 --- a/Zotlabs/Module/Update_cards.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php - -namespace Zotlabs\Module; - -/** - * Module: update_profile - * Purpose: AJAX synchronisation of profile page - * - */ - - -class Update_cards extends \Zotlabs\Web\Controller { - -function get() { - - $profile_uid = intval($_GET['p']); - $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); - - header("Content-type: text/html"); - echo "<!DOCTYPE html><html><body><section></section></body></html>\r\n"; - - killme(); - - - $mod = new Cards(); - - $text = $mod->get($profile_uid,$load); - - /** - * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well - */ - - echo str_replace("\t",' ',$text); - echo (($_GET['msie'] == 1) ? '</div>' : '</section>'); - echo "</body></html>\r\n"; - killme(); - -} -} diff --git a/Zotlabs/Module/Update_channel.php b/Zotlabs/Module/Update_channel.php deleted file mode 100644 index 46ad19805..000000000 --- a/Zotlabs/Module/Update_channel.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php - -namespace Zotlabs\Module; - -/** - * Module: update_profile - * Purpose: AJAX synchronisation of profile page - * - */ - - -class Update_channel extends \Zotlabs\Web\Controller { - -function get() { - - $profile_uid = intval($_GET['p']); - $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); - - header("Content-type: text/html"); - echo "<!DOCTYPE html><html><body>\r\n"; - - /** - * We can remove this hack once Internet Explorer recognises HTML5 natively - */ - - echo (($_GET['msie'] == 1) ? '<div>' : '<section>'); - - /** - * - * Grab the page inner contents by calling the content function from the profile module directly, - * but move any image src attributes to another attribute name. This is because - * some browsers will prefetch all the images for the page even if we don't need them. - * The only ones we need to fetch are those for new page additions, which we'll discover - * on the client side and then swap the image back. - * - */ - - $mod = new Channel(); - - $text = $mod->get($profile_uid,$load); - - $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; - $replace = "<img\${1} dst=\"\${2}\""; -// $text = preg_replace($pattern, $replace, $text); - -/* - if(! $load) { - $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); - } -*/ - - /** - * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well - */ - - echo str_replace("\t",' ',$text); - echo (($_GET['msie'] == 1) ? '</div>' : '</section>'); - echo "</body></html>\r\n"; - killme(); - -} -} diff --git a/Zotlabs/Module/Update_display.php b/Zotlabs/Module/Update_display.php deleted file mode 100644 index b2c6a56f5..000000000 --- a/Zotlabs/Module/Update_display.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php -namespace Zotlabs\Module; - -// See update_profile.php for documentation - -require_once('include/group.php'); - - -class Update_display extends \Zotlabs\Web\Controller { - - function get() { - - $profile_uid = intval($_GET['p']); - if(! $profile_uid) - $profile_uid = (-1); - $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); - header("Content-type: text/html"); - echo "<!DOCTYPE html><html><body>\r\n"; - echo (($_GET['msie'] == 1) ? '<div>' : '<section>'); - - $mod = new Display(); - $text = $mod->get($profile_uid, $load); - - echo str_replace("\t",' ',$text); - echo (($_GET['msie'] == 1) ? '</div>' : '</section>'); - echo "</body></html>\r\n"; - - killme(); - - } - -} diff --git a/Zotlabs/Module/Update_home.php b/Zotlabs/Module/Update_home.php deleted file mode 100644 index 0f699482e..000000000 --- a/Zotlabs/Module/Update_home.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php -namespace Zotlabs\Module; - -// See update_profile.php for documentation - -class Update_home extends \Zotlabs\Web\Controller { - - function get() { - - $profile_uid = ((intval($_GET['p'])) ? intval($_GET['p']) : (-1)); - $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); - header("Content-type: text/html"); - echo "<!DOCTYPE html><html><body>\r\n"; - echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '<div>' : '<section>'); - - $mod = new Home(); - $text = $mod->get($profile_uid, $load); - - $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; - $replace = "<img\${1} dst=\"\${2}\""; - // $text = preg_replace($pattern, $replace, $text); - /* - if(! $load) { - $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); - } - */ - echo str_replace("\t",' ',$text); - echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '</div>' : '</section>'); - echo "</body></html>\r\n"; - // logger('update_home: ' . $text); - killme(); - - } -} diff --git a/Zotlabs/Module/Update_network.php b/Zotlabs/Module/Update_network.php deleted file mode 100644 index c27b7614a..000000000 --- a/Zotlabs/Module/Update_network.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php -namespace Zotlabs\Module; - -// See update_profile.php for documentation - -require_once('include/group.php'); - -class Update_network extends \Zotlabs\Web\Controller { - - function get() { - - $profile_uid = intval($_GET['p']); - $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); - header("Content-type: text/html"); - echo "<!DOCTYPE html><html><body>\r\n"; - echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '<div>' : '<section>'); - - $mod = new Network(); - $text = $mod->get($profile_uid, $load); - - $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; - $replace = "<img\${1} dst=\"\${2}\""; - // $text = preg_replace($pattern, $replace, $text); - /* - if(! $load) { - $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); - } - */ - echo str_replace("\t",' ',$text); - echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '</div>' : '</section>'); - echo "</body></html>\r\n"; - // logger('update_network: ' . $text); - killme(); - - } -} diff --git a/Zotlabs/Module/Update_pubstream.php b/Zotlabs/Module/Update_pubstream.php deleted file mode 100644 index 952b48df3..000000000 --- a/Zotlabs/Module/Update_pubstream.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php -namespace Zotlabs\Module; - -// See update_profile.php for documentation - - -class Update_pubstream extends \Zotlabs\Web\Controller { - - function get() { - - $profile_uid = ((intval($_GET['p'])) ? intval($_GET['p']) : (-1)); - $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); - header("Content-type: text/html"); - echo "<!DOCTYPE html><html><body>\r\n"; - echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '<div>' : '<section>'); - - $mod = new Pubstream(); - $text = $mod->get($profile_uid, $load); - - $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; - $replace = "<img\${1} dst=\"\${2}\""; - // $text = preg_replace($pattern, $replace, $text); - /* - if(! $load) { - $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); - } - */ - echo str_replace("\t",' ',$text); - echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '</div>' : '</section>'); - echo "</body></html>\r\n"; - killme(); - - } -} diff --git a/Zotlabs/Module/Update_search.php b/Zotlabs/Module/Update_search.php deleted file mode 100644 index 4491f40f4..000000000 --- a/Zotlabs/Module/Update_search.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -namespace Zotlabs\Module; - -/** - * Module: update_profile - * Purpose: AJAX synchronisation of search page - * - */ - - -class Update_search extends \Zotlabs\Web\Controller { - - function get() { - - $profile_uid = intval($_GET['p']); - if(! $profile_uid) - $profile_uid = (-1); - - $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0); - - header("Content-type: text/html"); - echo "<!DOCTYPE html><html><body>\r\n"; - - /** - * We can remove this hack once Internet Explorer recognises HTML5 natively - */ - - echo (($_GET['msie'] == 1) ? '<div>' : '<section>'); - - /** - * - * Grab the page inner contents by calling the content function from the profile module directly, - * but move any image src attributes to another attribute name. This is because - * some browsers will prefetch all the images for the page even if we don't need them. - * The only ones we need to fetch are those for new page additions, which we'll discover - * on the client side and then swap the image back. - * - */ - - $mod = new Search(); - $text = $mod->get($profile_uid,$load); - - $pattern = "/<img([^>]*) src=\"([^\"]*)\"/"; - $replace = "<img\${1} dst=\"\${2}\""; - // $text = preg_replace($pattern, $replace, $text); - /* - if(! $load) { - $replace = '<br />' . t('[Embedded content - reload page to view]') . '<br />'; - $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; - $text = preg_replace($pattern, $replace, $text); - $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; - $text = preg_replace($pattern, $replace, $text); - } - */ - /** - * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well - */ - - echo str_replace("\t",' ',$text); - echo (($_GET['msie'] == 1) ? '</div>' : '</section>'); - echo "</body></html>\r\n"; - killme(); - - } -} diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php index e001ad929..2250e6e44 100644 --- a/Zotlabs/Module/Wall_attach.php +++ b/Zotlabs/Module/Wall_attach.php @@ -41,10 +41,12 @@ class Wall_attach extends \Zotlabs\Web\Controller { $matches = []; $partial = false; - $x = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); - if($x) { - // logger('Content-Range: ' . print_r($matches,true)); - $partial = true; + if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); + if($pm) { + // logger('Content-Range: ' . print_r($matches,true)); + $partial = true; + } } if($partial) { diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php index 2d2d8e2b7..ae543eb98 100644 --- a/Zotlabs/Module/Wiki.php +++ b/Zotlabs/Module/Wiki.php @@ -293,31 +293,43 @@ class Wiki extends \Zotlabs\Web\Controller { $p = Zlib\NativeWikiPage::get_page_content(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName)); } if(! ($p && $p['success'])) { + $x = new \Zotlabs\Widget\Wiki_pages(); + + $html = $x->create_missing_page([ + 'resource_id' => $resource_id, + 'channel_id' => $owner['channel_id'], + 'channel_address' => $owner['channel_address'], + 'refresh' => true + ]); + //json_return_and_die(array('pages' => $page_list_html, 'message' => '', 'success' => true)); notice( t('Error retrieving page content') . EOL); - goaway(z_root() . '/' . argv(0) . '/' . argv(1) ); + //goaway(z_root() . '/' . argv(0) . '/' . argv(1) ); + $renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName); + $showPageControls = $wiki_editor; } - - $mimeType = $p['pageMimeType']; - - $sampleContent = (($mimeType == 'text/bbcode') ? '[h3]' . t('New page') . '[/h3]' : '### ' . t('New page')); - if($mimeType === 'text/plain') - $sampleContent = t('New page'); - - $content = (($p['content'] == '') ? $sampleContent : $p['content']); - - // Render the Markdown-formatted page content in HTML - if($mimeType == 'text/bbcode') { - $renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName); - } - elseif($mimeType === 'text/plain') { - $renderedContent = str_replace(["\n",' ',"\t"],[EOL,' ',' '],htmlentities($content,ENT_COMPAT,'UTF-8',false)); - } - elseif($mimeType === 'text/markdown') { - $content = Zlib\MarkdownSoap::unescape($content); - $html = Zlib\NativeWikiPage::generate_toc(zidify_text(MarkdownExtra::defaultTransform(Zlib\NativeWikiPage::bbcode($content)))); - $renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName); - } - $showPageControls = $wiki_editor; + else { + $mimeType = $p['pageMimeType']; + + $sampleContent = (($mimeType == 'text/bbcode') ? '[h3]' . t('New page') . '[/h3]' : '### ' . t('New page')); + if($mimeType === 'text/plain') + $sampleContent = t('New page'); + + $content = (($p['content'] == '') ? $sampleContent : $p['content']); + + // Render the Markdown-formatted page content in HTML + if($mimeType == 'text/bbcode') { + $renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName); + } + elseif($mimeType === 'text/plain') { + $renderedContent = str_replace(["\n",' ',"\t"],[EOL,' ',' '],htmlentities($content,ENT_COMPAT,'UTF-8',false)); + } + elseif($mimeType === 'text/markdown') { + $content = Zlib\MarkdownSoap::unescape($content); + $html = Zlib\NativeWikiPage::generate_toc(zidify_text(MarkdownExtra::defaultTransform(Zlib\NativeWikiPage::bbcode($content)))); + $renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName); + } + $showPageControls = $wiki_editor; + } break; // default: // Strip the extraneous URL components // goaway('/' . argv(0) . '/' . argv(1) . '/' . $wikiUrlName . '/' . $pageUrlName); @@ -430,11 +442,15 @@ class Wiki extends \Zotlabs\Web\Controller { goaway('/' . argv(0) . '/' . $nick . '/'); } $wiki = array(); + + // backslashes won't work well in the javascript functions + $name = str_replace('\\','',$_POST['wikiName']); + // Generate new wiki info from input name $wiki['postVisible'] = ((intval($_POST['postVisible'])) ? 1 : 0); - $wiki['rawName'] = $_POST['wikiName']; - $wiki['htmlName'] = escape_tags($_POST['wikiName']); - $wiki['urlName'] = urlencode(urlencode($_POST['wikiName'])); + $wiki['rawName'] = $name; + $wiki['htmlName'] = escape_tags($name); + $wiki['urlName'] = urlencode(urlencode($name)); $wiki['mimeType'] = $_POST['mimeType']; $wiki['typelock'] = $_POST['typelock']; @@ -555,9 +571,14 @@ class Wiki extends \Zotlabs\Web\Controller { } $name = $_POST['pageName']; //Get new page name - if(urlencode(escape_tags($_POST['pageName'])) === '') { - json_return_and_die(array('message' => 'Error creating page. Invalid name.', 'success' => false)); + + // backslashes won't work well in the javascript functions + $name = str_replace('\\','',$name); + + if(urlencode(escape_tags($name)) === '') { + json_return_and_die(array('message' => 'Error creating page. Invalid name (' . print_r($_POST,true) . ').', 'success' => false)); } + $page = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id, $mimetype); if($page['item_id']) { @@ -626,7 +647,7 @@ class Wiki extends \Zotlabs\Web\Controller { logger('Wiki write permission denied. ' . EOL); json_return_and_die(array('success' => false)); } - + $saved = Zlib\NativeWikiPage::save_page(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName, 'content' => $content)); if($saved['success']) { @@ -758,7 +779,7 @@ class Wiki extends \Zotlabs\Web\Controller { if ((argc() === 4) && (argv(2) === 'rename') && (argv(3) === 'page')) { $resource_id = $_POST['resource_id']; $pageUrlName = $_POST['oldName']; - $pageNewName = $_POST['newName']; + $pageNewName = str_replace('\\','',$_POST['newName']); if ($pageUrlName === 'Home') { json_return_and_die(array('message' => 'Cannot rename Home','success' => false)); } diff --git a/Zotlabs/Render/Comanche.php b/Zotlabs/Render/Comanche.php index cd06e11a8..fb400b6fe 100644 --- a/Zotlabs/Render/Comanche.php +++ b/Zotlabs/Render/Comanche.php @@ -534,7 +534,12 @@ class Comanche { require_once('widget/' . $clsname . '/' . $clsname . '.php'); elseif(file_exists('Zotlabs/Widget/' . $clsname . '.php')) require_once('Zotlabs/Widget/' . $clsname . '.php'); - + else { + $pth = theme_include($clsname . '.php'); + if($pth) { + require_once($pth); + } + } if(class_exists($nsname)) { $x = new $nsname; $f = 'widget'; @@ -550,11 +555,13 @@ class Comanche { require_once('widget/' . trim($name) . '.php'); elseif(file_exists('widget/' . trim($name) . '/' . trim($name) . '.php')) require_once('widget/' . trim($name) . '/' . trim($name) . '.php'); - } - else { - $theme_widget = $func . '.php'; - if((! function_exists($func)) && theme_include($theme_widget)) - require_once(theme_include($theme_widget)); + + if(! function_exists($func)) { + $theme_widget = $func . '.php'; + if(theme_include($theme_widget)) { + require_once(theme_include($theme_widget)); + } + } } if(function_exists($func)) diff --git a/Zotlabs/Render/SmartyInterface.php b/Zotlabs/Render/SmartyInterface.php index 0e3a47c2f..9c9a501c0 100755 --- a/Zotlabs/Render/SmartyInterface.php +++ b/Zotlabs/Render/SmartyInterface.php @@ -2,8 +2,6 @@ namespace Zotlabs\Render; -require_once('library/Smarty/libs/Smarty.class.php'); - class SmartyInterface extends \Smarty { public $filename; diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php index dd3067cf8..c21b68971 100644 --- a/Zotlabs/Storage/Browser.php +++ b/Zotlabs/Storage/Browser.php @@ -12,7 +12,7 @@ use Sabre\DAV; * * @extends \\Sabre\\DAV\\Browser\\Plugin * - * @link http://github.com/friendica/red + * @link http://github.com/redmatrix/hubzilla * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) */ class Browser extends DAV\Browser\Plugin { @@ -373,8 +373,6 @@ class Browser extends DAV\Browser\Plugin { if(strpos($path,$special) === 0) $path = trim(substr($path,$count),'/'); - $info = t('Please use DAV to upload large (video, audio) files.<br>See <a class="zrl" href="help/member/member_guide#Cloud_Desktop_Clients">Cloud Desktop Clients</a>'); - $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array( '$folder_header' => t('Create new folder'), @@ -382,7 +380,6 @@ class Browser extends DAV\Browser\Plugin { '$upload_header' => t('Upload file'), '$upload_submit' => t('Upload'), '$quota' => $quota, - '$info' => $info, '$channick' => $this->auth->owner_nick, '$aclselect' => $aclselect, '$allow_cid' => acl2json($channel_acl['allow_cid']), diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php index 45df9ddd5..510d463c1 100644 --- a/Zotlabs/Storage/Directory.php +++ b/Zotlabs/Storage/Directory.php @@ -16,7 +16,7 @@ use Sabre\DAV; * @link http://github.com/friendica/red * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) */ -class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { +class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMoveTarget { /** * @brief The path inside /cloud @@ -457,6 +457,22 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { return false; } + + public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) { + + if(! $this->auth->owner_id) { + return false; + } + + if(! ($sourceNode->data && $sourceNode->data->hash)) { + return false; + } + + return attach_move($this->auth->owner_id, $sourceNode->data->hash, $this->folder_hash); + + } + + /** * @todo add description of what this function does. * @@ -675,7 +691,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { } $prefix = ''; - $suffix = ''; + $suffix = ' order by is_dir desc, filename asc '; $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix", dbesc($folder), diff --git a/Zotlabs/Thumbs/Epubthumb.php b/Zotlabs/Thumbs/Epubthumb.php index 4213b5267..22f1a5e8f 100644 --- a/Zotlabs/Thumbs/Epubthumb.php +++ b/Zotlabs/Thumbs/Epubthumb.php @@ -2,36 +2,54 @@ namespace Zotlabs\Thumbs; -require_once('library/epub-meta/epub.php'); +require_once 'library/epub-meta/epub.php'; +/** + * @brief Thumbnail creation for epub files. + * + */ class Epubthumb { + /** + * @brief Match for application/epub+zip. + * + * @param string $type MimeType + * @return boolean + */ function Match($type) { return(($type === 'application/epub+zip') ? true : false ); } - function Thumb($attach,$preview_style,$height = 300, $width = 300) { + /** + * @brief + * + * @param array $attach + * @param number $preview_style unused + * @param number $height (optional) default 300 + * @param number $width (optional) default 300 + */ + function Thumb($attach, $preview_style, $height = 300, $width = 300) { $photo = false; - $ep = new \Epub(dbunescbin($attach['content'])); + $ep = new \EPub(dbunescbin($attach['content'])); $data = $ep->Cover(); if($data['found']) { $photo = $data['data']; } - if($photo) { + if($photo) { $image = imagecreatefromstring($photo); - $dest = imagecreatetruecolor( $width, $height ); - $srcwidth = imagesx($image); - $srcheight = imagesy($image); + $dest = imagecreatetruecolor($width, $height); + $srcwidth = imagesx($image); + $srcheight = imagesy($image); - imagealphablending($dest, false); + imagealphablending($dest, false); imagesavealpha($dest, true); - imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight); - imagedestroy($image); - imagejpeg($dest,dbunescbin($attach['content']) . '.thumb'); + imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight); + imagedestroy($image); + imagejpeg($dest, dbunescbin($attach['content']) . '.thumb'); } } } diff --git a/Zotlabs/Thumbs/Video.php b/Zotlabs/Thumbs/Video.php index 5e09ef9a3..ff4d10a36 100644 --- a/Zotlabs/Thumbs/Video.php +++ b/Zotlabs/Thumbs/Video.php @@ -32,12 +32,25 @@ class Video { fclose($ostream); } + /* + * Note: imagick convert may try to call 'ffmpeg' (or other conversion utilities) under + * the covers for this particular operation. If this is not installed or not in the path + * for the web server user, errors may be reported in the web server logs. + */ + + + $ffmpeg = trim(shell_exec('which ffmpeg')); + if($ffmpeg) { + logger('ffmpeg not found in path. Video thumbnails may fail.'); + } + $imagick_path = get_config('system','imagick_convert_path'); if($imagick_path && @file_exists($imagick_path)) { $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -thumbnail ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile); // logger('imagick thumbnail command: ' . $cmd); - exec($cmd); + /** @scrutinizer ignore-unhandled */ + @exec($cmd); if(! file_exists($outfile)) { logger('imagick scale failed.'); @@ -46,7 +59,7 @@ class Video { @rename($outfile,$file . '.thumb'); } } - + @unlink($tmpfile); } } diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php index 1c66b8cf4..63033ce5e 100644 --- a/Zotlabs/Web/HTTPSig.php +++ b/Zotlabs/Web/HTTPSig.php @@ -117,7 +117,7 @@ class HTTPSig { logger('verified: ' . $x, LOGGER_DEBUG); - if($x === false) + if(! $x) return $result; if(! $spoofable) @@ -237,7 +237,7 @@ class HTTPSig { $fields = '(request-target)'; } - if(head) { + if($head) { foreach($head as $k => $v) { $headers .= strtolower($k) . ': ' . trim($v) . "\n"; if($fields) diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php index 12ef315d4..a6b780cdc 100644 --- a/Zotlabs/Web/Router.php +++ b/Zotlabs/Web/Router.php @@ -265,7 +265,7 @@ class Router { if(! \App::$error) { $arr = array('content' => \App::$page['content'], 'replace' => false); call_hooks(\App::$module . '_mod_content', $arr); - \App::$page['content'] = $arr['content']; + if(! $arr['replace']) { if($this->controller && method_exists($this->controller,'get')) { $arr = array('content' => $this->controller->get()); @@ -276,8 +276,8 @@ class Router { } } call_hooks(\App::$module . '_mod_aftercontent', $arr); - \App::$page['content'] .= $arr['content']; + \App::$page['content'] = (($arr['replace']) ? $arr['content'] : \App::$page['content'] . $arr['content']); } } } -}
\ No newline at end of file +} diff --git a/Zotlabs/Widget/Affinity.php b/Zotlabs/Widget/Affinity.php index 439ba1f33..4fb2874ae 100644 --- a/Zotlabs/Widget/Affinity.php +++ b/Zotlabs/Widget/Affinity.php @@ -9,15 +9,11 @@ class Affinity { if(! local_channel()) return ''; - // Get default cmin value from pconfig, but allow GET parameter to override - $cmin = intval(get_pconfig(local_channel(),'affinity','cmin')); - $cmin = (($cmin) ? $cmin : 0); - $cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $cmin); - - // Get default cmax value from pconfig, but allow GET parameter to override - $cmax = intval(get_pconfig(local_channel(),'affinity','cmax')); - $cmax = (($cmax) ? $cmax : 99); - $cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $cmax); + $default_cmin = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0); + $default_cmax = ((feature_enabled(local_channel(),'affinity')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99); + + $cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $default_cmin); + $cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $default_cmax); if(feature_enabled(local_channel(),'affinity')) { diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php index 305869706..9bfa9742a 100644 --- a/Zotlabs/Widget/Categories.php +++ b/Zotlabs/Widget/Categories.php @@ -13,8 +13,14 @@ class Categories { if(($cards) && (! feature_enabled(\App::$profile['profile_uid'],'cards'))) return ''; + $articles = ((array_key_exists('articles',$arr) && $arr['articles']) ? true : false); + + if(($articles) && (! feature_enabled(\App::$profile['profile_uid'],'articles'))) + return ''; + + if((! \App::$profile['profile_uid']) - || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),(($cards) ? 'view_pages' : 'view_stream')))) { + || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),(($cards || $articles) ? 'view_pages' : 'view_stream')))) { return ''; } @@ -25,6 +31,8 @@ class Categories { if($cards) return cardcategories_widget($srchurl, $cat); + elseif($articles) + return articlecategories_widget($srchurl, $cat); else return categories_widget($srchurl, $cat); diff --git a/Zotlabs/Widget/Cdav.php b/Zotlabs/Widget/Cdav.php index 60a860f93..589f915c5 100644 --- a/Zotlabs/Widget/Cdav.php +++ b/Zotlabs/Widget/Cdav.php @@ -63,9 +63,10 @@ class Cdav { $sharees = []; $share_displayname = []; + foreach($invites as $invite) { if(strpos($invite->href, 'mailto:') !== false) { - $sharee = channelx_by_hash(substr($invite->href, 7)); + $sharee = channelx_by_nick(substr($invite->principal, 11)); $sharees[] = [ 'name' => $sharee['channel_name'], 'access' => (($invite->access == 3) ? ' (RW)' : ' (R)'), @@ -173,4 +174,4 @@ class Cdav { } } -}
\ No newline at end of file +} diff --git a/Zotlabs/Widget/Forums.php b/Zotlabs/Widget/Forums.php index 91b987746..0b90b9740 100644 --- a/Zotlabs/Widget/Forums.php +++ b/Zotlabs/Widget/Forums.php @@ -11,8 +11,8 @@ class Forums { $o = ''; - if(is_array($arr) && array_key_exists('limit',$arr)) - $limit = " limit " . intval($limit) . " "; + if(is_array($arr) && array_key_exists('limit',$arr) && intval($arr['limit']) >= 0) + $limit = " limit " . intval($arr['limit']) . " "; else $limit = ''; diff --git a/Zotlabs/Widget/Hq_controls.php b/Zotlabs/Widget/Hq_controls.php new file mode 100644 index 000000000..0caa54a1a --- /dev/null +++ b/Zotlabs/Widget/Hq_controls.php @@ -0,0 +1,26 @@ +<?php + +namespace Zotlabs\Widget; + +class Hq_controls { + + function widget($arr) { + + if (! local_channel()) + return; + + return replace_macros(get_markup_template('hq_controls.tpl'), + [ + '$title' => t('HQ Control Panel'), + '$menu' => [ + 'create' => [ + 'label' => t('Create a new post'), + 'id' => 'jot-toggle', + 'href' => '#', + 'class' => '' + ] + ] + ] + ); + } +} diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php index 191f2afb6..5a0c1f3d5 100644 --- a/Zotlabs/Widget/Notifications.php +++ b/Zotlabs/Widget/Notifications.php @@ -20,8 +20,10 @@ class Notifications { 'label' => t('View your network activity') ], 'markall' => [ - 'url' => '#', 'label' => t('Mark all notifications read') + ], + 'filter' => [ + 'label' => t('Show new posts only') ] ]; @@ -36,8 +38,10 @@ class Notifications { 'label' => t('View your home activity') ], 'markall' => [ - 'url' => '#', 'label' => t('Mark all notifications seen') + ], + 'filter' => [ + 'label' => t('Show new posts only') ] ]; @@ -52,7 +56,6 @@ class Notifications { 'label' => t('View your private mails') ], 'markall' => [ - 'url' => '#', 'label' => t('Mark all messages seen') ] ]; @@ -68,7 +71,6 @@ class Notifications { 'label' => t('View events') ], 'markall' => [ - 'url' => '#', 'label' => t('Mark all events seen') ] ]; @@ -104,7 +106,6 @@ class Notifications { 'label' => t('View all notices') ], 'markall' => [ - 'url' => '#', 'label' => t('Mark all notices seen') ] ]; @@ -132,8 +133,10 @@ class Notifications { 'label' => t('View the public stream') ], 'markall' => [ - 'url' => '#', 'label' => t('Mark all notifications seen') + ], + 'filter' => [ + 'label' => t('Show new posts only') ] ]; } @@ -141,7 +144,8 @@ class Notifications { $o = replace_macros(get_markup_template('notifications_widget.tpl'), array( '$module' => \App::$module, '$notifications' => $notifications, - '$loading' => t('Loading...') + '$no_notifications' => t('Sorry, you have got no notifications at the moment'), + '$loading' => t('Loading') )); return $o; diff --git a/Zotlabs/Widget/Wiki_pages.php b/Zotlabs/Widget/Wiki_pages.php index 39d4b1717..ecd2c9100 100644 --- a/Zotlabs/Widget/Wiki_pages.php +++ b/Zotlabs/Widget/Wiki_pages.php @@ -5,6 +5,42 @@ namespace Zotlabs\Widget; class Wiki_pages { + function create_missing_page($arr) { + if(argc() < 4) + return; + + $c = channelx_by_nick(argv(1)); + $w = \Zotlabs\Lib\NativeWiki::exists_by_name($c['channel_id'],urldecode(argv(2))); + $arr = array( + 'resource_id' => $w['resource_id'], + 'channel_id' => $c['channel_id'], + 'channel_address' => $c['channel_address'], + 'refresh' => false + ); + + $can_create = perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'write_wiki'); + + $can_delete = ((local_channel() && (local_channel() == \App::$profile['uid'])) ? true : false); + $pageName = addslashes(escape_tags(urldecode(argv(3)))); + + return replace_macros(get_markup_template('wiki_page_not_found.tpl'), array( + '$resource_id' => $arr['resource_id'], + '$channel_address' => $arr['channel_address'], + '$wikiname' => $wikiname, + '$canadd' => $can_create, + '$candel' => $can_delete, + '$addnew' => t('Add new page'), + '$typelock' => $typelock, + '$lockedtype' => $w['mimeType'], + '$mimetype' => mimetype_select(0,$w['mimeType'], + [ 'text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]), + '$pageName' => array('missingPageName', 'Create Page' , $pageName), + '$refresh' => $arr['refresh'], + '$options' => t('Options'), + '$submit' => t('Submit') + )); + } + function widget($arr) { if(argc() < 3) |