diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | apps/files_sharing/ajax/share.php | 16 | ||||
-rw-r--r-- | apps/files_sharing/ajax/unshare.php | 11 | ||||
-rw-r--r-- | apps/files_sharing/ajax/userautocomplete.php | 29 | ||||
-rw-r--r-- | apps/files_sharing/appinfo/app.php | 13 | ||||
-rw-r--r-- | apps/files_sharing/appinfo/database.xml | 42 | ||||
-rw-r--r-- | apps/files_sharing/appinfo/info.xml | 10 | ||||
-rw-r--r-- | apps/files_sharing/js/list.js | 54 | ||||
-rw-r--r-- | apps/files_sharing/js/share.js | 95 | ||||
-rw-r--r-- | apps/files_sharing/lib_share.php | 314 | ||||
-rw-r--r-- | apps/files_sharing/list.php | 40 | ||||
-rw-r--r-- | apps/files_sharing/sharedstorage.php | 510 | ||||
-rw-r--r-- | apps/files_sharing/templates/list.php | 30 | ||||
-rw-r--r-- | lib/base.php | 5 | ||||
-rw-r--r-- | lib/filesystem.php | 5 |
15 files changed, 1173 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore index 94de5aec803..e62a5abd965 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ RCS/* # Lokalize *lokalize* -.project +.project
\ No newline at end of file diff --git a/apps/files_sharing/ajax/share.php b/apps/files_sharing/ajax/share.php new file mode 100644 index 00000000000..b2c3a477958 --- /dev/null +++ b/apps/files_sharing/ajax/share.php @@ -0,0 +1,16 @@ +<?php +$RUNTIME_NOAPPS = true; + +require_once('../../../lib/base.php'); +require_once('../lib_share.php'); + +$sources = $_GET['sources']; +$uid_shared_with = $_GET['uid_shared_with']; +$permissions = $_GET['permissions']; +foreach ($sources as $source) { + foreach ($uid_shared_with as $uid) { + new OC_SHARE($source, $uid, $permissions); + } +} + +?>
\ No newline at end of file diff --git a/apps/files_sharing/ajax/unshare.php b/apps/files_sharing/ajax/unshare.php new file mode 100644 index 00000000000..4d83d332257 --- /dev/null +++ b/apps/files_sharing/ajax/unshare.php @@ -0,0 +1,11 @@ +<?php +$RUNTIME_NOAPPS = true; + +require_once('../../../lib/base.php'); +require_once('../lib_share.php'); + +$source = $_GET['source']; +$uid_shared_with = $_GET['uid_shared_with']; +OC_SHARE::unshare($source, $uid_shared_with); + +?>
\ No newline at end of file diff --git a/apps/files_sharing/ajax/userautocomplete.php b/apps/files_sharing/ajax/userautocomplete.php new file mode 100644 index 00000000000..6e1469ae348 --- /dev/null +++ b/apps/files_sharing/ajax/userautocomplete.php @@ -0,0 +1,29 @@ +<?php +$RUNTIME_NOAPPS = true; + +require_once('../../../lib/base.php'); + +if (!OC_USER::isLoggedIn()) { + echo json_encode(array("status" => "error", "data" => array("message" => "Authentication error"))); + exit(); +} +$query = $_GET['term']; +$length = strlen($query); +$query = strtolower($query); +$users = array(); +$ocusers = OC_USER::getUsers(); +$self = OC_USER::getUser(); +$groups = OC_GROUP::getUserGroups($self); +foreach ($ocusers as $user) { + if ($user != $self && substr(strtolower($user), 0, $length) == $query) { + $users[] = (object)array('id' => $user, 'label' => $user, 'name' => $user); + } +} +foreach ($groups as $group) { + if (substr(strtolower($group), 0, $length) == $query) { + $users[] = (object)array('id' => $group, 'label' => $group, 'name' => $group); + } +} +echo json_encode($users); + +?> diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php new file mode 100644 index 00000000000..879bd1ea0eb --- /dev/null +++ b/apps/files_sharing/appinfo/app.php @@ -0,0 +1,13 @@ +<?php + +require_once('apps/files_sharing/lib_share.php'); + +OC_UTIL::addScript("files_sharing", "share"); + +OC_APP::addNavigationEntry( array( "id" => "files_sharing_list", + "order" => 10, + "href" => OC_HELPER::linkTo( "files_sharing", "list.php" ), + "name" => "Share", + "icon" => OC_HELPER::imagePath( "files_sharing", "share.png" ))); + +?>
\ No newline at end of file diff --git a/apps/files_sharing/appinfo/database.xml b/apps/files_sharing/appinfo/database.xml new file mode 100644 index 00000000000..7ddaca21aec --- /dev/null +++ b/apps/files_sharing/appinfo/database.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<database> + <name>*dbname*</name> + <create>true</create> + <overwrite>false</overwrite> + <charset>latin1</charset> + <table> + <name>*dbprefix*sharing</name> + <declaration> + <field> + <name>uid_owner</name> + <type>text</type> + <notnull>true</notnull> + <length>64</length> + </field> + <field> + <name>uid_shared_with</name> + <type>text</type> + <notnull>true</notnull> + <length>64</length> + </field> + <field> + <name>source</name> + <type>text</type> + <notnull>true</notnull> + <length>128</length> + </field> + <field> + <name>target</name> + <type>text</type> + <notnull>true</notnull> + <length>128</length> + </field> + <field> + <name>is_writeable</name> + <type>integer</type> + <notnull>true</notnull> + <length>1</length> + </field> + </declaration> + </table> +</database> diff --git a/apps/files_sharing/appinfo/info.xml b/apps/files_sharing/appinfo/info.xml new file mode 100644 index 00000000000..2fbb3300f69 --- /dev/null +++ b/apps/files_sharing/appinfo/info.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<info> + <id>files_sharing</id> + <name>Share Files</name> + <description>File sharing between users</description> + <version>0.1</version> + <licence>AGPL</licence> + <author>Michael Gapczynski</author> + <require>2</require> +</info>
\ No newline at end of file diff --git a/apps/files_sharing/js/list.js b/apps/files_sharing/js/list.js new file mode 100644 index 00000000000..41eabd1f4af --- /dev/null +++ b/apps/files_sharing/js/list.js @@ -0,0 +1,54 @@ +$(document).ready(function() { + $( "#source" ).autocomplete({ + source: "../../files/ajax/autocomplete.php", + minLength: 1 + }); + $( "#uid_shared_with" ).autocomplete({ + source: "ajax/userautocomplete.php", + minLength: 1 + }); + $("button.delete").live('click', function( event ) { + event.preventDefault(); +// var row=$(this); + var source=$(this).attr('data-source'); + var uid_shared_with=$(this).attr('data-uid_shared_with'); + var data='source='+encodeURIComponent(source)+'&uid_shared_with='+encodeURIComponent(uid_shared_with); + $.ajax({ + type: 'GET', + url: 'ajax/unshare.php', + cache: false, + data: data +// success: function(){ +// row.remove(); +// } + }); + }); + $('#share_item').submit(function( event ){ + event.preventDefault(); + var source=$('#source').val(); + var uid_shared_with=$('#uid_shared_with').val(); + var permissions=$('#permissions').val()||0; + var data='source='+source+'&uid_shared_with='+uid_shared_with+'&permissions='+permissions; + $.ajax({ + type: 'GET', + url: 'ajax/share.php', + cache: false, + data: data, +// success: function(token){ +// if(token){ +// var html="<tr class='link' id='"+token+"'>"; +// html+="<td class='path'>"+path+"</td>"; +// var expire=($('#expire').val())?$('#expire').val():'Never' +// html+="<td class='expire'>"+expire+"</td>" +// html+="<td class='link'><a href='get.php?token="+token+"'>"+$('#baseUrl').val()+"?token="+token+"</a></td>" +// html+="<td><button class='delete fancybutton' data-token='"+token+"'>Delete</button></td>" +// html+="</tr>" +// $(html).insertBefore($('#newlink_row')); +// $('#expire').val(''); +// $('#expire_time').val(''); +// $('#path').val(''); +// } +// } + }); + }); +});
\ No newline at end of file diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js new file mode 100644 index 00000000000..32926c6811e --- /dev/null +++ b/apps/files_sharing/js/share.js @@ -0,0 +1,95 @@ +$(document).ready(function() { + $('.share').click(function(event) { + event.preventDefault(); + var html = "<div id='dialog' title='Share "+getSelectedFiles('name')+"' align='center'>"; + html += "<label><input type='radio' name='share_type' value='private' checked='checked' /> Private</label>"; + html += "<label><input type='radio' name='share_type' value='public' /> Public</label>"; + html += "<br />"; + html += "<div id='private'>"; + html += "<label>Share with <input placeholder='User or Group' class='uid_shared_with' /></label>"; + html += "<button id='hey' class='add-uid_shared_with fancybutton'>+</button>"; + html += "<br />"; + html += "<a id='toggle-private-advanced'>Advanced</a>"; + html += "<br />"; + html += "<div id='private-advanced' style='display: none; text-align: left'>"; + html += "<label><input type='checkbox' name='share_permissions' value='read' checked='checked' disabled='disable' /> Read</label><br />"; + html += "<label><input type='checkbox' name='share_permissions' value='write' /> Write</label><br />"; + html += "<label><input type='checkbox' name='share_permissions' value='rename' /> Rename</label><br />"; + html += "<label><input type='checkbox' name='share_permissions' value='delete' /> Delete</label><br />"; + html += "</div>"; + html += "</div>"; + html += "<div id='public' style='display: none'>"; + html += "TODO: Construct a public link"; + html += "<input placeholder='Expires' id='expire' />"; + html += "</div>"; + html += "<br />"; + html += "<button class='submit fancybutton'>Share</button>"; + html += "<div>"; + $(html).dialog({ + close: function(event, ui) { + $(this).remove(); + } + }); + }); + $("input[name=share_type]").live('change', function() { + $('#private').toggle(); + $('#public').toggle(); + }); + $('.uid_shared_with').live('keyup', function() { + $(this).autocomplete({ + source: "../apps/files_sharing/ajax/userautocomplete.php", + minLength: 1 + }); + }); + $('button.add-uid_shared_with').live('click', function(event) { + event.preventDefault(); + // TODO Make sure previous textbox has a valid user or group name + var html = "<br />"; + html += "<label>Share with <input placeholder='User or Group' class='uid_shared_with' /></label>"; + html += "<button class='add-uid_shared_with fancybutton'>+</button>"; + $(html).insertAfter('.add-uid_shared_with'); + $(this).html(" -  "); + $(this).removeClass("add-uid_shared_with fancybutton"); + $(this).addClass("remove-uid_shared_with fancybutton"); + }); + $('button.remove-uid_shared_with').live('click', function(event) { + event.preventDefault(); + alert("remove"); + // TODO Remove corresponding row + }); + $('#toggle-private-advanced').live('click', function(event) { + event.preventDefault(); + $('#private-advanced').toggle(); + }); + $('#expire').datepicker({ + dateFormat:'MM d, yy', + altField: "#expire_time", + altFormat: "yy-mm-dd" + }); + $('button.submit').live('click', function(event) { + event.preventDefault(); + if ($("input[name=share_type]:checked").val() == 'public') { + // TODO Construct public link + } else { + // TODO Check all inputs are valid + var sources = ""; + var files = getSelectedFiles('name'); + var length = files.length; + for (var i = 0; i < length; i++) { + sources += "&sources[]=" + $('#dir').val() + "/" + files[i]; + } + var uid_shared_with = $('.uid_shared_with').val(); + var permissions = 0; + var data = sources+'&uid_shared_with[]='+uid_shared_with+'&permissions='+permissions; + $.ajax({ + type: 'GET', + url: '../apps/files_sharing/ajax/share.php', + cache: false, + data: data, + success: function() { + $('#dialog').dialog('close'); + } + }); + } + }); +});
\ No newline at end of file diff --git a/apps/files_sharing/lib_share.php b/apps/files_sharing/lib_share.php new file mode 100644 index 00000000000..b096a956e7d --- /dev/null +++ b/apps/files_sharing/lib_share.php @@ -0,0 +1,314 @@ +<?php +/** + * ownCloud + * + * @author Michael Gapczynski + * @copyright 2011 Michael Gapczynski GapczynskiM@gmail.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +OC_HOOK::connect("OC_FILESYSTEM","post_delete", "OC_SHARE", "deleteItem"); +OC_HOOK::connect("OC_FILESYSTEM","post_rename", "OC_SHARE", "renameItem"); + +/** + * This class manages shared items within the database. + */ +class OC_SHARE { + + /** + * TODO notify user a file is being shared with them? + * Share an item, adds an entry into the database + * @param string $item + * @param user item shared with $uid_shared_with + */ + public function __construct($source, $uid_shared_with, $permissions, $public = false) { + if ($source && OC_FILESYSTEM::file_exists($source) && OC_FILESYSTEM::is_readable($source)) { + $source = "/".OC_USER::getUser()."/files".$source; + $uid_owner = OC_USER::getUser(); + if ($public) { + // TODO create token for public file + $token = sha1("$uid_owner-$item"); + } else { + $query = OC_DB::prepare("INSERT INTO *PREFIX*sharing VALUES(?,?,?,?,?)"); + $target = "/".$uid_shared_with."/files/Share/".basename($source); + $check = OC_DB::prepare("SELECT target FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with = ?"); + $result = $check->execute(array($target, $uid_shared_with))->fetchAll(); + // Check if target already exists for the user, if it does append a number to the name + if (count($result) > 0) { + if ($pos = strrpos($target, ".")) { + $name = substr($target, 0, $pos); + $ext = substr($target, $pos); + } else { + $name = $target; + $ext = ""; + } + $counter = 1; + while (count($result) > 0) { + $newTarget = $name."_".$counter.$ext; + $result = $check->execute(array($newTarget, $uid_shared_with))->fetchAll(); + $counter++; + } + $target = $newTarget; + } + $query->execute(array($uid_owner, $uid_shared_with, $source, $target, $permissions)); + } + } + } + + /** + * Remove any duplicate or trailing '/' from the path + * @return A clean path + */ + private static function cleanPath($path) { + $path = rtrim($path, "/"); + return preg_replace('{(/)\1+}', "/", $path); + } + + /** + * Get the user and the user's groups and put them into an array + * @return An array to be used by the IN operator in a query for uid_shared_with + */ + private static function getUserAndGroups() { + $self = OC_USER::getUser(); + $groups = OC_GROUP::getUserGroups($self); + array_unshift($groups, $self); + return $groups; + } + + /** + * Create a new entry in the database for a file inside a shared folder + * + * $oldTarget and $newTarget may be the same value. $oldTarget exists in case the file is being moved outside of the folder + * + * @param $oldTarget The current target location + * @param $newTarget The new target location + */ + public static function pullOutOfFolder($oldTarget, $newTarget) { + $folders = self::getParentFolders($oldTarget); + $source = $folders['source'].substr($oldTarget, strlen($folders['target'])); + $item = self::getItem($folders['target']); + $query = OC_DB::prepare("INSERT INTO *PREFIX*sharing VALUES(?,?,?,?,?)"); + $query->execute(array($item[0]['uid_owner'], OC_USER::getUser(), $source, $newTarget, $item[0]['is_writeable'])); + } + + /** + * Get the item with the specified target location + * @param $target The target location of the item + * @return An array with the item + */ + public static function getItem($target) { + $target = self::cleanPath($target); + $query = OC_DB::prepare("SELECT uid_owner, source, is_writeable FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with = ? LIMIT 1"); + return $query->execute(array($target, OC_USER::getUser()))->fetchAll(); + } + + /** + * Get all items the current user is sharing + * @return An array with all items the user is sharing + */ + public static function getMySharedItems() { + $query = OC_DB::prepare("SELECT uid_shared_with, source, is_writeable FROM *PREFIX*sharing WHERE uid_owner = ?"); + return $query->execute(array(OC_USER::getUser()))->fetchAll(); + } + + /** + * Get the items within a shared folder that have their own entry for the purpose of name, location, or permissions that differ from the folder itself + * + * Works for both target and source folders. Can be used for getting all items shared with you e.g. pass '/MTGap/files' + * + * @param $folder The folder of the items to look for + * @return An array with all items in the database that are in the folder + */ + public static function getItemsInFolder($folder) { + $folder = self::cleanPath($folder); + // Append '/' in order to filter out the folder itself if not already there + if (substr($folder, -1) !== "/") { + $folder .= "/"; + } + $length = strlen($folder); + $userAndGroups = self::getUserAndGroups(); + $query = OC_DB::prepare("SELECT uid_owner, source, target FROM *PREFIX*sharing WHERE SUBSTR(source, 1, ?) = ? OR SUBSTR(target, 1, ?) = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).")"); + return $query->execute(array_merge(array($length, $folder, $length, $folder), $userAndGroups))->fetchAll(); + } + + /** + * Get the source and target parent folders of the specified target location + * @param $target The target location of the item + * @return An array with the keys 'source' and 'target' with the values of the source and target parent folders + */ + public static function getParentFolders($target) { + $target = self::cleanPath($target); + $userAndGroups = self::getUserAndGroups(); + $query = OC_DB::prepare("SELECT source FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).") LIMIT 1"); + // Prevent searching for user directory e.g. '/MTGap/files' + $userDirectory = substr($target, 0, strpos($target, "files") + 5); + while ($target != "" && $target != "/" && $target != "." && $target != $userDirectory) { + // Check if the parent directory of this target location is shared + $target = dirname($target); + $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll(); + if (count($result) > 0) { + break; + } + } + if (count($result) > 0) { + // Return both the source folder and the target folder + return array("source" => $result[0]['source'], "target" => $target); + } else { + return false; + } + } + + /** + * Get the source location of the item at the specified target location + * @param $target The target location of the item + * @return Source location or false if target location is not valid + */ + public static function getSource($target) { + $target = self::cleanPath($target); + $userAndGroups = self::getUserAndGroups(); + $query = OC_DB::prepare("SELECT source FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).") LIMIT 1"); + $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll(); + if (count($result) > 0) { + return $result[0]['source']; + } else { + $folders = self::getParentFolders($target); + if ($folders == false) { + return false; + } else { + return $folders['source'].substr($target, strlen($folders['target'])); + } + } + } + + /** + * Check if the user has write permission for the item at the specified target location + * @param $target The target location of the item + * @return True if the user has write permission or false if read only + */ + public static function isWriteable($target) { + $target = self::cleanPath($target); + $userAndGroups = self::getUserAndGroups(); + $query = OC_DB::prepare("SELECT is_writeable FROM *PREFIX*sharing WHERE target = ? AND uid_shared_with IN(".substr(str_repeat(",?", count($userAndGroups)), 1).") LIMIT 1"); + $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll(); + if (count($result) > 0) { + return $result[0]['is_writeable']; + } else { + // Check if the folder is writeable + $folders = OC_SHARE::getParentFolders($target); + $result = $query->execute(array_merge(array($target), $userAndGroups))->fetchAll(); + if (count($result) > 0) { + return $result[0]['is_writeable']; + } else { + return false; + } + } + } + + /** + * Set the source location to a new value + * @param $oldSource The current source location + * @param $newTarget The new source location + */ + public static function setSource($oldSource, $newSource) { + $oldSource = self::cleanPath($oldSource); + $newSource = self::cleanPath($newSource); + $query = OC_DB::prepare("UPDATE *PREFIX*sharing SET source = REPLACE(source, ?, ?) WHERE uid_owner = ?"); + $query->execute(array($oldSource, $newSource, OC_USER::getUser())); + } + + /** + * Set the target location to a new value + * + * You must use the pullOutOfFolder() function to change the target location of a file inside a shared folder if the target location differs from the folder + * + * @param $oldTarget The current target location + * @param $newTarget The new target location + */ + public static function setTarget($oldTarget, $newTarget) { + $oldTarget = self::cleanPath($oldTarget); + $newTarget = self::cleanPath($newTarget); + $query = OC_DB::prepare("UPDATE *PREFIX*sharing SET target = REPLACE(target, ?, ?) WHERE uid_shared_with = ?"); + $query->execute(array($oldTarget, $newTarget, OC_USER::getUser())); + } + + /** + * Change write permission for the specified item and user + * + * You must construct a new shared item to change the write permission of a file inside a shared folder if the write permission differs from the folder + * + * @param $source The source location of the item + * @param $uid_shared_with Array of users to change the write permission for + * @param $is_writeable True if the user has write permission or false if read only + */ + public static function setIsWriteable($source, $uid_shared_with, $is_writeable) { + $source = self::cleanPath($source); + $query = OC_DB::prepare("UPDATE *PREFIX*sharing SET is_writeable = ? WHERE SUBSTR(source, 1, ?) = ? AND uid_shared_with = ? AND uid_owner = ?"); + $query->execute(array($is_writeable, strlen($source), $source, $uid_shared_with, OC_USER::getUser())); + } + + /** + * Unshare the item, removes it from all specified users + * + * You must use the pullOutOfFolder() function to unshare a file inside a shared folder and set $newTarget to nothing + * + * @param $source The source location of the item + * @param $uid_shared_with Array of users to unshare the item from + */ + public static function unshare($source, $uid_shared_with) { + $source = self::cleanPath($source); + $query = OC_DB::prepare("DELETE FROM *PREFIX*sharing WHERE SUBSTR(source, 1, ?) = ? AND uid_shared_with = ? AND uid_owner = ?"); + $query->execute(array(strlen($source), $source, $uid_shared_with, OC_USER::getUser())); + } + + /** + * Unshare the item from the current user, removes it only from the database and doesn't touch the source file + * + * You must use the pullOutOfFolder() function to unshare a file inside a shared folder and set $newTarget to nothing + * + * @param $target The target location of the item + */ + public static function unshareFromMySelf($target) { + $target = self::cleanPath($target); + $query = OC_DB::prepare("DELETE FROM *PREFIX*sharing WHERE SUBSTR(target, 1, ?) = ? AND uid_shared_with = ?"); + $query->execute(array(strlen($target), $target, OC_USER::getUser())); + } + + /** + * Remove the item from the database, the owner deleted the file + * @param $arguments Array of arguments passed from OC_HOOK + */ + public static function deleteItem($arguments) { + $source = "/".OC_USER::getUser()."/files".$arguments['path']; + $source = self::cleanPath($source); + $query = OC_DB::prepare("DELETE FROM *PREFIX*sharing WHERE SUBSTR(source, 1, ?) = ? AND uid_owner = ?"); + $query->execute(array(strlen($source), $source, OC_USER::getUser())); + } + + /** + * Rename the item in the database, the owner renamed the file + * @param $arguments Array of arguments passed from OC_HOOK + */ + public static function renameItem($arguments) { + $oldSource = "/".OC_USER::getUser()."/files".$arguments['oldpath']; + $oldSource = self::cleanPath($oldSource); + $newSource = "/".OC_USER::getUser()."/files".$arguments['newpath']; + $newSource = self::cleanPath($newSource); + self::setSource($oldSource, $newSource); + } + +} + +?> diff --git a/apps/files_sharing/list.php b/apps/files_sharing/list.php new file mode 100644 index 00000000000..6c27899369d --- /dev/null +++ b/apps/files_sharing/list.php @@ -0,0 +1,40 @@ +<?php +/** + * ownCloud + * + * @author Michael Gapczynski + * @copyright 2011 Michael Gapczynski GapczynskiM@gmail.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +require_once('../../lib/base.php'); +require_once('lib_share.php'); +require('template.php'); + +if (!OC_USER::isLoggedIn()){ + header( "Location: ".OC_HELPER::linkTo( "index.php" )); + exit(); +} + +OC_APP::setActiveNavigationEntry("files_sharing_list"); + +OC_UTIL::addScript("files_sharing", "list"); + +$tmpl = new OC_TEMPLATE("files_sharing", "list", "user"); +$tmpl->assign("shared_items", OC_SHARE::getMySharedItems()); +$tmpl->printPage(); + +?>
\ No newline at end of file diff --git a/apps/files_sharing/sharedstorage.php b/apps/files_sharing/sharedstorage.php new file mode 100644 index 00000000000..8efccbc769f --- /dev/null +++ b/apps/files_sharing/sharedstorage.php @@ -0,0 +1,510 @@ +<?php +/** + * ownCloud + * + * @author Michael Gapczynski + * @copyright 2011 Michael Gapczynski GapczynskiM@gmail.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +require_once( 'lib_share.php' ); + +OC_FILESYSTEM::registerStorageType('shared','OC_FILESTORAGE_SHARED',array('datadir'=>'string')); + +/** + * Convert target path to source path and pass the function call to the correct storage provider + */ +class OC_FILESTORAGE_SHARED extends OC_FILESTORAGE { + + private $datadir; + private $sourcePaths = array(); + + public function __construct($arguments) { + $this->datadir = $arguments['datadir']; + } + + public function getInternalPath($path) { + $mountPoint = OC_FILESYSTEM::getMountPoint($path); + $internalPath = substr($path, strlen($mountPoint)); + return $internalPath; + } + + public function getSource($target) { + $target = $this->datadir.$target; + if (array_key_exists($target, $this->sourcePaths)) { + return $this->sourcePaths[$target]; + } else { + $source = OC_SHARE::getSource($target); + $this->sourcePaths[$target] = $source; + return $source; + } + } + + public function mkdir($path) { + if ($path == "" || $path == "/") { + return false; + } else { + $source = $this->getSource($path); + if ($source) { + if (OC_SHARE::isWriteable($this->datadir.$path)) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->mkdir($this->getInternalPath($source)); + } + } + } + } + + public function rmdir($path) { + // The folder will be removed from the database, but won't be deleted from the owner's filesystem + OC_SHARE::unshareFromMySelf($this->datadir.$path); + } + + public function opendir($path) { + if ($path == "" || $path == "/") { + global $FAKEDIRS; + $path = $this->datadir.$path; + $sharedItems = OC_SHARE::getItemsInFolder($path); + if (empty($sharedItems)) { + return false; + } + foreach ($sharedItems as $item) { + // If item is in the root of the shared storage provider add it to the fakedirs + if (dirname($item['target'])."/" == $path) { + $files[] = basename($item['target']); + } + } + $FAKEDIRS['shared'] = $files; + return opendir('fakedir://shared'); + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + $dh = $storage->opendir($this->getInternalPath($source)); + // Remove any duplicate or trailing '/' + $path = rtrim($this->datadir.$path, "/"); + $path = preg_replace('{(/)\1+}', "/", $path); + $modifiedItems = OC_SHARE::getItemsInFolder($source); + if ($modifiedItems && $dh) { + global $FAKEDIRS; + $sources = array(); + $targets = array(); + foreach ($modifiedItems as $item) { + // If the item is in the current directory and has a different name than the source, add it to the arrays + if (dirname($item['target']) == $path && basename($item['source']) != basename($item['target'])) { + $sources[] = basename($item['source']); + $targets[] = basename($item['target']); + // If the item was unshared from self, add it it to the arrays + } elseif ($item['target'] == "/") { + $sources[] = basename($item['source']); + $targets[] = ""; + } + } + // Don't waste time if there aren't any modified items in the current directory + if (empty($sources)) { + return $dh; + } else { + while (($filename = readdir($dh)) !== false) { + if ($filename != "." && $filename != "..") { + // If the file isn't in the sources array it isn't modified and can be added as is + if (!in_array($filename, $sources)) { + $files[] = $filename; + // The file has a different name than the source and is added to the fakedirs + } else { + $target = $targets[array_search($filename, $sources)]; + // Don't add the file if it was unshared from self by the user + if ($target != "") { + $files[] = $target; + } + } + } + } + $FAKEDIRS['shared'] = $files; + return opendir('fakedir://shared'); + } + } else { + return $dh; + } + } + } + } + + public function is_dir($path) { + if ($path == "" || $path == "/") { + return true; + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->is_dir($this->getInternalPath($source)); + } + } + } + + public function is_file($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->is_file($this->getInternalPath($source)); + } + } + + // TODO fill in other components of array + public function stat($path) { + if ($path == "" || $path == "/") { + $stat["dev"] = ""; + $stat["ino"] = ""; + $stat["mode"] = ""; + $stat["nlink"] = ""; + $stat["uid"] = ""; + $stat["gid"] = ""; + $stat["rdev"] = ""; + $stat["size"] = $this->filesize($path); + $stat["atime"] = $this->fileatime($path); + $stat["mtime"] = $this->filemtime($path); + $stat["ctime"] = $this->filectime($path); + $stat["blksize"] = ""; + $stat["blocks"] = ""; + return $stat; + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->stat($this->getInternalPath($source)); + } + } + } + + public function filetype($path) { + if ($path == "" || $path == "/") { + return "dir"; + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->filetype($this->getInternalPath($source)); + } + } + + } + + public function filesize($path) { + if ($path == "" || $path == "/" || $this->is_dir($path)) { + return $this->getFolderSize($path); + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->filesize($this->getInternalPath($source)); + } + } + } + + public function getFolderSize($path) { + if ($path == "" || $path == "/") { + $dbpath = OC_USER::getUser()."/files/Share/"; + } else { + $source = $this->getSource($path); + $dbpath = $this->getInternalPath($source); + } + $query = OC_DB::prepare("SELECT size FROM *PREFIX*foldersize WHERE path=?"); + $size = $query->execute(array($dbpath))->fetchAll(); + if (count($size) > 0) { + return $size[0]['size']; + } else { + return $this->calculateFolderSize($path); + } + } + + public function calculateFolderSize($path) { + if ($this->is_file($path)) { + $path = dirname($path); + } + $path = str_replace("//", "/", $path); + if ($this->is_dir($path) && substr($path, -1) != "/") { + $path .= "/"; + } + $size = 0; + if ($dh = $this->opendir($path)) { + while (($filename = readdir($dh)) !== false) { + if ($filename != "." && $filename != "..") { + $subFile = $path.$filename; + if ($this->is_file($subFile)) { + $size += $this->filesize($subFile); + } else { + $size += $this->getFolderSize($subFile); + } + } + } + if ($size > 0) { + if ($path == "" || $path == "/") { + $dbpath = OC_USER::getUser()."/files/Share/"; + } else { + $source = $this->getSource($path); + $dbpath = $this->getInternalPath($source); + } + $query = OC_DB::prepare("INSERT INTO *PREFIX*foldersize VALUES(?,?)"); + $result = $query->execute(array($dbpath, $size)); + } + } + return $size; + } + + public function is_readable($path) { + return true; + } + + public function is_writeable($path) { + if ($path == "" || $path == "/") { + return true; + } else { + return OC_SHARE::isWriteable($this->datadir.$path); + } + } + + public function file_exists($path) { + if ($path == "" || $path == "/") { + return true; + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->file_exists($this->getInternalPath($source)); + } + } + } + + public function readfile($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->readfile($this->getInternalPath($source)); + } + } + + public function filectime($path) { + if ($path == "" || $path == "/") { + $ctime = 0; + $dir = $this->opendir($path); + while (($filename = readdir($dir)) != false) { + $tempctime = $this->filectime($filename); + if ($tempctime < $ctime) { + $ctime = $tempctime; + } + } + return $ctime; + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->filectime($this->getInternalPath($source)); + } + } + } + + public function filemtime($path) { + if ($path == "" || $path == "/") { + $mtime = 0; + $dir = $this->opendir($path); + while (($filename = readdir($dir)) != false) { + $tempmtime = $this->filemtime($filename); + if ($tempmtime > $mtime) { + $mtime = $tempmtime; + } + } + return $mtime; + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->filemtime($this->getInternalPath($source)); + } + } + } + + public function fileatime($path) { + if ($path == "" || $path == "/") { + $atime = 0; + $dir = $this->opendir($path); + while (($filename = readdir($dir)) != false) { + $tempatime = $this->fileatime($filename); + if ($tempatime > $atime) { + $atime = $tempatime; + } + } + return $atime; + } else { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->fileatime($this->getInternalPath($source)); + } + } + } + + public function file_get_contents($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->file_get_contents($this->getInternalPath($source)); + } + } + + // TODO OC_SHARE::getPermissions() + public function file_put_contents($path, $data) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->file_put_contents($this->getInternalPath($source), $data); + } + } + + public function unlink($path) { + // The file will be removed from the database, but won't be touched on the owner's filesystem + $target = $this->datadir.$path; + // If file is inside a shared folder + if (OC_SHARE::getParentFolders($target)) { + // If entry for file already exists + if (OC_SHARE::getItem($target)) { + OC_SHARE::setTarget($target, "/"); + } else { + OC_SHARE::pullOutOfFolder($target, "/"); + } + } else { + OC_SHARE::unshareFromMySelf($target); + } + return true; + } + + public function rename($path1, $path2) { + // The file will be renamed in the database, but won't be touched on the owner's filesystem + $oldTarget = $this->datadir.$path1; + $newTarget = $this->datadir.$path2; + if (OC_SHARE::getItem($oldTarget)) { + OC_SHARE::setTarget($oldTarget, $newTarget); + } else { + OC_SHARE::pullOutOfFolder($oldTarget, $newTarget); + if (self::is_dir($path1)) { + OC_SHARE::setTarget($oldTarget, $newTarget); + } + } + return true; + } + + public function copy($path1, $path2) { + if ($path2 == "" || $path2 == "/") { + // TODO Construct new shared item or should this not be allowed? + } else { + if ($this->is_writeable($path)) { + $tmpFile = $this->toTmpFile($path1); + return $this->fromTmpFile($tmpFile, $path2); + } else { + return false; + } + } + } + + public function fopen($path, $mode) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->fopen($this->getInternalPath($source), $mode); + } + } + + public function toTmpFile($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->toTmpFile($this->getInternalPath($source)); + } + } + + public function fromTmpFile($tmpFile, $path) { + if ($this->is_writeable($path)) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->fromTmpFile($tmpFile, $this->getInternalPath($source)); + } + } else { + return false; + } + } + + public function fromUploadedFile($tmpPath, $path) { + $source = $this->getSource($tmpPath); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->fromUploadedFile($this->getInternalPath($source), $path); + } + } + + public function getMimeType($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->getMimeType($this->getInternalPath($source)); + } + } + + public function delTree($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->delTree($this->getInternalPath($source)); + } + } + + public function find($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->find($this->getInternalPath($source)); + } + } + + public function getTree($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->getTree($this->getInternalPath($source)); + } + } + + public function hash($type, $path, $raw) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->hash($type, $this->getInternalPath($source), $raw); + } + } + + public function free_space($path) { + $source = $this->getSource($path); + if ($source) { + $storage = OC_FILESYSTEM::getStorage($source); + return $storage->free_space($this->getInternalPath($source)); + } + } + + // TODO query all shared files? + public function search($query) { + + } + +} + +?>
\ No newline at end of file diff --git a/apps/files_sharing/templates/list.php b/apps/files_sharing/templates/list.php new file mode 100644 index 00000000000..73ffff1ab6b --- /dev/null +++ b/apps/files_sharing/templates/list.php @@ -0,0 +1,30 @@ +<fieldset> + <legend>Your Shared Files</legend> + <table id='itemlist'> + <thead> + <tr> + <th>Item</th> + <th>Shared With</th> + <th>Permissions</th> + </tr> + </thead> + <tbody> + <?php foreach($_['shared_items'] as $item):?> + <tr class='item'> + <td class='source'><?php echo substr($item['source'], strlen("/".$_SESSION['user_id']."/files/"));?></td> + <td class='uid_shared_with'><?php echo $item['uid_shared_with'];?></td> + <td class='permissions'><?php echo $item['is_writeable'];?></td> + <td><button class='delete fancybutton' data-source='<?php echo $item['source'];?>' data-uid_shared_with='<?php echo $item['uid_shared_with'];?>'>Delete</button></td> + </tr> + <?php endforeach;?> + <tr id='share_item_row'> + <form action='#' id='share_item'> + <td class='source'><input placeholder='Item' id='source'/></td> + <td class='uid_shared_with'><input placeholder='Share With' id='uid_shared_with'/></td> + <td class='permissions'><input placeholder='Permissions' id='permissions'/></td> + <td><input type='submit' value='Share'/></td> + </form> + </tr> + </tbody> + </table> +</fieldset> diff --git a/lib/base.php b/lib/base.php index 4636dd703ed..d81479e5a28 100644 --- a/lib/base.php +++ b/lib/base.php @@ -84,6 +84,7 @@ require_once('appconfig.php'); require_once('files.php'); require_once('filesystem.php'); require_once('filestorage.php'); +require_once('apps/files_sharing/sharedstorage.php'); require_once('l10n.php'); require_once('preferences.php'); require_once('log.php'); @@ -164,6 +165,10 @@ class OC_UTIL { // } OC_FILESYSTEM::mount($rootStorage,'/'); + // TODO add this storage provider in a proper way + $sharedStorage = OC_FILESYSTEM::createStorage('shared',array('datadir'=>'/'.OC_USER::getUser().'/files/Share/')); + OC_FILESYSTEM::mount($sharedStorage,'/'.OC_USER::getUser().'/files/Share/'); + $CONFIG_DATADIRECTORY = "$CONFIG_DATADIRECTORY_ROOT/$user/$root"; if( !is_dir( $CONFIG_DATADIRECTORY )){ mkdir( $CONFIG_DATADIRECTORY, 0755, true ); diff --git a/lib/filesystem.php b/lib/filesystem.php index b82fe2afebf..2c26667bbee 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -175,7 +175,7 @@ class OC_FILESYSTEM{ * @param string path * @return OC_FILESTORAGE */ - static private function getStorage($path){ + static public function getStorage($path){ $mountpoint=self::getMountPoint($path); if($mountpoint){ return self::$storages[$mountpoint]; @@ -189,7 +189,7 @@ class OC_FILESYSTEM{ * @param string path * @return string */ - static private function getMountPoint($path){ + static public function getMountPoint($path){ if(!$path){ $path='/'; } @@ -214,6 +214,7 @@ class OC_FILESYSTEM{ } return $foundMountPoint; } + /** * return the path to a local version of the file * we need this because we can't know if a file is stored local or not from outside the filestorage and for some purposes a local file is needed |