Merge branch 'master' of https://code.grnet.gr/git/pithos
authorAntony Chazapis <chazapis@gmail.com>
Thu, 15 Sep 2011 23:22:52 +0000 (02:22 +0300)
committerAntony Chazapis <chazapis@gmail.com>
Thu, 15 Sep 2011 23:22:52 +0000 (02:22 +0300)
25 files changed:
pithos/backends/lib/sqlalchemy/public.py
pithos/backends/lib/sqlalchemy/xfeatures.py
tools/lib/client.py
tools/store
tools/test
web_client/src/gr/grnet/pithos/web/client/DeleteFileDialog.java
web_client/src/gr/grnet/pithos/web/client/FileContextMenu.java
web_client/src/gr/grnet/pithos/web/client/FileList.java
web_client/src/gr/grnet/pithos/web/client/FilePropertiesDialog.java
web_client/src/gr/grnet/pithos/web/client/FileUploadDialog.java
web_client/src/gr/grnet/pithos/web/client/FolderContextMenu.java
web_client/src/gr/grnet/pithos/web/client/FolderPropertiesDialog.java
web_client/src/gr/grnet/pithos/web/client/PermissionsList.java
web_client/src/gr/grnet/pithos/web/client/Pithos.java
web_client/src/gr/grnet/pithos/web/client/TreeView.java [new file with mode: 0644]
web_client/src/gr/grnet/pithos/web/client/VersionsList.java
web_client/src/gr/grnet/pithos/web/client/commands/EmptyTrashCommand.java
web_client/src/gr/grnet/pithos/web/client/commands/PasteCommand.java
web_client/src/gr/grnet/pithos/web/client/foldertree/AccountResource.java
web_client/src/gr/grnet/pithos/web/client/foldertree/FolderTreeView.java
web_client/src/gr/grnet/pithos/web/client/foldertree/FolderTreeViewModel.java
web_client/src/gr/grnet/pithos/web/client/mysharedtree/MysharedTreeView.java
web_client/src/gr/grnet/pithos/web/client/mysharedtree/MysharedTreeViewModel.java
web_client/src/gr/grnet/pithos/web/client/othersharedtree/OtherSharedTreeView.java
web_client/src/gr/grnet/pithos/web/client/othersharedtree/OtherSharedTreeViewModel.java

index 7037e7a..4b2327e 100644 (file)
@@ -49,7 +49,7 @@ class Public(DBWorker):
     
     def public_set(self, path):
         s = self.public.select()
-        s = s.where(self.xfeaturevals.c.path == path)
+        s = s.where(self.public.c.path == path)
         r = self.conn.execute(s)
         public = r.fetchall()
         r.close()
index 577b3aa..084107e 100644 (file)
@@ -145,6 +145,7 @@ class XFeatures(DBWorker):
         s = self.xfeaturevals.select()
         s = s.where(self.xfeaturevals.c.feature_id == feature)
         s = s.where(self.xfeaturevals.c.key == key)
+        s = s.where(self.xfeaturevals.c.value == value)
         r = self.conn.execute(s)
         xfeaturevals = r.fetchall()
         r.close()
index 40f2a24..461c7db 100644 (file)
@@ -34,6 +34,7 @@
 from httplib import HTTPConnection, HTTP
 from sys import stdin
 from xml.dom import minidom
+from StringIO import StringIO
 
 import json
 import types
@@ -72,7 +73,8 @@ class Client(object):
         self.token = token
     
     def _req(self, method, path, body=None, headers={}, format='text', params={}):
-        full_path = '/%s%s?format=%s' % (self.api, path, format)
+        slash = '/' if self.api else ''
+        full_path = '%s%s%s?format=%s' % (slash, self.api, path, format)
         
         for k,v in params.items():
             if v:
@@ -204,8 +206,9 @@ class Client(object):
         return self._req('POST', path, body, headers=headers, format=format,
                         params=params)
     
-    def put(self, path, body=None, format='text', headers=None):
-        return self._req('PUT', path, body, headers=headers, format=format)
+    def put(self, path, body=None, format='text', headers=None, params={}):
+        return self._req('PUT', path, body, headers=headers, format=format,
+                         params=params)
     
     def _list(self, path, format='text', params={}, **headers):
         status, headers, data = self.get(path, format=format, headers=headers,
@@ -399,7 +402,7 @@ class OOS_Client(Client):
     def retrieve_object_hashmap(self, container, object, params={},
                         account=None, **headers):
         """returns the hashmap representing object's data"""
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'object']:
             args.pop(elem)
         data = self.retrieve_object(container, object, format='json', **args)
@@ -415,7 +418,7 @@ class OOS_Client(Client):
                                               **h)
     
     def create_object(self, container, object, f=stdin, format='text', meta={},
-                      etag=None, content_type=None, content_encoding=None,
+                      params={}, etag=None, content_type=None, content_encoding=None,
                       content_disposition=None, account=None, **headers):
         """creates a zero-length object"""
         account = account or self.account
@@ -433,14 +436,14 @@ class OOS_Client(Client):
         for k,v in meta.items():
             headers['x-object-meta-%s' %k.strip()] = v.strip()
         data = f.read() if f else None
-        return self.put(path, data, format, headers=headers)
+        return self.put(path, data, format, headers=headers, params=params)
     
     def create_zero_length_object(self, container, object, meta={}, etag=None,
                                   content_type=None, content_encoding=None,
                                   content_disposition=None, account=None,
                                   **headers):
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'headers', 'account']:
             args.pop(elem)
         args.update(headers)
@@ -681,7 +684,7 @@ class Pithos_Client(OOS_Client):
         params = {'until':until, 'meta':meta}
         if shared:
             params['shared'] = None
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'params', 'until', 'meta']:
             args.pop(elem)
         return OOS_Client.list_objects(self, container, params=params, **args)
@@ -728,6 +731,8 @@ class Pithos_Client(OOS_Client):
         l = [elem for elem in l if eval(elem)]
         for elem in l:
             headers.update({elem:eval(elem)})
+        if format != 'text':
+            params['hashmap'] = None
         return OOS_Client.retrieve_object(self, container, object,
                                           account=account, format=format,
                                           params=params, **headers)
@@ -739,7 +744,7 @@ class Pithos_Client(OOS_Client):
                                 account=None):
         """returns a specific object version"""
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         l = ['self', 'container', 'object']
         for elem in l:
             args.pop(elem)
@@ -752,7 +757,7 @@ class Pithos_Client(OOS_Client):
                                     if_unmodified_since=None, account=None):
         """returns the object version list"""
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         l = ['self', 'container', 'object']
         for elem in l:
             args.pop(elem)
@@ -768,20 +773,20 @@ class Pithos_Client(OOS_Client):
                                   x_object_public=None, account=None):
         """createas a zero length object"""
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'object']:
             args.pop(elem)
         return OOS_Client.create_zero_length_object(self, container, object,
                                                     **args)
     
-    def create_object(self, container, object, f=stdin, 
-                      meta={}, etag=None, content_type=None,
+    def create_object(self, container, object, f=stdin, format='text',
+                      meta={}, params={}, etag=None, content_type=None,
                       content_encoding=None, content_disposition=None,
                       x_object_manifest=None, x_object_sharing=None,
                       x_object_public=None, account=None):
         """creates an object"""
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'object']:
             args.pop(elem)
         return OOS_Client.create_object(self, container, object, **args)
@@ -810,27 +815,25 @@ class Pithos_Client(OOS_Client):
         return self._chunked_transfer(path, 'PUT', f, headers=headers,
                                       blocksize=blocksize)
     
-    def create_object_by_hashmap(container, object, f=stdin, format='json',
+    def create_object_by_hashmap(self, container, object, hashmap={},
                                  meta={}, etag=None, content_encoding=None,
                                  content_disposition=None, content_type=None,
                                  x_object_sharing=None, x_object_manifest=None,
                                  x_object_public = None, account=None):
         """creates an object by uploading hashes representing data instead of data"""
         account = account or self.account
-        args = locals()
-        for elem in ['self', 'container', 'object']:
+        args = locals().copy()
+        for elem in ['self', 'container', 'object', 'hashmap']:
             args.pop(elem)
             
-        data = f.read() if f else None
-        if data and format == 'json':
-            try:
-                data = eval(data)
-                data = json.dumps(data)
-            except SyntaxError:
-                raise Fault('Invalid formatting')
+        try:
+            data = json.dumps(hashmap)
+        except SyntaxError:
+            raise Fault('Invalid formatting')
+        args['params'] = {'hashmap':None}
+        args['format'] = 'json'
         
-        #TODO check with xml
-        return self.create_object(container, object, **args)
+        return self.create_object(container, object, f=StringIO(data), **args)
     
     def create_manifestation(self, container, object, manifest, account=None):
         """creates a manifestation"""
@@ -848,7 +851,7 @@ class Pithos_Client(OOS_Client):
                       x_source_object=None, account=None):
         """updates an object"""
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'object', 'replace']:
             args.pop(elem)
         if not replace:
@@ -863,7 +866,7 @@ class Pithos_Client(OOS_Client):
                                    x_object_public=None, account=None):
         """updates an object (incremental upload)"""
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'object', 'replace']:
             args.pop(elem)
         if not replace:
@@ -877,7 +880,7 @@ class Pithos_Client(OOS_Client):
                       x_object_sharing=None, x_object_public=None, account=None):
         """updates an object"""
         account = account or self.account
-        args = locals()
+        args = locals().copy()
         for elem in ['self', 'container', 'object', 'source']:
             args.pop(elem)
         
index d1e3614..4eee33f 100755 (executable)
@@ -399,9 +399,13 @@ class PutObject(Command):
             self.client.create_object_using_chunks(container, object, f,
                                                     meta=meta, **args)
         elif self.use_hashes:
-            format = 'json' if detail else 'text'
-            self.client.create_object_by_hashmap(container, object, f, format,
-                                 meta=meta, **args)
+            data = f.read()
+            if data is object:
+                hashmap = json.loads()
+                self.client.create_object_by_hashmap(container, object, hashmap,
+                                                 meta=meta, **args)
+            else:
+                print "Expected object"
         elif self.x_object_manifest:
             self.client.create_manifestation(container, object, self.x_object_manifest)
         elif not f:
index a737a4c..ca34fae 100755 (executable)
@@ -276,8 +276,8 @@ class BaseTestCase(unittest.TestCase):
             obj['meta'] = args
             
             path = '/%s/%s' % (container, name)
-            self.client.create_object(container, name, StringIO(obj['data']),
-                                      meta, **args)
+            self.client.create_object(container, name, f=StringIO(obj['data']),
+                                      meta=meta, **args)
             
             return obj
         except IOError:
@@ -1326,6 +1326,16 @@ class ObjectPut(BaseTestCase):
         self.assertEqual(int(zero_meta['content-length']), 0)
         self.assertEqual(zero_hash, [])
         self.assertEqual(zero_data, '')
+    
+    def test_create_object_by_hashmap(self):
+        c = self.container
+        o = 'object'
+        self.upload_random_data(c, o)
+        hashmap = self.client.retrieve_object(c, o, format='json')
+        o2 = 'object-copy'
+        self.client.create_object_by_hashmap(c, o2, hashmap)
+        self.assertEqual(self.client.retrieve_object(c, o),
+                         self.client.retrieve_object(c, o))
 
 class ObjectCopy(BaseTestCase):
     def setUp(self):
@@ -1912,7 +1922,7 @@ class TestPermissions(BaseTestCase):
         self.initial_meta = self.client.retrieve_account_metadata(restricted=True)
         
         #create a group
-        self.authorized = ['chazapis', 'verigak', 'gtsouk', 'papagian']
+        self.authorized = ['chazapis', 'verigak', 'gtsouk']
         groups = {'pithosdev':','.join(self.authorized)}
         self.client.set_account_groups(**groups)
     
@@ -1933,13 +1943,10 @@ class TestPermissions(BaseTestCase):
         
         BaseTestCase.tearDown(self)
     
-    def test_read_access(self):
-        self.client.create_container('c')
-        o = self.upload_random_data('c', 'o')
-        self.client.share_object('c', 'o', ['%s:pithosdev' % get_user()])
+    def assert_read(self, authorized=[], any=False):
         for token, account in OTHER_ACCOUNTS.items():
             cl = Pithos_Client(get_server(), token, account, get_api()) 
-            if account in self.authorized:
+            if account in authorized or any:
                 self.assert_not_raises_fault(401, cl.retrieve_object_metadata,
                                              'c', 'o', account=get_user())
             else:
@@ -1950,29 +1957,30 @@ class TestPermissions(BaseTestCase):
         o = self.upload_random_data('c', 'o/also-shared')
         for token, account in OTHER_ACCOUNTS.items():
             cl = Pithos_Client(get_server(), token, account, get_api()) 
-            if account in self.authorized:
+            if account in authorized or any:
                 self.assert_not_raises_fault(401, cl.retrieve_object_metadata,
                                              'c', 'o/also-shared', account=get_user())
             else:
                 self.assert_raises_fault(401, cl.retrieve_object_metadata,
                                          'c', 'o/also-shared', account=get_user())
     
-    def test_write_access(self):
-        self.client.create_container('c')
-        o = self.upload_random_data('c', 'o')
-        self.client.share_object('c', 'o', ['chazapis'], read=False)
-        o_data = o['data']
+    def assert_write(self, o_data, authorized=[], any=False):
         for token, account in OTHER_ACCOUNTS.items():
             cl = Pithos_Client(get_server(), token, account, get_api()) 
             new_data = get_random_data()
-            if account in [get_user(), 'chazapis']:
+            if account in authorized or any:
+                # test write access
                 self.assert_not_raises_fault(401, cl.update_object,
                                              'c', 'o', StringIO(new_data),
                                              account=get_user())
-                server_data = self.client.retrieve_object('c', 'o')
-                self.assertEqual(o_data, server_data[:len(o_data)])
-                self.assertEqual(new_data, server_data[len(o_data):])
-                o_data = server_data
+                try:
+                    # test read access
+                    server_data = cl.retrieve_object('c', 'o', account=get_user())
+                    self.assertEqual(o_data, server_data[:len(o_data)])
+                    self.assertEqual(new_data, server_data[len(o_data):])
+                    o_data = server_data
+                except Fault, f:
+                    self.failIf(f.status == 401)
             else:
                 self.assert_raises_fault(401, cl.update_object,
                                              'c', 'o', StringIO(new_data),
@@ -1984,20 +1992,75 @@ class TestPermissions(BaseTestCase):
         for token, account in OTHER_ACCOUNTS.items():
             cl = Pithos_Client(get_server(), token, account, get_api()) 
             new_data = get_random_data()
-            if account in [get_user(), 'chazapis']:
+            if account in authorized or any:
+                # test write access
                 self.assert_not_raises_fault(401, cl.update_object,
                                              'c', o['name'],
                                              StringIO(new_data),
                                              account=get_user())
-                server_data = self.client.retrieve_object('c', o['name'])
-                self.assertEqual(o_data, server_data[:len(o_data)])
-                self.assertEqual(new_data, server_data[len(o_data):])
-                o_data = server_data
+                try:
+                    server_data = cl.retrieve_object('c', o['name'], account=get_user())
+                    self.assertEqual(o_data, server_data[:len(o_data)])
+                    self.assertEqual(new_data, server_data[len(o_data):])
+                    o_data = server_data
+                except Fault, f:
+                    self.failIf(f.status == 401)
             else:
                 self.assert_raises_fault(401, cl.update_object,
                                              'c', o['name'],
                                              StringIO(new_data),
                                              account=get_user())
+    
+    def test_group_read(self):
+        self.client.create_container('c')
+        o = self.upload_random_data('c', 'o')
+        self.client.share_object('c', 'o', ['%s:pithosdev' % get_user()])
+        self.assert_read(authorized=self.authorized)
+    
+    def test_read_many(self):
+        #test read access
+        self.client.create_container('c')
+        o = self.upload_random_data('c', 'o')
+        self.client.share_object('c', 'o', self.authorized)
+        self.assert_read(authorized=self.authorized)
+    
+    def test_read_by_everyone(self):
+        self.client.create_container('c')
+        o = self.upload_random_data('c', 'o')
+        self.client.share_object('c', 'o', ['*'])
+        self.assert_read(any=True)
+    
+    def test_group_write(self):
+        self.client.create_container('c')
+        o = self.upload_random_data('c', 'o')
+        self.client.share_object('c', 'o', ['%s:pithosdev' % get_user()], read=False)
+        self.assert_write(o['data'], authorized=self.authorized)
+    
+    def test_write_many(self):
+        self.client.create_container('c')
+        o = self.upload_random_data('c', 'o')
+        self.client.share_object('c', 'o', self.authorized, read=False)
+        self.assert_write(o['data'], authorized=self.authorized)
+    
+    def test_write_by_everyone(self):
+        self.client.create_container('c')
+        o = self.upload_random_data('c', 'o')
+        self.client.share_object('c', 'o', ['*'], read=False)
+        o_data = o['data']
+        self.assert_write(o['data'], any=True)
+
+class TestPublish(BaseTestCase):
+    def test_publish(self):
+        self.client.create_container('c')
+        o_data = self.upload_random_data('c', 'o')['data']
+        self.client.publish_object('c', 'o')
+        meta = self.client.retrieve_object_metadata('c', 'o')
+        self.assertTrue('x-object-public' in meta)
+        url = '/public/%s/c/o' % get_user()
+        self.assertEqual(meta['x-object-public'], url)
+        public_client = Pithos_Client(get_server(), get_auth(), get_user(), api='')
+        data = public_client.get(url)[2]
+        self.assertEqual(o_data, data)
 
 class AssertMappingInvariant(object):
     def __init__(self, callable, *args, **kwargs):
index 2694d52..5845397 100644 (file)
@@ -134,7 +134,7 @@ public class DeleteFileDialog extends DialogBox {
         if (iter.hasNext()) {\r
             File f = iter.next();\r
             String path = f.getUri();\r
-            DeleteRequest deleteFile = new DeleteRequest(app.getApiPath(), app.getUsername(), path) {\r
+            DeleteRequest deleteFile = new DeleteRequest(app.getApiPath(), f.getOwner(), path) {\r
                 @Override\r
                 public void onSuccess(@SuppressWarnings("unused") Resource result) {\r
                     deleteFile(iter);\r
index 675410b..3dff03b 100644 (file)
@@ -179,46 +179,64 @@ public class FileContextMenu extends PopupPanel {
         *
         * @param newImages the image bundle passed on by the parent object
         */
-       public FileContextMenu(final Pithos app, Images newImages, Folder selectedFolder, List<File> selectedFiles, boolean isTrash) {
+       public FileContextMenu(final Pithos app, Images newImages, TreeView selectedTree, Folder selectedFolder, List<File> selectedFiles, boolean isTrash) {
                // The popup's constructor's argument is a boolean specifying that it
                // auto-close itself when the user clicks outside of it.
                super(true);
                setAnimationEnabled(true);
                images = newImages;
         MenuBar contextMenu = new MenuBar(true);
+        Boolean[] permissions = null;
+        boolean canWrite = true;
+        if (selectedFolder != null) {
+               permissions = selectedFolder.getPermissions().get(app.getUsername());
+               canWrite = selectedFolder.getOwner().equals(app.getUsername()) || (permissions!= null && permissions[1] != null && permissions[1]);
+               }
+        else {
+               for (File f : selectedFiles) {
+                       permissions = f.getPermissions().get(app.getUsername());
+                       canWrite &= (f.getOwner().equals(app.getUsername()) || (permissions!= null && permissions[1] != null && permissions[1]));
+               }
+        }
 
-        if (!selectedFolder.isInTrash()) {
-               if (app.getClipboard().hasFiles()) {
+        if (selectedFolder != null && !selectedFolder.isInTrash()) {
+               if (canWrite && app.getClipboard().hasFiles()) {
                    pasteItem = new MenuItem("<span>" + AbstractImagePrototype.create(images.paste()).getHTML() + "&nbsp;Paste</span>", true, new PasteCommand(app, this, selectedFolder));
                    contextMenu.addItem(pasteItem);
                }
 
-               MenuItem upload = new MenuItem("<span>" + AbstractImagePrototype.create(images.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(app, this, selectedFolder));
-               contextMenu.addItem(upload);
-
-                       cutItem = new MenuItem("<span id='fileContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(app, this, selectedFiles));
-            contextMenu.addItem(cutItem);
+               if (canWrite) {
+                       MenuItem upload = new MenuItem("<span>" + AbstractImagePrototype.create(images.fileUpdate()).getHTML() + "&nbsp;Upload</span>", true, new UploadFileCommand(app, this, selectedFolder));
+                       contextMenu.addItem(upload);
+       
+                               cutItem = new MenuItem("<span id='fileContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(app, this, selectedFiles));
+                   contextMenu.addItem(cutItem);
+               }
 
                        copyItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(app, this, selectedFiles));
             contextMenu.addItem(copyItem);
 
-                       trashItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(app, this, selectedFiles));
-            contextMenu.addItem(trashItem);
+            if (selectedTree.equals(app.getFolderTreeView())) {
+                               trashItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(app, this, selectedFiles));
+                   contextMenu.addItem(trashItem);
+            }
         }
         else {
                        MenuItem restore = new MenuItem("<span>" + AbstractImagePrototype.create(images.versions()).getHTML() + "&nbsp;Restore</span>", true, new RestoreTrashCommand(app, this, selectedFiles));
                        contextMenu.addItem(restore);
         }
 
-               deleteItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(app, this, selectedFiles, MessagePanel.images));
-        contextMenu.addItem(deleteItem);
+        if (canWrite) {
+                       deleteItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(app, this, selectedFiles, MessagePanel.images));
+               contextMenu.addItem(deleteItem);
+        }
 
 //      MenuItem refresh = new MenuItem("<span>" + AbstractImagePrototype.create(images.refresh()).getHTML() + "&nbsp;Refresh</span>", true, new RefreshCommand(this, images));
 //      contextMenu.addItem(refresh);
 //                     sharingItem = new MenuItem("<span>" + AbstractImagePrototype.create(newImages.sharing()).getHTML() + "&nbsp;Sharing</span>", true, new PropertiesCommand(this, images, 1));
 //            contextMenu.addItem(sharingItem);
         if (!selectedFolder.isInTrash()) {
-               if (selectedFiles.size() == 1)
+               if (canWrite && selectedFiles.size() == 1)
                        contextMenu.addItem(new MenuItem("<span>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(app, this, selectedFiles, images, 0)));
 
             if (!selectedFiles.isEmpty())
index 12ef1fd..d614f30 100644 (file)
@@ -314,12 +314,15 @@ public class FileList extends Composite {
         vp.addHandler(new ContextMenuHandler() {
             @Override
             public void onContextMenu(ContextMenuEvent event) {
-                Folder selectedFolder = treeView.getSelection();
-                FileContextMenu contextMenu = new FileContextMenu(app, images, selectedFolder, getSelectedFiles(), false);
-                int x = event.getNativeEvent().getClientX();
-                int y = event.getNativeEvent().getClientY();
-                contextMenu.setPopupPosition(x, y);
-                contextMenu.show();
+               TreeView tree = app.getSelectedTree();
+               if (tree != null && (tree.equals(app.getFolderTreeView()) || tree.equals(app.getOtherSharedTreeView()))) {
+                       Folder selectedFolder = app.getSelection();
+                       FileContextMenu contextMenu = new FileContextMenu(app, images, tree, selectedFolder, getSelectedFiles(), false);
+                       int x = event.getNativeEvent().getClientX();
+                       int y = event.getNativeEvent().getClientY();
+                       contextMenu.setPopupPosition(x, y);
+                       contextMenu.show();
+               }
             }
         }, ContextMenuEvent.getType());
                initWidget(vp);
index 95c5edd..d5343a8 100644 (file)
@@ -398,7 +398,7 @@ public class FilePropertiesDialog extends AbstractPropertiesDialog {
             PutRequest updateFile = new PutRequest(app.getApiPath(), app.getUsername(), path) {\r
                 @Override\r
                 public void onSuccess(@SuppressWarnings("unused") Resource result) {\r
-                    updateMetaData(app.getApiPath(), app.getUsername(), path + "?update=", newTags, finalPublished, perms);\r
+                    updateMetaData(app.getApiPath(), file.getOwner(), path + "?update=", newTags, finalPublished, perms);\r
                 }\r
 \r
                 @Override\r
index 3026d4c..e6f8a2f 100644 (file)
@@ -171,7 +171,10 @@ public class FileUploadDialog extends DialogBox {
                                        GWT.log(results, null);
                                        app.displayError(results);
                                }
-                app.updateFolder(folder, true, null);
+                               if (app.getSelectedTree().equals(app.getFolderTreeView()))
+                                       app.updateFolder(folder, true, null);
+                               else
+                                       app.updateOtherSharedFolder(folder, true);
                                hide();
                        }
                });
@@ -206,7 +209,7 @@ public class FileUploadDialog extends DialogBox {
             return;
         }
         final String fname = getFilename(upload.getFilename());
-        String apath = app.getApiPath() + app.getUsername() + folder.getUri() + "/" + fname;
+        String apath = app.getApiPath() + folder.getOwner() + folder.getUri() + "/" + fname;
         form.setAction(apath);
         submit.setEnabled(false);
         upload.setVisible(false);
index e5c5f8e..4743787 100644 (file)
@@ -82,33 +82,40 @@ public class FolderContextMenu extends PopupPanel {
                images = newImages;
         MenuBar contextMenu = new MenuBar(true);
 
-        if (!folder.isInTrash()) {
-               MenuItem newFolder = new MenuItem("<span id = 'folderContextMenu.newFolder'>" + AbstractImagePrototype.create(newImages.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(app, this, folder, images));
-               contextMenu.addItem(newFolder);
+        Boolean[] permissions = folder.getPermissions().get(app.getUsername());
+       boolean canWrite = folder.getOwner().equals(app.getUsername()) || (permissions!= null && permissions[1] != null && permissions[1]);
 
-               if (!folder.isContainer()) {
-                   MenuItem cut = new MenuItem("<span id = 'folderContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(app, this, folder));
-                   contextMenu.addItem(cut);
-               }
+        if (!folder.isInTrash()) {
+               if (canWrite) {
+                       MenuItem newFolder = new MenuItem("<span id = 'folderContextMenu.newFolder'>" + AbstractImagePrototype.create(newImages.folderNew()).getHTML() + "&nbsp;New Folder</span>", true, new NewFolderCommand(app, this, folder, images));
+                       contextMenu.addItem(newFolder);
+
+                       if (!folder.isContainer()) {
+                           MenuItem cut = new MenuItem("<span id = 'folderContextMenu.cut'>" + AbstractImagePrototype.create(newImages.cut()).getHTML() + "&nbsp;Cut</span>", true, new CutCommand(app, this, folder));
+                           contextMenu.addItem(cut);
+                       }
+               }
 
                MenuItem copy = new MenuItem("<span id = 'folderContextMenu.copy'>" + AbstractImagePrototype.create(newImages.copy()).getHTML() + "&nbsp;Copy</span>", true, new CopyCommand(app, this, folder));
                contextMenu.addItem(copy);
        
-               if (!app.getClipboard().isEmpty()) {
-                   pasteItem = new MenuItem("<span id = 'folderContextMenu.paste'>" + AbstractImagePrototype.create(newImages.paste()).getHTML() + "&nbsp;Paste</span>", true, new PasteCommand(app, this, folder));
-                   contextMenu.addItem(pasteItem);
-               }
-
-                   if (!folder.isContainer()) {
-                       MenuItem moveToTrash = new MenuItem("<span id = 'folderContextMenu.moveToTrash'>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(app, this, folder));
-                       contextMenu.addItem(moveToTrash);
-               
-                       MenuItem delete = new MenuItem("<span id = 'folderContextMenu.delete'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(app, this, folder, MessagePanel.images));
-                       contextMenu.addItem(delete);
-               
-                       MenuItem properties = new MenuItem("<span id = 'folderContextMenu.properties'>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(app, this, folder, newImages, 0));
-                       contextMenu.addItem(properties);
-                   }
+               if (canWrite) {
+                       if (!app.getClipboard().isEmpty()) {
+                           pasteItem = new MenuItem("<span id = 'folderContextMenu.paste'>" + AbstractImagePrototype.create(newImages.paste()).getHTML() + "&nbsp;Paste</span>", true, new PasteCommand(app, this, folder));
+                           contextMenu.addItem(pasteItem);
+                       }
+
+                           if (!folder.isContainer()) {
+                               MenuItem moveToTrash = new MenuItem("<span id = 'folderContextMenu.moveToTrash'>" + AbstractImagePrototype.create(newImages.emptyTrash()).getHTML() + "&nbsp;Move to Trash</span>", true, new ToTrashCommand(app, this, folder));
+                               contextMenu.addItem(moveToTrash);
+                       
+                               MenuItem delete = new MenuItem("<span id = 'folderContextMenu.delete'>" + AbstractImagePrototype.create(newImages.delete()).getHTML() + "&nbsp;Delete</span>", true, new DeleteCommand(app, this, folder, MessagePanel.images));
+                               contextMenu.addItem(delete);
+                       
+                               MenuItem properties = new MenuItem("<span id = 'folderContextMenu.properties'>" + AbstractImagePrototype.create(newImages.viewText()).getHTML() + "&nbsp;Properties</span>", true, new PropertiesCommand(app, this, folder, newImages, 0));
+                               contextMenu.addItem(properties);
+                           }
+               }
         }
         else {
                if (!folder.isTrash()) {
index a1e0015..fa07817 100644 (file)
@@ -49,6 +49,7 @@ import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.ClickEvent;\r
 import com.google.gwt.event.dom.client.ClickHandler;\r
 import com.google.gwt.event.dom.client.KeyCodes;\r
+import com.google.gwt.http.client.Response;\r
 import com.google.gwt.i18n.client.DateTimeFormat;\r
 import com.google.gwt.user.client.Event.NativePreviewEvent;\r
 import com.google.gwt.user.client.ui.Button;\r
@@ -260,7 +261,7 @@ public class FolderPropertiesDialog extends DialogBox {
        private void createFolder() {\r
                String name = folderName.getText();\r
         String path = folder.getUri() + "/" + name;\r
-        PutRequest createFolder = new PutRequest(app.getApiPath(), app.getUsername(), path) {\r
+        PutRequest createFolder = new PutRequest(app.getApiPath(), folder.getOwner(), path) {\r
             @Override\r
             public void onSuccess(@SuppressWarnings("unused") Resource result) {\r
                 app.updateFolder(folder, true, null);\r
@@ -301,15 +302,15 @@ public class FolderPropertiesDialog extends DialogBox {
         final String newName = folderName.getText().trim();\r
         if (!folder.isContainer() && !folder.getName().equals(newName)) {\r
             final String path = folder.getParent().getUri() + "/" + newName;\r
-            PutRequest newFolder = new PutRequest(app.getApiPath(), app.getUsername(), path) {\r
+            PutRequest newFolder = new PutRequest(app.getApiPath(), folder.getParent().getOwner(), path) {\r
                 @Override\r
                 public void onSuccess(@SuppressWarnings("unused") Resource result) {\r
                     Iterator<File> iter = folder.getFiles().iterator();\r
-                    app.copyFiles(iter, folder.getParent().getUri() + "/" + newName, new Command() {\r
+                    app.copyFiles(iter, folder.getParent().getOwner(), folder.getParent().getUri() + "/" + newName, new Command() {\r
                         @Override\r
                         public void execute() {\r
                             Iterator<Folder> iterf = folder.getSubfolders().iterator();\r
-                            app.copySubfolders(iterf, folder.getParent().getUri() + "/" + newName, new Command() {\r
+                            app.copySubfolders(iterf, folder.getParent().getOwner(), folder.getParent().getUri() + "/" + newName, new Command() {\r
                                 @Override\r
                                 public void execute() {\r
                                     app.deleteFolder(folder);\r
@@ -340,7 +341,7 @@ public class FolderPropertiesDialog extends DialogBox {
             updateMetadata(folder.getUri() + "?update=", perms);\r
        }\r
 \r
-       protected void updateMetadata(String path, Map<String, Boolean[]> newPermissions) {\r
+       protected void updateMetadata(final String path, final Map<String, Boolean[]> newPermissions) {\r
         if (newPermissions != null) {\r
             PostRequest updateFolder = new PostRequest(app.getApiPath(), folder.getOwner(), path) {\r
                 @Override\r
@@ -351,7 +352,34 @@ public class FolderPropertiesDialog extends DialogBox {
                 @Override\r
                 public void onError(Throwable t) {\r
                     GWT.log("", t);\r
-                    app.displayError("System error modifying folder: " + t.getMessage());\r
+                    if (t instanceof RestException) {\r
+                       if (((RestException) t).getHttpStatusCode() == Response.SC_NOT_FOUND) { //Probably a virtual folder\r
+                            final String path1 = folder.getUri();\r
+                            PutRequest newFolder = new PutRequest(app.getApiPath(), folder.getOwner(), path1) {\r
+                                @Override\r
+                                public void onSuccess(@SuppressWarnings("unused") Resource result) {\r
+                                       updateMetadata(path, newPermissions);\r
+                                }\r
+\r
+                                @Override\r
+                                public void onError(Throwable t) {\r
+                                    GWT.log("", t);\r
+                                    if(t instanceof RestException){\r
+                                        app.displayError("Unable to update folder: " + ((RestException) t).getHttpStatusText());\r
+                                    }\r
+                                    else\r
+                                        app.displayError("System error modifying folder: " + t.getMessage());\r
+                                }\r
+                            };\r
+                            newFolder.setHeader("X-Auth-Token", app.getToken());\r
+                            newFolder.setHeader("Content-Type", "application/folder");\r
+                            newFolder.setHeader("Accept", "*/*");\r
+                            newFolder.setHeader("Content-Length", "0");\r
+                            Scheduler.get().scheduleDeferred(newFolder);\r
+                       }\r
+                    }\r
+                    else\r
+                       app.displayError("System error modifying folder: " + t.getMessage());\r
                 }\r
             };\r
             updateFolder.setHeader("X-Auth-Token", app.getToken());\r
index 39aaad2..45ab6c7 100644 (file)
@@ -141,6 +141,7 @@ public class PermissionsList extends Composite {
                     public void onValueChange(ValueChangeEvent<Boolean> booleanValueChangeEvent) {
                         Boolean[] ps = permissions.get(user);
                         ps[0] = booleanValueChangeEvent.getValue();
+                        hasChanges = true;
                     }
                 });
                 write.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@@ -148,6 +149,7 @@ public class PermissionsList extends Composite {
                     public void onValueChange(ValueChangeEvent<Boolean> booleanValueChangeEvent) {
                         Boolean[] ps = permissions.get(user);
                         ps[1] = booleanValueChangeEvent.getValue();
+                        hasChanges = true;
                     }
                 });
                 PushButton removeButton = new PushButton(AbstractImagePrototype.create(images.delete()).createImage(), new ClickHandler() {
index a58e95c..1b51721 100644 (file)
@@ -240,17 +240,17 @@ public class Pithos implements EntryPoint, ResizeHandler {
      */
     private String token;
 
-    protected SingleSelectionModel<Folder> folderTreeSelectionModel;
-    protected FolderTreeViewModel folderTreeViewModel;
-    protected FolderTreeView folderTreeView;
+    SingleSelectionModel<Folder> folderTreeSelectionModel;
+    FolderTreeViewModel folderTreeViewModel;
+    FolderTreeView folderTreeView;
 
-    protected SingleSelectionModel<Folder> mysharedTreeSelectionModel;
+    SingleSelectionModel<Folder> mysharedTreeSelectionModel;
     private MysharedTreeViewModel mysharedTreeViewModel;
-    private MysharedTreeView mysharedTreeView;
+    MysharedTreeView mysharedTreeView;
 
     protected SingleSelectionModel<Folder> otherSharedTreeSelectionModel;
     private OtherSharedTreeViewModel otherSharedTreeViewModel;
-    private OtherSharedTreeView otherSharedTreeView;
+    OtherSharedTreeView otherSharedTreeView;
 
     protected SingleSelectionModel<Tag> tagTreeSelectionModel;
     private TagTreeViewModel tagTreeViewModel;
@@ -259,12 +259,23 @@ public class Pithos implements EntryPoint, ResizeHandler {
     private GroupTreeViewModel groupTreeViewModel;
     private GroupTreeView groupTreeView;
 
+    private TreeView selectedTree;
     protected AccountResource account;
     
     private Folder trash;
 
     @SuppressWarnings("rawtypes")
        private List<SingleSelectionModel> selectionModels = new ArrayList<SingleSelectionModel>();
+    
+    Button upload;
+    
+    private HTML totalFiles;
+    
+    private HTML usedBytes;
+    
+    private HTML totalBytes;
+    
+    private HTML usedPercent;
 
        @Override
        public void onModuleLoad() {
@@ -294,15 +305,6 @@ public class Pithos implements EntryPoint, ResizeHandler {
         rightside.addStyleName("pithos-rightSide");
         rightside.setSpacing(5);
 
-        PushButton parentButton = new PushButton(new Image(images.asc()), new ClickHandler() {
-            @Override
-            public void onClick(@SuppressWarnings("unused") ClickEvent event) {
-
-            }
-        });
-        parentButton.addStyleName("pithos-parentButton");
-        rightside.add(parentButton);
-
         HTML folderStatistics = new HTML("5 Files (size: 1.1GB)");
         folderStatistics.addStyleName("pithos-folderStatistics");
         rightside.add(folderStatistics);
@@ -316,7 +318,8 @@ public class Pithos implements EntryPoint, ResizeHandler {
             @Override
             public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
                 if (folderTreeSelectionModel.getSelectedObject() != null) {
-                    deselectOthers(folderTreeSelectionModel);
+                    deselectOthers(folderTreeView, folderTreeSelectionModel);
+                    applyPermissions(folderTreeSelectionModel.getSelectedObject());
                     Folder f = folderTreeSelectionModel.getSelectedObject();
                     updateFolder(f, true, null);
                 }
@@ -335,7 +338,8 @@ public class Pithos implements EntryPoint, ResizeHandler {
             @Override
             public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
                 if (mysharedTreeSelectionModel.getSelectedObject() != null) {
-                    deselectOthers(mysharedTreeSelectionModel);
+                    deselectOthers(mysharedTreeView, mysharedTreeSelectionModel);
+                    upload.setEnabled(false);
                     updateSharedFolder(mysharedTreeSelectionModel.getSelectedObject(), true);
                 }
             }
@@ -349,7 +353,8 @@ public class Pithos implements EntryPoint, ResizeHandler {
             @Override
             public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
                 if (otherSharedTreeSelectionModel.getSelectedObject() != null) {
-                    deselectOthers(otherSharedTreeSelectionModel);
+                    deselectOthers(otherSharedTreeView, otherSharedTreeSelectionModel);
+                    applyPermissions(otherSharedTreeSelectionModel.getSelectedObject());
                     updateOtherSharedFolder(otherSharedTreeSelectionModel.getSelectedObject(), true);
                 }
             }
@@ -358,30 +363,15 @@ public class Pithos implements EntryPoint, ResizeHandler {
         otherSharedTreeViewModel = new OtherSharedTreeViewModel(this, otherSharedTreeSelectionModel);
         otherSharedTreeView = new OtherSharedTreeView(otherSharedTreeViewModel);
 
-        tagTreeSelectionModel = new SingleSelectionModel<Tag>();
-        tagTreeSelectionModel.addSelectionChangeHandler(new Handler() {
-            @Override
-            public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
-                if (tagTreeSelectionModel.getSelectedObject() != null) {
-                    deselectOthers(tagTreeSelectionModel);
-                    Tag t = tagTreeSelectionModel.getSelectedObject();
-                    updateTag(t);
-                }
-            }
-        });
-        selectionModels.add(tagTreeSelectionModel);
-        tagTreeViewModel = new TagTreeViewModel(this, tagTreeSelectionModel);
-        tagTreeView = new TagTreeView(tagTreeViewModel);
-
         groupTreeViewModel = new GroupTreeViewModel(this);
         groupTreeView = new GroupTreeView(groupTreeViewModel);
 
         VerticalPanel trees = new VerticalPanel();
 
-        Button upload = new Button("Upload File", new ClickHandler() {
+        upload = new Button("Upload File", new ClickHandler() {
             @Override
             public void onClick(@SuppressWarnings("unused") ClickEvent event) {
-                new UploadFileCommand(Pithos.this, null, folderTreeView.getSelection()).execute();
+                new UploadFileCommand(Pithos.this, null, getSelection()).execute();
             }
         });
         upload.addStyleName("pithos-uploadButton");
@@ -389,7 +379,21 @@ public class Pithos implements EntryPoint, ResizeHandler {
         
         HorizontalPanel treeHeader = new HorizontalPanel();
         treeHeader.addStyleName("pithos-treeHeader");
-        treeHeader.add(new HTML("Total Files: 6 | Used: 2.1 of 50 GB (4.2%)"));
+        HorizontalPanel statistics = new HorizontalPanel();
+        statistics.add(new HTML("Total Files:&nbsp;"));
+        totalFiles = new HTML();
+        statistics.add(totalFiles);
+        statistics.add(new HTML("&nbsp;|&nbsp;Used:&nbsp;"));
+        usedBytes = new HTML();
+        statistics.add(usedBytes);
+        statistics.add(new HTML("&nbsp;of&nbsp;"));
+        totalBytes = new HTML();
+        statistics.add(totalBytes);
+        statistics.add(new HTML("&nbsp;("));
+        usedPercent = new HTML();
+        statistics.add(usedPercent);
+        statistics.add(new HTML("%)"));
+        treeHeader.add(statistics);
         trees.add(treeHeader);
 
         trees.add(folderTreeView);
@@ -436,8 +440,26 @@ public class Pithos implements EntryPoint, ResizeHandler {
         });
     }
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-       public void deselectOthers(SingleSelectionModel model) {
+    public void applyPermissions(Folder f) {
+       if (f != null) {
+               if (f.isInTrash())
+                       upload.setEnabled(false);
+               else {
+                       Boolean[] perms = f.getPermissions().get(username);
+                       if (f.getOwner().equals(username) || (perms != null && perms[1] != null && perms[1])) {
+                               upload.setEnabled(true);
+                       }
+                       else
+                               upload.setEnabled(false);
+               }
+       }
+       else
+               upload.setEnabled(false);
+       }
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
+       public void deselectOthers(TreeView _selectedTree, SingleSelectionModel model) {
+       selectedTree = _selectedTree;
         for (SingleSelectionModel s : selectionModels)
             if (!s.equals(model))
                 s.setSelected(s.getSelectedObject(), false);
@@ -512,7 +534,7 @@ public class Pithos implements EntryPoint, ResizeHandler {
         */
        protected void authenticateUser() {
                Configuration conf = (Configuration) GWT.create(Configuration.class);
-        Window.Location.assign(Window.Location.getHost() + conf.loginUrl() + "?next=" + Window.Location.getHref());
+        Window.Location.assign(conf.loginUrl() + "?next=" + Window.Location.getHref());
        }
 
        protected void fetchAccount() {
@@ -534,6 +556,7 @@ public class Pithos implements EntryPoint, ResizeHandler {
                                }
                     folderTreeViewModel.initialize(account);
                     groupTreeViewModel.initialize();
+                    updateStatistics();
                 }
             }
 
@@ -550,7 +573,14 @@ public class Pithos implements EntryPoint, ResizeHandler {
         Scheduler.get().scheduleDeferred(getAccount);
     }
 
-    protected void createHomeContainer(final AccountResource account) {
+    protected void updateStatistics() {
+       totalFiles.setHTML(String.valueOf(account.getNumberOfObjects()));
+       usedBytes.setHTML(String.valueOf(account.getFileSizeAsString()));
+       totalBytes.setHTML(String.valueOf(account.getQuotaAsString()));
+       usedPercent.setHTML(String.valueOf(account.getUsedPercentage()));
+       }
+
+       protected void createHomeContainer(final AccountResource account) {
         String path = "/" + Pithos.HOME_CONTAINER;
         PutRequest createPithos = new PutRequest(getApiPath(), getUsername(), path) {
             @Override
@@ -724,7 +754,7 @@ public class Pithos implements EntryPoint, ResizeHandler {
        }
 
     public void deleteFolder(final Folder folder) {
-        String path = getApiPath() + getUsername() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + folder.getPrefix();
+        String path = getApiPath() + folder.getOwner() + "/" + folder.getContainer() + "?format=json&delimiter=/&prefix=" + folder.getPrefix();
         RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, path);
         builder.setHeader("If-Modified-Since", "0");
         builder.setHeader("X-Auth-Token", getToken());
@@ -758,7 +788,7 @@ public class Pithos implements EntryPoint, ResizeHandler {
             if (o != null && !o.containsKey("subdir")) {
                 JSONString name = o.get("name").isString();
                 String path = "/" + folder.getContainer() + "/" + name.stringValue();
-                DeleteRequest delete = new DeleteRequest(getApiPath(), getUsername(), path) {
+                DeleteRequest delete = new DeleteRequest(getApiPath(), folder.getOwner(), path) {
                     @Override
                     public void onSuccess(@SuppressWarnings("unused") Resource result) {
                         deleteObject(folder, i + 1, array);
@@ -837,14 +867,14 @@ public class Pithos implements EntryPoint, ResizeHandler {
         return folderTreeView;
     }
 
-    public void copyFiles(final Iterator<File> iter, final String targetUri, final Command callback) {
+    public void copyFiles(final Iterator<File> iter, final String targetUsername, final String targetUri, final Command callback) {
         if (iter.hasNext()) {
             File file = iter.next();
             String path = targetUri + "/" + file.getName();
-            PutRequest copyFile = new PutRequest(getApiPath(), getUsername(), path) {
+            PutRequest copyFile = new PutRequest(getApiPath(), targetUsername, path) {
                 @Override
                 public void onSuccess(@SuppressWarnings("unused") Resource result) {
-                    copyFiles(iter, targetUri, callback);
+                    copyFiles(iter, targetUsername, targetUri, callback);
                 }
 
                 @Override
@@ -866,27 +896,27 @@ public class Pithos implements EntryPoint, ResizeHandler {
         }
     }
 
-    public void copySubfolders(final Iterator<Folder> iter, final String targetUri, final Command callback) {
+    public void copySubfolders(final Iterator<Folder> iter, final String targetUsername, final String targetUri, final Command callback) {
         if (iter.hasNext()) {
             final Folder f = iter.next();
-            copyFolder(f, targetUri, callback);
+            copyFolder(f, targetUsername, targetUri, callback);
         }
         else  if (callback != null) {
             callback.execute();
         }
     }
 
-    public void copyFolder(final Folder f, final String targetUri, final Command callback) {
+    public void copyFolder(final Folder f, final String targetUsername, final String targetUri, final Command callback) {
         String path = targetUri + "/" + f.getName();
-        PutRequest createFolder = new PutRequest(getApiPath(), getUsername(), path) {
+        PutRequest createFolder = new PutRequest(getApiPath(), targetUsername, path) {
             @Override
             public void onSuccess(@SuppressWarnings("unused") Resource result) {
                 Iterator<File> iter = f.getFiles().iterator();
-                copyFiles(iter, targetUri + "/" + f.getName(), new Command() {
+                copyFiles(iter, targetUsername, targetUri + "/" + f.getName(), new Command() {
                     @Override
                     public void execute() {
                         Iterator<Folder> iterf = f.getSubfolders().iterator();
-                        copySubfolders(iterf, targetUri + "/" + f.getName(), new Command() {
+                        copySubfolders(iterf, targetUsername, targetUri + "/" + f.getName(), new Command() {
                             @Override
                             public void execute() {
                                 callback.execute();
@@ -939,4 +969,12 @@ public class Pithos implements EntryPoint, ResizeHandler {
                account.removeGroup(group);
                updateGroupsNode();
        }
+
+       public TreeView getSelectedTree() {
+               return selectedTree;
+       }
+       
+       public Folder getSelection() {
+               return selectedTree.getSelection();
+       }
 }
diff --git a/web_client/src/gr/grnet/pithos/web/client/TreeView.java b/web_client/src/gr/grnet/pithos/web/client/TreeView.java
new file mode 100644 (file)
index 0000000..0d4bad5
--- /dev/null
@@ -0,0 +1,7 @@
+package gr.grnet.pithos.web.client;
+
+import gr.grnet.pithos.web.client.foldertree.Folder;
+
+public interface TreeView {
+       public Folder getSelection();
+}
index 3e596f6..a62822d 100644 (file)
@@ -112,7 +112,7 @@ public class VersionsList extends Composite {
                        downloadHtml.addClickHandler(new ClickHandler() {
                                @Override
                                public void onClick(ClickEvent event) {
-                                       String fileUrl = app.getApiPath() + app.getUsername() + file.getUri() + "?X-Auth-Token=" + app.getToken() + "&version=" + v.getVersion();
+                                       String fileUrl = app.getApiPath() + file.getOwner() + file.getUri() + "?X-Auth-Token=" + app.getToken() + "&version=" + v.getVersion();
                                        Window.open(fileUrl, "_BLANK", "");
                                }
                        });
index 6bf19a9..fcc0ced 100644 (file)
  */
 package gr.grnet.pithos.web.client.commands;
 
+import java.util.Iterator;
+
 import gr.grnet.pithos.web.client.Pithos;
+import gr.grnet.pithos.web.client.foldertree.File;
+import gr.grnet.pithos.web.client.foldertree.Folder;
+import gr.grnet.pithos.web.client.foldertree.Resource;
+import gr.grnet.pithos.web.client.rest.DeleteRequest;
+import gr.grnet.pithos.web.client.rest.RestException;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.ui.PopupPanel;
 
@@ -46,7 +55,7 @@ import com.google.gwt.user.client.ui.PopupPanel;
 public class EmptyTrashCommand implements Command{
        private PopupPanel containerPanel;
 
-    private Pithos app;
+    Pithos app;
 
        public EmptyTrashCommand(Pithos _app, PopupPanel _containerPanel){
         app = _app;
@@ -57,5 +66,98 @@ public class EmptyTrashCommand implements Command{
        public void execute() {
                if (containerPanel != null)
                        containerPanel.hide();
+               
+               final Folder trash = app.getAccount().getTrash();
+               if (trash != null) {
+                       Iterator<File> iter = trash.getFiles().iterator();
+                       deleteFile(iter, new Command() {
+                               
+                               @Override
+                               public void execute() {
+                                       Iterator<Folder> iter2 = trash.getSubfolders().iterator();
+                                       deleteSubfolder(iter2, new Command() {
+                                               
+                                               @Override
+                                               public void execute() {
+                                                       app.updateTrash(true, null);
+                                               }
+                                       });
+                               }
+                       });
+               }
+       }
+
+       protected void deleteSubfolder(final Iterator<Folder> iter2, final Command callback) {
+               if (iter2.hasNext()) {
+                       final Folder f = iter2.next();
+                       Iterator<File> iter3 = f.getFiles().iterator();
+                       deleteFile(iter3, new Command() {
+                               
+                               @Override
+                               public void execute() {
+                                       Iterator<Folder> iter4 = f.getSubfolders().iterator();
+                                       deleteSubfolder(iter4, new Command() {
+                                               
+                                               @Override
+                                               public void execute() {
+                                                       String path = f.getUri();
+                                                       DeleteRequest deleteF = new DeleteRequest(app.getApiPath(), f.getOwner(), path) {
+                                                               
+                                                               @Override
+                                                               public void onSuccess(Resource result) {
+                                                                       deleteSubfolder(iter2, callback);
+                                                               }
+                                                               
+                                                               @Override
+                                                               public void onError(Throwable t) {
+                                                                       GWT.log("", t);
+                                                                       if (t instanceof RestException) {
+                                                                               app.displayError("Unable to delete file:" + ((RestException) t).getHttpStatusText());
+                                                                       }
+                                                                       else
+                                                                               app.displayError("System error deleting file:" + t.getMessage());
+                                                               }
+                                                       };
+                                                       deleteF.setHeader("X-Auth-Token", app.getToken());
+                                                       Scheduler.get().scheduleDeferred(deleteF);
+                                               }
+                                       });
+                               }
+                       });
+               }
+               else {
+                       if (callback != null)
+                               callback.execute();
+               }
+       }
+
+       void deleteFile(final Iterator<File> iter, final Command callback) {
+               if (iter.hasNext()) {
+                       File f = iter.next();
+                       String path = f.getUri();
+                       DeleteRequest deleteF = new DeleteRequest(app.getApiPath(), f.getOwner(), path) {
+                               
+                               @Override
+                               public void onSuccess(Resource result) {
+                                       deleteFile(iter, callback);
+                               }
+                               
+                               @Override
+                               public void onError(Throwable t) {
+                                       GWT.log("", t);
+                                       if (t instanceof RestException) {
+                                               app.displayError("Unable to delete file:" + ((RestException) t).getHttpStatusText());
+                                       }
+                                       else
+                                               app.displayError("System error deleting file:" + t.getMessage());
+                               }
+                       };
+                       deleteF.setHeader("X-Auth-Token", app.getToken());
+                       Scheduler.get().scheduleDeferred(deleteF);
+               }
+               else {
+                       if (callback != null)
+                               callback.execute();
+               }
        }
 }
index a978b50..caee0e3 100644 (file)
@@ -74,7 +74,7 @@ public class PasteCommand implements Command {
         if (clipboardItem instanceof Folder) {
             final Folder tobeCopied = (Folder) clipboardItem;
             if (operation == Clipboard.COPY) {
-                app.copyFolder(tobeCopied, folder.getUri(), new Command() {
+                app.copyFolder(tobeCopied, folder.getOwner(), folder.getUri(), new Command() {
                     @Override
                     public void execute() {
                         app.getClipboard().clear();
@@ -83,7 +83,7 @@ public class PasteCommand implements Command {
                 });
             }
             else {
-                app.copyFolder(tobeCopied, folder.getUri(), new Command() {
+                app.copyFolder(tobeCopied, folder.getOwner(), folder.getUri(), new Command() {
                     @Override
                     public void execute() {
                         app.getClipboard().clear();
@@ -98,7 +98,7 @@ public class PasteCommand implements Command {
                        List<File> tobeCopied = (List<File>) clipboardItem;
             Iterator<File> iter = tobeCopied.iterator();
             if (operation == Clipboard.COPY) {
-                app.copyFiles(iter, folder.getUri(), new Command() {
+                app.copyFiles(iter, folder.getOwner(), folder.getUri(), new Command() {
                     @Override
                     public void execute() {
                         app.getClipboard().clear();
@@ -122,7 +122,7 @@ public class PasteCommand implements Command {
         if (iter.hasNext()) {
             File file = iter.next();
             String path = folder.getUri() + "/" + file.getName();
-            PutRequest copyFile = new PutRequest(app.getApiPath(), app.getUsername(), path) {
+            PutRequest copyFile = new PutRequest(app.getApiPath(), folder.getOwner(), path) {
                 @Override
                 public void onSuccess(@SuppressWarnings("unused") Resource result) {
                     moveFiles(iter, callback);
index de26365..fd28267 100644 (file)
@@ -204,14 +204,15 @@ public class AccountResource extends Resource {
         return getSize(bytesUsed , (1024D*1024D*1024D)) + " GB";
     }
 
-    public String getQuotaLeftAsString() {
-        if (bytesRemaining < 1024)
-            return String.valueOf(bytesRemaining) + " B";
-        else if (bytesRemaining < 1024 * 1024)
-            return getSize(bytesRemaining, 1024D) + " KB";
-        else if (bytesRemaining < 1024 * 1024 * 1024)
-            return getSize(bytesRemaining,(1024D * 1024D)) + " MB";
-        return getSize(bytesRemaining , (1024D * 1024D * 1024D)) + " GB";
+    public String getQuotaAsString() {
+       long quota = bytesUsed + bytesRemaining;
+        if (quota < 1024)
+            return String.valueOf(quota) + " B";
+        else if (quota < 1024 * 1024)
+            return getSize(quota, 1024D) + " KB";
+        else if (quota < 1024 * 1024 * 1024)
+            return getSize(quota,(1024D * 1024D)) + " MB";
+        return getSize(quota , (1024D * 1024D * 1024D)) + " GB";
     }
 
     public List<Group> getGroups() {
@@ -239,4 +240,16 @@ public class AccountResource extends Resource {
        public void removeGroup(Group group) {
                groups.remove(group);
        }
+
+       public Folder getTrash() {
+               for (Folder c : containers) {
+                       if (c.getName().equals(Pithos.TRASH_CONTAINER))
+                               return c;
+               }
+               return null;
+       }
+
+       public double getUsedPercentage() {
+               return 100.0 * bytesUsed / (bytesUsed + bytesRemaining);
+       }
 }
index 76cba0a..9893285 100644 (file)
@@ -47,8 +47,9 @@ import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.Tree;
 import gr.grnet.pithos.web.client.FolderContextMenu;
+import gr.grnet.pithos.web.client.TreeView;
 
-public class FolderTreeView extends Composite {
+public class FolderTreeView extends Composite implements TreeView {
 
     public void updateChildren(Folder folder) {
         TreeNode root = ((CellTree) getWidget()).getRootTreeNode();
@@ -57,17 +58,17 @@ public class FolderTreeView extends Composite {
 
     private void updateChildren(TreeNode node, Folder folder) {
         for (int i=0; i<node.getChildCount(); i++) {
-            if (node.isChildOpen(i)) {
-                if (folder.equals(node.getChildValue(i))) {
-                    node.setChildOpen(i, false, true);
-                    node.setChildOpen(i, true, true);
-                }
-                else {
+            if (folder.equals(node.getChildValue(i))) {
+                node.setChildOpen(i, false, true);
+                node.setChildOpen(i, true, true);
+            }
+            else {
+                if (node.isChildOpen(i)) {
                     TreeNode n = node.setChildOpen(i, true);
                     updateChildren(n, folder);
                 }
             }
-        }
+       }
     }
 
     static interface BasicResources extends CellTree.Resources {
index 5323180..105b0d6 100644 (file)
@@ -137,7 +137,7 @@ public class FolderTreeViewModel implements TreeViewModel {
             final Folder f = iter.next();
 
             String path = "/" + f.getContainer() + "?format=json&delimiter=/&prefix=" + f.getPrefix();
-            GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), app.getUsername(), path, f) {
+            GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), f.getOwner(), path, f) {
                 @Override
                 public void onSuccess(@SuppressWarnings("unused") Folder _result) {
                     fetchFolder(iter, callback);
@@ -188,7 +188,7 @@ public class FolderTreeViewModel implements TreeViewModel {
             @Override
             public void execute() {
                 String path = "/" + f.getContainer() + "?format=json&delimiter=/&prefix=" + f.getPrefix();
-                GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), app.getUsername(), path, f) {
+                GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), f.getOwner(), path, f) {
                     @Override
                     public void onSuccess(final Folder _result) {
                         if (showfiles)
index 5537cc7..78d864e 100644 (file)
@@ -36,6 +36,7 @@
 package gr.grnet.pithos.web.client.mysharedtree;
 
 import gr.grnet.pithos.web.client.FolderContextMenu;
+import gr.grnet.pithos.web.client.TreeView;
 import gr.grnet.pithos.web.client.foldertree.Folder;
 
 import com.google.gwt.core.client.GWT;
@@ -49,7 +50,7 @@ import com.google.gwt.user.cellview.client.TreeNode;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.Tree;
 
-public class MysharedTreeView extends Composite {
+public class MysharedTreeView extends Composite implements TreeView {
 
     public void updateChildren(Folder folder) {
         TreeNode root = ((CellTree) getWidget()).getRootTreeNode();
index ee736fb..e104fdf 100644 (file)
@@ -72,7 +72,7 @@ public class MysharedTreeViewModel implements TreeViewModel {
 
     protected Pithos app;
 
-    private Cell<Folder> folderCell = new AbstractCell<Folder>(ContextMenuEvent.getType().getName()) {
+    private Cell<Folder> folderCell = new AbstractCell<Folder>() {
 
        @Override
         public void render(@SuppressWarnings("unused") Context context, Folder folder, SafeHtmlBuilder safeHtmlBuilder) {
@@ -116,7 +116,8 @@ public class MysharedTreeViewModel implements TreeViewModel {
                 @Override
                 public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
                     if (selectionModel2.getSelectedObject() != null) {
-                       app.deselectOthers(selectionModel2);
+                       app.deselectOthers(app.getMySharedTreeView(), selectionModel2);
+                       app.applyPermissions(null);
                        fetchSharedFiles();
                     }
                 }
@@ -196,7 +197,7 @@ public class MysharedTreeViewModel implements TreeViewModel {
             final Folder f = iter.next();
 
             String path = "/" + f.getContainer() + "?format=json&delimiter=/&prefix=" + f.getPrefix();
-            GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), app.getUsername(), path, f) {
+            GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), f.getOwner(), path, f) {
                 @Override
                 public void onSuccess(Folder _result) {
                        if (!_result.isShared()) {
@@ -249,7 +250,7 @@ public class MysharedTreeViewModel implements TreeViewModel {
 
     public void fetchFolder(final Folder f, final ListDataProvider<Folder> dataProvider, final boolean showfiles) {
         String path = "/" + f.getContainer() + "?format=json&delimiter=/&prefix=" + f.getPrefix();
-        GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), app.getUsername(), path, f) {
+        GetRequest<Folder> getFolder = new GetRequest<Folder>(Folder.class, app.getApiPath(), f.getOwner(), path, f) {
             @Override
             public void onSuccess(final Folder _result) {
                 if (showfiles)
index 531510e..4da4b28 100644 (file)
@@ -36,6 +36,7 @@
 package gr.grnet.pithos.web.client.othersharedtree;
 
 import gr.grnet.pithos.web.client.FolderContextMenu;
+import gr.grnet.pithos.web.client.TreeView;
 import gr.grnet.pithos.web.client.foldertree.Folder;
 
 import com.google.gwt.core.client.GWT;
@@ -49,7 +50,7 @@ import com.google.gwt.user.cellview.client.TreeNode;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.Tree;
 
-public class OtherSharedTreeView extends Composite {
+public class OtherSharedTreeView extends Composite implements TreeView {
 
     public void updateChildren(Folder folder) {
         TreeNode root = ((CellTree) getWidget()).getRootTreeNode();
index 89eb4c1..5119475 100644 (file)
@@ -118,7 +118,8 @@ public class OtherSharedTreeViewModel implements TreeViewModel {
                 @Override
                 public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
                     if (selectionModel2.getSelectedObject() != null) {
-                       app.deselectOthers(selectionModel2);
+                       app.deselectOthers(app.getOtherSharedTreeView(), selectionModel2);
+                       app.applyPermissions(null);
                        app.showFiles(new HashSet<File>());
                     }
                 }
@@ -149,8 +150,12 @@ public class OtherSharedTreeViewModel implements TreeViewModel {
                        @Override
                        public void onSelectionChange(@SuppressWarnings("unused") SelectionChangeEvent event) {
                            if (selectionModel3.getSelectedObject() != null) {
-                               app.deselectOthers(selectionModel3);
+                               app.deselectOthers(app.getOtherSharedTreeView(), selectionModel3);
+                               app.applyPermissions(null);
                                String username = selectionModel3.getSelectedObject();
+                                       if (userDataProviderMap.get(username) == null) {
+                                               userDataProviderMap.put(username, new ListDataProvider<Folder>());
+                                       }
                                fetchSharedFiles(username, userDataProviderMap.get(username));
                            }
                        }