diff options
Diffstat (limited to 'Zotlabs/Lib')
-rw-r--r-- | Zotlabs/Lib/Apps.php | 3 | ||||
-rw-r--r-- | Zotlabs/Lib/Enotify.php | 2 | ||||
-rw-r--r-- | Zotlabs/Lib/Img_filesize.php | 122 | ||||
-rw-r--r-- | Zotlabs/Lib/MarkdownSoap.php | 65 | ||||
-rw-r--r-- | Zotlabs/Lib/NativeWikiPage.php | 4 | ||||
-rw-r--r-- | Zotlabs/Lib/Permcat.php | 78 | ||||
-rw-r--r-- | Zotlabs/Lib/ThreadItem.php | 21 | ||||
-rw-r--r-- | Zotlabs/Lib/ThreadStream.php | 17 |
8 files changed, 269 insertions, 43 deletions
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); |