diff options
16 files changed, 384 insertions, 371 deletions
diff --git a/doc/to_do_code.bb b/doc/to_do_code.bb index 89b31f46d..f4c685063 100644 --- a/doc/to_do_code.bb +++ b/doc/to_do_code.bb @@ -3,73 +3,38 @@ We need much more than this, but here are areas where developers can help. Please edit this page when items are finished. Another place for developers to start is with the issues list.
[li]Documentation - see Red Documentation Project To-Do List[/li]
-
[li]Include TOS link in registration/verification email[/li]
-
[li]Finish the anti-spam bayesian engine[/li]
-
[li]If DAV folders exist, add an option to the Settings page to set a default folder for attachment uploads.[/li]
-
[li]Integrate the "open site" list with the register page[/li]
-
[li]implement oembed provider interface[/li]
-
[li]refactor the oembed client interface so that we can safely sandbox remote content[/li]
-
[li]implement openid server interface[/li]
-
[li]Write more webpage layouts[/li]
-
[li]Write more webpage widgets[/li]
-
[li](Advanced) create a UI for building Comanche pages[/li]
-
-[li]templatise and translate the Web interface to webDAV[/li]
-
[li]Extend WebDAV to provide desktop access to photo albums[/li]
-
[li]External post connectors - create standard interface[/li]
-
[li]External post connectors, add popular services[/li]
-
[li]service classes - provide a pluggable subscription payment gateway for premium accounts[/li]
-
[li]service classes - account overview page showing resources consumed by channel. With special consideration this page can also be accessed at a meta level by the site admin to drill down on problematic accounts/channels.[/li]
-
[li]Events module - fix permissions on events, and provide JS translation support for the calendar overview; integrate with calDAV[/li]
-
[li]Events module - event followups and RSVP[/li]
-
[li]Uploads - integrate #^[url=https://github.com/blueimp/jQuery-File-Upload]https://github.com/blueimp/jQuery-File-Upload[/url][/li]
-
[li]Import/export - include events, things, etc.[/li]
-
[li]Import channel from Diaspora/Friendica[/li]
-
[li]MediaGoblin photo "crosspost" connector[/li]
-
[li]Create management page/UI for extensible profile fields[/li]
-
[li]Create interface to include/exclude and re-order standard profile fields[/li]
-
[li]Provide a mechanism to share page design elements in posts (just like apps)[/li]
-
[li]App taxonomy[/li]
-
[li]Customisable App collection pages[/li]
-
[li]replace the tinymce visual editor and/or make the visual editor pluggable and responsive to different output formats. We probably want library/bbedit for bbcode. This needs a fair bit of work to catch up with our "enhanced bbcode", but start with images, links, bold and highlight and work from there.[/li]
-
[li]Photos module - turn photos into normal conversations and fix tagging[/li]
-
[li]Provide RSS feed support which look like channels (in matrix only - copyright issues)[/li]
-
[li]Create mobile clients for the top platforms - which involves extending the API so that we can do stuff far beyond the current crop of Twitter/Statusnet clients. Ditto for mobile themes. We can probably use something like the Friendica Android app as a base to start from.[/li]
-
[li]Implement owned and exchangeable "things".[/li]
-
[li]Family Account creation - using service classes (an account holder can create a certain number of sub-accounts which are all tied to their subscription - if the subscription lapses they all go away).[/li]
-
[li]Put mod_admin under Comanche[/li]
In many cases some of the work has already been started and code exists so that you needn't start from scratch. Please contact one of the developer channels like Channel One (one@zothub.com) before embarking and we can tell you what we already have and provide some insights on how we envision these features fitting together.
diff --git a/images/default_profile_photos/rainbow_man/175.png b/images/default_profile_photos/rainbow_man/175.png Binary files differindex a0a236841..30a7e0ffb 100644 --- a/images/default_profile_photos/rainbow_man/175.png +++ b/images/default_profile_photos/rainbow_man/175.png diff --git a/images/default_profile_photos/rainbow_man/48.png b/images/default_profile_photos/rainbow_man/48.png Binary files differindex 9e3399598..8bd2695e6 100644 --- a/images/default_profile_photos/rainbow_man/48.png +++ b/images/default_profile_photos/rainbow_man/48.png diff --git a/images/default_profile_photos/rainbow_man/80.png b/images/default_profile_photos/rainbow_man/80.png Binary files differindex b0b1ca784..970f10a1e 100644 --- a/images/default_profile_photos/rainbow_man/80.png +++ b/images/default_profile_photos/rainbow_man/80.png diff --git a/images/default_profile_photos/rainbow_man_trans/175.png b/images/default_profile_photos/rainbow_man_trans/175.png Binary files differnew file mode 100644 index 000000000..a0a236841 --- /dev/null +++ b/images/default_profile_photos/rainbow_man_trans/175.png diff --git a/images/default_profile_photos/rainbow_man_trans/48.png b/images/default_profile_photos/rainbow_man_trans/48.png Binary files differnew file mode 100644 index 000000000..9e3399598 --- /dev/null +++ b/images/default_profile_photos/rainbow_man_trans/48.png diff --git a/images/default_profile_photos/rainbow_man_trans/80.png b/images/default_profile_photos/rainbow_man_trans/80.png Binary files differnew file mode 100644 index 000000000..b0b1ca784 --- /dev/null +++ b/images/default_profile_photos/rainbow_man_trans/80.png diff --git a/images/default_profile_photos/red_koala/175.png b/images/default_profile_photos/red_koala/175.png Binary files differindex 4e51c80e2..ee4a701d9 100644 --- a/images/default_profile_photos/red_koala/175.png +++ b/images/default_profile_photos/red_koala/175.png diff --git a/images/default_profile_photos/red_koala/48.png b/images/default_profile_photos/red_koala/48.png Binary files differindex 69ecfebd9..bc5e61e7b 100644 --- a/images/default_profile_photos/red_koala/48.png +++ b/images/default_profile_photos/red_koala/48.png diff --git a/images/default_profile_photos/red_koala/80.png b/images/default_profile_photos/red_koala/80.png Binary files differindex 48c161fc7..be5b70269 100644 --- a/images/default_profile_photos/red_koala/80.png +++ b/images/default_profile_photos/red_koala/80.png diff --git a/images/default_profile_photos/red_koala_trans/175.png b/images/default_profile_photos/red_koala_trans/175.png Binary files differnew file mode 100644 index 000000000..4e51c80e2 --- /dev/null +++ b/images/default_profile_photos/red_koala_trans/175.png diff --git a/images/default_profile_photos/red_koala_trans/48.png b/images/default_profile_photos/red_koala_trans/48.png Binary files differnew file mode 100644 index 000000000..69ecfebd9 --- /dev/null +++ b/images/default_profile_photos/red_koala_trans/48.png diff --git a/images/default_profile_photos/red_koala_trans/80.png b/images/default_profile_photos/red_koala_trans/80.png Binary files differnew file mode 100644 index 000000000..48c161fc7 --- /dev/null +++ b/images/default_profile_photos/red_koala_trans/80.png diff --git a/include/RedDAV/RedBrowser.php b/include/RedDAV/RedBrowser.php new file mode 100644 index 000000000..dcd54ef82 --- /dev/null +++ b/include/RedDAV/RedBrowser.php @@ -0,0 +1,361 @@ +<?php +/** + * RedMatrix - "The Network" + * + * @link http://github.com/friendica/red + * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) + */ + +namespace RedMatrix\RedDAV; + +use Sabre\DAV; + +/** + * @brief Provides a DAV frontend for the webbrowser. + * + * RedBrowser is a SabreDAV server-plugin to provide a view to the DAV storage + * for the webbrowser. + * + * @extends \Sabre\DAV\Browser\Plugin + */ +class RedBrowser extends DAV\Browser\Plugin { + + /** + * @see set_writeable() + * @see \Sabre\DAV\Auth\Backend\BackendInterface + * @var RedBasicAuth + */ + private $auth; + + /** + * @brief Constructor for RedBrowser class. + * + * $enablePost will be activated through set_writeable() in a later stage. + * At the moment the write_storage permission is only valid for the whole + * folder. No file specific permissions yet. + * + * Disable assets with $enableAssets = false. Should get some thumbnail views + * anyway. + * + * @param RedBasicAuth &$auth + */ + public function __construct(&$auth) { + $this->auth = $auth; + parent::__construct(false, false); + } + + /** + * The DAV browser is instantiated after the auth module and directory classes + * but before we know the current directory and who the owner and observer + * are. So we add a pointer to the browser into the auth module and vice versa. + * Then when we've figured out what directory is actually being accessed, we + * call the following function to decide whether or not to show web elements + * which include writeable objects. + * + * @todo Maybe this can be solved with some $server->subscribeEvent()? + */ + public function set_writeable() { + if (! $this->auth->owner_id) { + $this->enablePost = false; + } + + if (! perm_is_allowed($this->auth->owner_id, get_observer_hash(), 'write_storage')) { + $this->enablePost = false; + } else { + $this->enablePost = true; + } + } + + /** + * @brief Creates the directory listing for the given path. + * + * @param string $path which should be displayed + */ + public function generateDirectoryIndex($path) { + // (owner_id = channel_id) is visitor owner of this directory? + $is_owner = ((local_user() && $this->auth->owner_id == local_user()) ? true : false); + + if ($this->auth->getTimezone()) + date_default_timezone_set($this->auth->getTimezone()); + + require_once('include/conversation.php'); + + if ($this->auth->owner_nick) { + $html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick); + } + + $files = $this->server->getPropertiesForPath($path, array( + '{DAV:}displayname', + '{DAV:}resourcetype', + '{DAV:}getcontenttype', + '{DAV:}getcontentlength', + '{DAV:}getlastmodified', + ), 1); + + $parent = $this->server->tree->getNodeForPath($path); + + $parentpath = array(); + // only show parent if not leaving /cloud/; TODO how to improve this? + if ($path && $path != "cloud") { + list($parentUri) = DAV\URLUtil::splitPath($path); + $fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri); + + $parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : ''; + $parentpath['path'] = $fullPath; + } + + $f = array(); + foreach ($files as $file) { + $ft = array(); + $type = null; + + // This is the current directory, we can skip it + if (rtrim($file['href'],'/') == $path) continue; + + list(, $name) = DAV\URLUtil::splitPath($file['href']); + + if (isset($file[200]['{DAV:}resourcetype'])) { + $type = $file[200]['{DAV:}resourcetype']->getValue(); + + // resourcetype can have multiple values + if (!is_array($type)) $type = array($type); + + foreach ($type as $k=>$v) { + // Some name mapping is preferred + switch ($v) { + case '{DAV:}collection' : + $type[$k] = t('Collection'); + break; + case '{DAV:}principal' : + $type[$k] = t('Principal'); + break; + case '{urn:ietf:params:xml:ns:carddav}addressbook' : + $type[$k] = t('Addressbook'); + break; + case '{urn:ietf:params:xml:ns:caldav}calendar' : + $type[$k] = t('Calendar'); + break; + case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' : + $type[$k] = t('Schedule Inbox'); + break; + case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' : + $type[$k] = t('Schedule Outbox'); + break; + case '{http://calendarserver.org/ns/}calendar-proxy-read' : + $type[$k] = 'Proxy-Read'; + break; + case '{http://calendarserver.org/ns/}calendar-proxy-write' : + $type[$k] = 'Proxy-Write'; + break; + } + } + $type = implode(', ', $type); + } + + // If no resourcetype was found, we attempt to use + // the contenttype property + if (!$type && isset($file[200]['{DAV:}getcontenttype'])) { + $type = $file[200]['{DAV:}getcontenttype']; + } + if (!$type) $type = t('Unknown'); + + $size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : ''; + $lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : ''); + + $fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/')); + + $displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name; + + $displayName = $this->escapeHTML($displayName); + $type = $this->escapeHTML($type); + + $icon = ''; + if ($this->enableAssets) { + $node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name); + foreach (array_reverse($this->iconMap) as $class=>$iconName) { + if ($node instanceof $class) { + $icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>'; + break; + } + } + } + + $parentHash = ""; + $owner = $this->auth->owner_id; + $splitPath = split("/", $fullPath); + if (count($splitPath) > 3) { + for ($i = 3; $i < count($splitPath); $i++) { + $attachName = urldecode($splitPath[$i]); + $attachHash = $this->findAttachHash($owner, $parentHash, $attachName); + $parentHash = $attachHash; + } + } + + $attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"icon-download\"></i></a>"; + + // put the array for this file together + $ft['attachId'] = $this->findAttachIdByHash($attachHash); + $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser(); + $ft['icon'] = $icon; + $ft['attachIcon'] = (($size) ? $attachIcon : ''); + // @todo Should this be an item value, not a global one? + $ft['is_owner'] = $is_owner; + $ft['fullPath'] = $fullPath; + $ft['displayName'] = $displayName; + $ft['type'] = $type; + $ft['size'] = $size; + $ft['sizeFormatted'] = $this->userReadableSize($size); + $ft['lastmodified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : ''); + + $f[] = $ft; + } + + // Storage and quota for the account (all channels of the owner of this directory)! + $limit = service_class_fetch($owner, 'attach_upload_limit'); + $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d", + intval($this->auth->channel_account_id) + ); + $used = $r[0]['total']; + if ($used) { + $quotaDesc = t('%1$s used'); + $quotaDesc = sprintf($quotaDesc, + $this->userReadableSize($used)); + } + if ($limit && $used) { + $quotaDesc = t('%1$s used of %2$s (%3$s%)'); + $quotaDesc = sprintf($quotaDesc, + $this->userReadableSize($used), + $this->userReadableSize($limit), + round($used / $limit, 1)); + } + + // prepare quota for template + $quota['used'] = $used; + $quota['limit'] = $limit; + $quota['desc'] = $quotaDesc; + + $html .= replace_macros(get_markup_template('cloud_directory.tpl'), array( + '$header' => t('Files') . ": " . $this->escapeHTML($path) . "/", + '$parentpath' => $parentpath, + '$entries' => $f, + '$quota' => $quota, + '$name' => t('Name'), + '$type' => t('Type'), + '$size' => t('Size'), + '$lastmod' => t('Last Modified'), + '$parent' => t('parent'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$total' => t('Total') + )); + + $output = ''; + if ($this->enablePost) { + $this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output)); + } + $html .= $output; + + get_app()->page['content'] = $html; + construct_page(get_app()); + } + + function userReadableSize($size) { + $ret = ""; + if (is_numeric($size)) { + $incr = 0; + $k = 1024; + $unit = array('bytes', 'KB', 'MB', 'GB', 'TB', 'PB'); + while (($size / $k) >= 1){ + $incr++; + $size = round($size / $k, 2); + } + $ret = $size . " " . $unit[$incr]; + } + return $ret; + } + + /** + * @brief Creates a form to add new folders and upload files. + * + * @param \Sabre\DAV\INode $node + * @param string &$output + */ + public function htmlActionsPanel(DAV\INode $node, &$output) { + if (! $node instanceof DAV\ICollection) + return; + + // We also know fairly certain that if an object is a non-extended + // SimpleCollection, we won't need to show the panel either. + if (get_class($node) === 'Sabre\\DAV\\SimpleCollection') + return; + + $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array( + '$folder_header' => t('Create new folder'), + '$folder_submit' => t('Create'), + '$upload_header' => t('Upload file'), + '$upload_submit' => t('Upload') + )); + } + + /** + * This method takes a path/name of an asset and turns it into url + * suiteable for http access. + * + * @param string $assetName + * @return string + */ + protected function getAssetUrl($assetName) { + return z_root() . '/cloud/?sabreAction=asset&assetName=' . urlencode($assetName); + } + + /** + * @brief Return the hash of an attachment. + * + * Given the owner, the parent folder and and attach name get the attachment + * hash. + * + * @param int $owner + * The owner_id + * @param string $hash + * The parent's folder hash + * @param string $attachName + * The name of the attachment + * @return string + */ + protected function findAttachHash($owner, $parentHash, $attachName) { + $r = q("SELECT hash FROM attach WHERE uid = %d AND folder = '%s' AND filename = '%s' ORDER BY edited DESC LIMIT 1", + intval($owner), + dbesc($parentHash), + dbesc($attachName) + ); + $hash = ""; + if ($r) { + foreach ($r as $rr) { + $hash = $rr['hash']; + } + } + return $hash; + } + + /** + * @brief Returns an attachment's id for a given hash. + * + * This id is used to access the attachment in filestorage/ + * + * @param string $attachHash + * The hash of an attachment + * @return string + */ + protected function findAttachIdByHash($attachHash) { + $r = q("SELECT id FROM attach WHERE hash = '%s' ORDER BY edited DESC LIMIT 1", + dbesc($attachHash) + ); + $id = ""; + if ($r) { + foreach ($r as $rr) { + $id = $rr['id']; + } + } + return $id; + } +}
\ No newline at end of file diff --git a/include/reddav.php b/include/reddav.php index 3de24661e..5c93daf1f 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -14,14 +14,18 @@ */ use Sabre\DAV; + require_once('vendor/autoload.php'); require_once('include/attach.php'); - /** * @brief RedDirectory class. * * A class that represents a directory. + * + * @extends \Sabre\DAV\Node + * @implements \Sabre\DAV\ICollection + * @implements \Sabre\DAV\IQuota */ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { @@ -1176,326 +1180,3 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { } } // class RedBasicAuth - - - -/** - * @brief RedBrowser class. - * - * RedBrowser is a SabreDAV server-plugin to provide a view to the DAV in - * the browser - */ -class RedBrowser extends DAV\Browser\Plugin { - - /** - * @var RedBasicAuth - */ - private $auth; - - /** - * @brief Constructor for RedBrowser. - * - * @param RedBasicAuth &$auth - */ - function __construct(&$auth) { - $this->auth = $auth; - $this->enableAssets = false; - } - - // The DAV browser is instantiated after the auth module and directory classes but before we know the current - // directory and who the owner and observer are. So we add a pointer to the browser into the auth module and vice - // versa. Then when we've figured out what directory is actually being accessed, we call the following function - // to decide whether or not to show web elements which include writeable objects. - // @todo Maybe this can be solved with some $server->subscribeEvent()? - function set_writeable() { - if (! $this->auth->owner_id) { - $this->enablePost = false; - } - - if (! perm_is_allowed($this->auth->owner_id, get_observer_hash(), 'write_storage')) { - $this->enablePost = false; - } else { - $this->enablePost = true; - } - } - - /** - * @brief Creates the directory listing for the given path. - * - * @param string $path which should be displayed - */ - public function generateDirectoryIndex($path) { - // (owner_id = channel_id) is visitor owner of this directory? - $is_owner = ((local_user() && $this->auth->owner_id == local_user()) ? true : false); - - if ($this->auth->getTimezone()) - date_default_timezone_set($this->auth->getTimezone()); - - require_once('include/conversation.php'); - - if ($this->auth->owner_nick) { - $html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick); - } - - $files = $this->server->getPropertiesForPath($path, array( - '{DAV:}displayname', - '{DAV:}resourcetype', - '{DAV:}getcontenttype', - '{DAV:}getcontentlength', - '{DAV:}getlastmodified', - ), 1); - - $parent = $this->server->tree->getNodeForPath($path); - - $parentpath = array(); - // only show parent if not leaving /cloud/; TODO how to improve this? - if ($path && $path != "cloud") { - list($parentUri) = DAV\URLUtil::splitPath($path); - $fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri); - - $parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : ''; - $parentpath['path'] = $fullPath; - } - - $f = array(); - foreach ($files as $file) { - $ft = array(); - $type = null; - - // This is the current directory, we can skip it - if (rtrim($file['href'],'/')==$path) continue; - - list(, $name) = DAV\URLUtil::splitPath($file['href']); - - if (isset($file[200]['{DAV:}resourcetype'])) { - $type = $file[200]['{DAV:}resourcetype']->getValue(); - - // resourcetype can have multiple values - if (!is_array($type)) $type = array($type); - - foreach ($type as $k=>$v) { - // Some name mapping is preferred - switch ($v) { - case '{DAV:}collection' : - $type[$k] = t('Collection'); - break; - case '{DAV:}principal' : - $type[$k] = t('Principal'); - break; - case '{urn:ietf:params:xml:ns:carddav}addressbook' : - $type[$k] = t('Addressbook'); - break; - case '{urn:ietf:params:xml:ns:caldav}calendar' : - $type[$k] = t('Calendar'); - break; - case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' : - $type[$k] = t('Schedule Inbox'); - break; - case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' : - $type[$k] = t('Schedule Outbox'); - break; - case '{http://calendarserver.org/ns/}calendar-proxy-read' : - $type[$k] = 'Proxy-Read'; - break; - case '{http://calendarserver.org/ns/}calendar-proxy-write' : - $type[$k] = 'Proxy-Write'; - break; - } - } - $type = implode(', ', $type); - } - - // If no resourcetype was found, we attempt to use - // the contenttype property - if (!$type && isset($file[200]['{DAV:}getcontenttype'])) { - $type = $file[200]['{DAV:}getcontenttype']; - } - if (!$type) $type = t('Unknown'); - - $size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : ''; - $lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : ''); - - $fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/')); - - $displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name; - - $displayName = $this->escapeHTML($displayName); - $type = $this->escapeHTML($type); - - $icon = ''; - if ($this->enableAssets) { - $node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name); - foreach (array_reverse($this->iconMap) as $class=>$iconName) { - if ($node instanceof $class) { - $icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>'; - break; - } - } - } - - $parentHash = ""; - $owner = $this->auth->owner_id; - $splitPath = split("/", $fullPath); - if (count($splitPath) > 3) { - for ($i = 3; $i < count($splitPath); $i++) { - $attachName = urldecode($splitPath[$i]); - $attachHash = $this->findAttachHash($owner, $parentHash, $attachName); - $parentHash = $attachHash; - } - } - - $attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"icon-download\"></i></a>"; - - // put the array for this file together - $ft['attachId'] = $this->findAttachIdByHash($attachHash); - $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser(); - $ft['icon'] = $icon; - $ft['attachIcon'] = (($size) ? $attachIcon : ''); - // @todo Should this be an item value, not a global one? - $ft['is_owner'] = $is_owner; - $ft['fullPath'] = $fullPath; - $ft['displayName'] = $displayName; - $ft['type'] = $type; - $ft['size'] = $size; - $ft['sizeFormatted'] = $this->userReadableSize($size); - $ft['lastmodified'] = (($lastmodified) ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : ''); - - $f[] = $ft; - } - - // Storage and quota for the account (all channels of the owner of this directory)! - $limit = service_class_fetch($owner, 'attach_upload_limit'); - $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d", - intval($this->auth->channel_account_id) - ); - $used = $r[0]['total']; - if ($used) { - $quotaDesc = t('%1$s used'); - $quotaDesc = sprintf($quotaDesc, - $this->userReadableSize($used)); - } - if ($limit && $used) { - $quotaDesc = t('%1$s used of %2$s (%3$s%)'); - $quotaDesc = sprintf($quotaDesc, - $this->userReadableSize($used), - $this->userReadableSize($limit), - round($used / $limit, 1)); - } - - // prepare quota for template - $quota['used'] = $used; - $quota['limit'] = $limit; - $quota['desc'] = $quotaDesc; - - $html .= replace_macros(get_markup_template('cloud_directory.tpl'), array( - '$header' => t('Files') . ": " . $this->escapeHTML($path) . "/", - '$parentpath' => $parentpath, - '$entries' => $f, - '$quota' => $quota, - '$name' => t('Name'), - '$type' => t('Type'), - '$size' => t('Size'), - '$lastmod' => t('Last Modified'), - '$parent' => t('parent'), - '$edit' => t('Edit'), - '$delete' => t('Delete'), - '$total' => t('Total') - )); - - $output = ''; - if ($this->enablePost) { - $this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output)); - } - $html .= $output; - - get_app()->page['content'] = $html; - construct_page(get_app()); - } - - function userReadableSize($size) { - $ret = ""; - if (is_numeric($size)) { - $incr = 0; - $k = 1024; - $unit = array('bytes', 'KB', 'MB', 'GB', 'TB', 'PB'); - while (($size / $k) >= 1){ - $incr++; - $size = round($size / $k, 2); - } - $ret = $size . " " . $unit[$incr]; - } - return $ret; - } - - /** - * Creates a form to add new folders and upload files. - * - * @param DAV\INode $node - * @param string &$output - */ - public function htmlActionsPanel(DAV\INode $node, &$output) { - - //Removed link to filestorage page - //if($this->auth->owner_id && $this->auth->owner_id == $this->auth->channel_id) { - // $channel = get_app()->get_channel(); - // if($channel) { - // $output .= '<tr><td colspan="2"><a href="filestorage/' . $channel['channel_address'] . '" >' . t('Edit File properties') . '</a></td></tr><tr><td> </td></tr>'; - // } - //} - - if (! $node instanceof DAV\ICollection) - return; - - // We also know fairly certain that if an object is a non-extended - // SimpleCollection, we won't need to show the panel either. - if (get_class($node) === 'Sabre\\DAV\\SimpleCollection') - return; - - $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array( - '$folder_header' => t('Create new folder'), - '$folder_submit' => t('Create'), - '$upload_header' => t('Upload file'), - '$upload_submit' => t('Upload') - )); - } - - /** - * This method takes a path/name of an asset and turns it into url - * suiteable for http access. - * - * @param string $assetName - * @return string - */ - protected function getAssetUrl($assetName) { - return z_root() . '/cloud/?sabreAction=asset&assetName=' . urlencode($assetName); - } - - protected function findAttachHash($owner, $parentHash, $attachName) { - $r = q("SELECT * FROM attach WHERE uid = %d AND folder = '%s' AND filename = '%s' ORDER BY edited desc LIMIT 1", - intval($owner), - dbesc($parentHash), - dbesc($attachName) - ); - $hash = ""; - if ($r) { - foreach ($r as $rr) { - $hash = $rr['hash']; - } - } - return $hash; - } - - protected function findAttachIdByHash($attachHash) { - $r = q("SELECT * FROM attach WHERE hash = '%s' ORDER BY edited DESC LIMIT 1", - dbesc($attachHash) - ); - $id = ""; - if ($r) { - foreach ($r as $rr) { - $id = $rr['id']; - } - } - return $id; - } - -} // class RedBrowser diff --git a/mod/cloud.php b/mod/cloud.php index c21c4c4b6..28c59872d 100644 --- a/mod/cloud.php +++ b/mod/cloud.php @@ -7,12 +7,13 @@ */ use Sabre\DAV; +use RedMatrix\RedDAV; // composer autoloader for SabreDAV require_once('vendor/autoload.php'); // workaround for HTTP-auth in CGI mode -if(x($_SERVER, 'REDIRECT_REMOTE_USER')) { +if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; if(strlen($userpass)) { list($name, $password) = explode(':', $userpass); @@ -21,7 +22,7 @@ if(x($_SERVER, 'REDIRECT_REMOTE_USER')) { } } -if(x($_SERVER, 'HTTP_AUTHORIZATION')) { +if (x($_SERVER, 'HTTP_AUTHORIZATION')) { $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; if(strlen($userpass)) { list($name, $password) = explode(':', $userpass); @@ -40,7 +41,7 @@ function cloud_init(&$a) { $theme_info_file = "view/theme/" . current_theme() . "/php/theme.php"; if (file_exists($theme_info_file)){ require_once($theme_info_file); - if(function_exists(str_replace('-', '_', current_theme()) . '_init')) { + if (function_exists(str_replace('-', '_', current_theme()) . '_init')) { $func = str_replace('-', '_', current_theme()) . '_init'; $func($a); } @@ -48,26 +49,26 @@ function cloud_init(&$a) { require_once('include/reddav.php'); - if(! is_dir('store')) + if (! is_dir('store')) os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false); $which = null; - if(argc() > 1) + if (argc() > 1) $which = argv(1); $profile = 0; $a->page['htmlhead'] .= '<link rel="alternate" type="application/atom+xml" href="' . $a->get_baseurl() . '/feed/' . $which . '" />' . "\r\n"; - if($which) + if ($which) profile_load($a, $which, $profile); $auth = new RedBasicAuth(); $ob_hash = get_observer_hash(); - if($ob_hash) { - if(local_user()) { + if ($ob_hash) { + if (local_user()) { $channel = $a->get_channel(); $auth->setCurrentUser($channel['channel_address']); $auth->channel_id = $channel['channel_id']; @@ -79,7 +80,7 @@ function cloud_init(&$a) { $auth->observer = $ob_hash; } - if($_GET['davguest']) + if ($_GET['davguest']) $_SESSION['davguest'] = true; $_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']); @@ -113,7 +114,7 @@ function cloud_init(&$a) { $isapublic_file = false; $davguest = ((x($_SESSION, 'davguest')) ? true : false); - if((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) { + if ((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) { try { $x = RedFileData('/' . $a->cmd, $auth); if($x instanceof RedFile) @@ -124,7 +125,7 @@ function cloud_init(&$a) { } } - if((! $auth->observer) && (! $isapublic_file) && (! $davguest)) { + if ((! $auth->observer) && (! $isapublic_file) && (! $davguest)) { try { $auth->Authenticate($server, t('RedMatrix - Guests: Username: {your email address}, Password: +++')); } @@ -134,13 +135,18 @@ function cloud_init(&$a) { } } + require_once('include/RedDAV/RedBrowser.php'); // provide a directory view for the cloud in Red Matrix - $browser = new RedBrowser($auth); + $browser = new RedDAV\RedBrowser($auth); $auth->setBrowserPlugin($browser); $server->addPlugin($browser); + // Experimental QuotaPlugin +// require_once('include/RedDAV/QuotaPlugin.php'); +// $server->addPlugin(new RedDAV\QuotaPlugin($auth)); + // All we need to do now, is to fire up the server $server->exec(); |