Merge lp:~facundo/magicicada-server/publicfiles into lp:magicicada-server

Proposed by Facundo Batista
Status: Merged
Approved by: Natalia Bidart
Approved revision: 81
Merged at revision: 80
Proposed branch: lp:~facundo/magicicada-server/publicfiles
Merge into: lp:magicicada-server
Diff against target: 781 lines (+418/-18)
16 files modified
config-manager.txt (+2/-2)
magicicada/filesync/services.py (+1/-0)
magicicada/filesync/utilities/make_abundant_files.py (+1/-0)
magicicada/rpcdb/backend.py (+19/-2)
magicicada/rpcdb/tests/test_backend.py (+124/-4)
magicicada/server/content.py (+22/-0)
magicicada/server/integration/integtests_udf.py (+2/-0)
magicicada/server/integtests/test_sync.py (+0/-1)
magicicada/server/server.py (+78/-0)
magicicada/server/testing/aq_helpers.py (+1/-0)
magicicada/server/testing/testcase.py (+1/-0)
magicicada/server/tests/test_content.py (+39/-7)
magicicada/server/tests/test_fileops.py (+88/-1)
magicicada/server/tests/test_server.py (+33/-0)
magicicada/settings/__init__.py (+1/-0)
test (+6/-1)
To merge this branch: bzr merge lp:~facundo/magicicada-server/publicfiles
Reviewer Review Type Date Requested Status
Natalia Bidart Approve
Review via email: mp+310158@code.launchpad.net

Commit message

Support public files changing and listing through the normal Server.

Description of the change

Support public files changing and listing through the normal Server.

You need Protocol and Client changes for this to work:

    lp:~facundo/magicicada-protocol/publicfiles
    lp:~facundo/magicicada-client/publicfiles

To post a comment you must log in.
81. By Facundo Batista

New sourcedeps and aesthetics issues

Revision history for this message
Facundo Batista (facundo) wrote :

Now the client and protocol new stuff is properly indicated in the sourcedeps, so this is all set for review.

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Looks good. I don't like the tests that use mocker but I understand is following the existing test infrastructure.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config-manager.txt'
--- config-manager.txt 2016-09-01 17:12:32 +0000
+++ config-manager.txt 2016-12-27 22:00:10 +0000
@@ -29,5 +29,5 @@
29./.sourcecode/requests ~ubuntuone-pqm-team/requests/stable;revno=81629./.sourcecode/requests ~ubuntuone-pqm-team/requests/stable;revno=816
30./.sourcecode/requests_oauthlib ~ubuntuone-pqm-team/requests-oauthlib/stable;revno=1630./.sourcecode/requests_oauthlib ~ubuntuone-pqm-team/requests-oauthlib/stable;revno=16
31./.sourcecode/u1sync ~facundo/u1sync/opensourcing;revno=1031./.sourcecode/u1sync ~facundo/u1sync/opensourcing;revno=10
32./.sourcecode/magicicada-client ~chicharreros/magicicada-client/trunk;revno=142932./.sourcecode/magicicada-client ~chicharreros/magicicada-client/trunk;revno=1433
33./.sourcecode/magicicada-protocol ~chicharreros/magicicada-protocol/trunk;revno=16633./.sourcecode/magicicada-protocol ~chicharreros/magicicada-protocol/trunk;revno=169
3434
=== modified file 'magicicada/filesync/services.py'
--- magicicada/filesync/services.py 2016-06-03 00:35:53 +0000
+++ magicicada/filesync/services.py 2016-12-27 22:00:10 +0000
@@ -1090,6 +1090,7 @@
1090 return result1090 return result
1091 return wrapper1091 return wrapper
10921092
1093
1093timing_metric = TimingMetrics()1094timing_metric = TimingMetrics()
10941095
10951096
10961097
=== modified file 'magicicada/filesync/utilities/make_abundant_files.py'
--- magicicada/filesync/utilities/make_abundant_files.py 2016-06-03 20:57:04 +0000
+++ magicicada/filesync/utilities/make_abundant_files.py 2016-12-27 22:00:10 +0000
@@ -133,6 +133,7 @@
133 if sys.stdout.isatty():133 if sys.stdout.isatty():
134 sys.stdout.write(home + curses.tigetstr('el'))134 sys.stdout.write(home + curses.tigetstr('el'))
135135
136
136if __name__ == '__main__':137if __name__ == '__main__':
137 from optparse import OptionParser138 from optparse import OptionParser
138 parser = OptionParser("%prog [options] username")139 parser = OptionParser("%prog [options] username")
139140
=== modified file 'magicicada/rpcdb/backend.py'
--- magicicada/rpcdb/backend.py 2016-05-29 20:37:49 +0000
+++ magicicada/rpcdb/backend.py 2016-12-27 22:00:10 +0000
@@ -1,5 +1,5 @@
1# Copyright 2008-2015 Canonical1# Copyright 2008-2015 Canonical
2# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)2# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
3#3#
4# This program is free software: you can redistribute it and/or modify4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as5# it under the terms of the GNU Affero General Public License as
@@ -100,6 +100,22 @@
100 shares=shares, udfs=udfs)100 shares=shares, udfs=udfs)
101 return result101 return result
102102
103 def list_public_files(self, user_id):
104 """List all the public files for the user."""
105 user = self._get_user(user_id)
106
107 public_files = [self._process_node(n) for n in user.get_public_files()]
108 result = dict(public_files=public_files)
109 return result
110
111 def change_public_access(self, user_id, volume_id, node_id,
112 is_public, session_id=None):
113 """Change the public access for a node."""
114 user = self._get_user(user_id, session_id)
115 node = user.volume(volume_id).node(node_id)
116 node = node.change_public_access(is_public)
117 return dict(public_url=node.public_url)
118
103 def move(self, user_id, volume_id, node_id,119 def move(self, user_id, volume_id, node_id,
104 new_parent_id, new_name, session_id=None):120 new_parent_id, new_name, session_id=None):
105 """Move a node and/or rename it."""121 """Move a node and/or rename it."""
@@ -308,7 +324,8 @@
308 storage_key=storage_key, is_live=is_live,324 storage_key=storage_key, is_live=is_live,
309 size=size, is_file=is_file, volume_id=node.vol_id,325 size=size, is_file=is_file, volume_id=node.vol_id,
310 parent_id=node.parent_id, content_hash=node.content_hash,326 parent_id=node.parent_id, content_hash=node.content_hash,
311 path=node.path, has_content=has_content)327 path=node.path, has_content=has_content,
328 public_url=node.public_url)
312 return d329 return d
313330
314 def get_delta(self, user_id, volume_id, from_generation, limit):331 def get_delta(self, user_id, volume_id, from_generation, limit):
315332
=== modified file 'magicicada/rpcdb/tests/test_backend.py'
--- magicicada/rpcdb/tests/test_backend.py 2016-06-03 20:57:04 +0000
+++ magicicada/rpcdb/tests/test_backend.py 2016-12-27 22:00:10 +0000
@@ -1,5 +1,5 @@
1# Copyright 2008-2015 Canonical1# Copyright 2008-2015 Canonical
2# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)2# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
3#3#
4# This program is free software: you can redistribute it and/or modify4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as5# it under the terms of the GNU Affero General Public License as
@@ -243,6 +243,118 @@
243 self.assertEqual(udf2['path'], 'path2')243 self.assertEqual(udf2['path'], 'path2')
244 self.assertEqual(udf2['generation'], 8)244 self.assertEqual(udf2['generation'], 8)
245245
246 def test_change_public_access(self):
247 """Change the public acces of a node."""
248 mocker = Mocker()
249
250 # node, with a generation attribute
251 node = mocker.mock()
252 expect(node.public_url).result('test public url')
253
254 # user, with the chained calls to the action
255 user = mocker.mock()
256 expect(
257 user.volume('vol_id').node('node_id').change_public_access(True)
258 ).result(node)
259 self.backend._get_user = lambda *a: user
260
261 with mocker:
262 kwargs = dict(user_id='user_id', volume_id='vol_id',
263 node_id='node_id', is_public=True,
264 session_id='session_id')
265 result = self.backend.change_public_access(**kwargs)
266
267 self.assertEqual(result, dict(public_url='test public url'))
268
269 def test_list_public_files(self):
270 """List public files."""
271 mocker = Mocker()
272
273 # node 1
274 node1 = mocker.mock()
275 expect(node1.id).result('node_id1')
276 expect(node1.path).result('path1')
277 expect(node1.name).result('name1')
278 expect(node1.vol_id).result('volume_id1')
279 expect(node1.generation).result('generation1')
280 expect(node1.is_public).result(True)
281 expect(node1.parent_id).result('parent_id1')
282 expect(node1.status).result(STATUS_LIVE)
283 expect(node1.content_hash).result('content_hash1')
284 expect(node1.kind).result(StorageObject.FILE)
285 expect(node1.when_last_modified).result('last_modified1')
286 content1 = mocker.mock()
287 expect(content1.size).result('size1')
288 expect(content1.crc32).result('crc321')
289 expect(content1.deflated_size).result('deflated_size1')
290 expect(content1.storage_key).result('storage_key1')
291 expect(node1.content).result(content1)
292 expect(node1.public_url).result('public url 1')
293
294 # node 2
295 node2 = mocker.mock()
296 expect(node2.id).result('node_id2')
297 expect(node2.path).result('path2')
298 expect(node2.name).result('name2')
299 expect(node2.vol_id).result('volume_id2')
300 expect(node2.generation).result('generation2')
301 expect(node2.is_public).result(True)
302 expect(node2.parent_id).result('parent_id2')
303 expect(node2.status).result(STATUS_DEAD)
304 expect(node2.content_hash).result('content_hash2')
305 expect(node2.kind).result(StorageObject.DIRECTORY)
306 expect(node2.when_last_modified).result('last_modified2')
307 content2 = mocker.mock()
308 expect(content2.size).result('size2')
309 expect(content2.crc32).result('crc322')
310 expect(content2.deflated_size).result('deflated_size2')
311 expect(content2.storage_key).result('storage_key2')
312 expect(node2.content).result(content2)
313 expect(node2.public_url).result('public url 2')
314
315 # user
316 user = mocker.mock()
317 self.backend._get_user = lambda *a: user
318 expect(user.get_public_files()).result([node1, node2])
319
320 with mocker:
321 result = self.backend.list_public_files(user_id='user_id',)
322 node1, node2 = result['public_files']
323
324 self.assertEqual(node1['id'], 'node_id1')
325 self.assertEqual(node1['path'], 'path1')
326 self.assertEqual(node1['name'], 'name1')
327 self.assertEqual(node1['volume_id'], 'volume_id1')
328 self.assertEqual(node1['parent_id'], 'parent_id1')
329 self.assertEqual(node1['is_live'], True)
330 self.assertEqual(node1['generation'], 'generation1')
331 self.assertEqual(node1['is_public'], True)
332 self.assertEqual(node1['content_hash'], 'content_hash1')
333 self.assertEqual(node1['is_file'], True)
334 self.assertEqual(node1['size'], 'size1')
335 self.assertEqual(node1['crc32'], 'crc321')
336 self.assertEqual(node1['deflated_size'], 'deflated_size1')
337 self.assertEqual(node1['storage_key'], 'storage_key1')
338 self.assertEqual(node1['last_modified'], 'last_modified1')
339 self.assertEqual(node1['public_url'], 'public url 1')
340
341 self.assertEqual(node2['id'], 'node_id2')
342 self.assertEqual(node2['path'], 'path2')
343 self.assertEqual(node2['name'], 'name2')
344 self.assertEqual(node2['volume_id'], 'volume_id2')
345 self.assertEqual(node2['parent_id'], 'parent_id2')
346 self.assertEqual(node2['is_live'], False)
347 self.assertEqual(node2['generation'], 'generation2')
348 self.assertEqual(node2['is_public'], True)
349 self.assertEqual(node2['content_hash'], 'content_hash2')
350 self.assertEqual(node2['is_file'], False)
351 self.assertEqual(node2['size'], 'size2')
352 self.assertEqual(node2['crc32'], 'crc322')
353 self.assertEqual(node2['deflated_size'], 'deflated_size2')
354 self.assertEqual(node2['storage_key'], 'storage_key2')
355 self.assertEqual(node2['last_modified'], 'last_modified2')
356 self.assertEqual(node2['public_url'], 'public url 2')
357
246 def test_move(self):358 def test_move(self):
247 """Move."""359 """Move."""
248 mocker = Mocker()360 mocker = Mocker()
@@ -706,6 +818,7 @@
706 expect(content.deflated_size).result('deflated_size')818 expect(content.deflated_size).result('deflated_size')
707 expect(content.storage_key).result('storage_key')819 expect(content.storage_key).result('storage_key')
708 expect(node.content).count(1).result(content)820 expect(node.content).count(1).result(content)
821 expect(node.public_url).result(None)
709822
710 # user823 # user
711 user = mocker.mock()824 user = mocker.mock()
@@ -722,7 +835,8 @@
722 last_modified='last_modified', crc32='crc32',835 last_modified='last_modified', crc32='crc32',
723 generation='generation', content_hash='content_hash',836 generation='generation', content_hash='content_hash',
724 deflated_size='deflated_size', storage_key='storage_key',837 deflated_size='deflated_size', storage_key='storage_key',
725 volume_id='volume_id', path='path', has_content=True)838 volume_id='volume_id', path='path', has_content=True,
839 public_url=None)
726 self.assertEqual(result, should)840 self.assertEqual(result, should)
727841
728 def test_get_node_no_content(self):842 def test_get_node_no_content(self):
@@ -743,6 +857,7 @@
743 expect(node.kind).result(StorageObject.FILE)857 expect(node.kind).result(StorageObject.FILE)
744 expect(node.when_last_modified).result('last_modified')858 expect(node.when_last_modified).result('last_modified')
745 expect(node.content).result(None)859 expect(node.content).result(None)
860 expect(node.public_url).result(None)
746861
747 # user862 # user
748 user = mocker.mock()863 user = mocker.mock()
@@ -758,7 +873,7 @@
758 is_public=False, is_live=True, is_file=True, size=None,873 is_public=False, is_live=True, is_file=True, size=None,
759 last_modified='last_modified', crc32=None,874 last_modified='last_modified', crc32=None,
760 generation='generation', content_hash='content_hash',875 generation='generation', content_hash='content_hash',
761 deflated_size=None, storage_key=None,876 deflated_size=None, storage_key=None, public_url=None,
762 volume_id='volume_id', path="path", has_content=False)877 volume_id='volume_id', path="path", has_content=False)
763 self.assertEqual(result, should)878 self.assertEqual(result, should)
764879
@@ -780,6 +895,7 @@
780 expect(node.kind).result(StorageObject.FILE)895 expect(node.kind).result(StorageObject.FILE)
781 expect(node.when_last_modified).result('last_modified')896 expect(node.when_last_modified).result('last_modified')
782 expect(node.content).count(1).result(None)897 expect(node.content).count(1).result(None)
898 expect(node.public_url).result(None)
783899
784 # user900 # user
785 user = mocker.mock()901 user = mocker.mock()
@@ -798,7 +914,7 @@
798 is_public=False, is_live=True, is_file=True, size=None,914 is_public=False, is_live=True, is_file=True, size=None,
799 last_modified='last_modified', crc32=None,915 last_modified='last_modified', crc32=None,
800 generation='generation', content_hash='content_hash',916 generation='generation', content_hash='content_hash',
801 deflated_size=None, storage_key=None,917 deflated_size=None, storage_key=None, public_url=None,
802 volume_id='volume_id', path='path', has_content=False)918 volume_id='volume_id', path='path', has_content=False)
803 self.assertEqual(result, should)919 self.assertEqual(result, should)
804920
@@ -825,6 +941,7 @@
825 expect(content1.deflated_size).count(2).result('deflated_size1')941 expect(content1.deflated_size).count(2).result('deflated_size1')
826 expect(content1.storage_key).count(2).result('storage_key1')942 expect(content1.storage_key).count(2).result('storage_key1')
827 expect(node1.content).count(2).result(content1)943 expect(node1.content).count(2).result(content1)
944 expect(node1.public_url).count(2).result('public url')
828945
829 # node 2946 # node 2
830 node2 = mocker.mock()947 node2 = mocker.mock()
@@ -845,6 +962,7 @@
845 expect(content2.deflated_size).count(2).result('deflated_size2')962 expect(content2.deflated_size).count(2).result('deflated_size2')
846 expect(content2.storage_key).count(2).result('storage_key2')963 expect(content2.storage_key).count(2).result('storage_key2')
847 expect(node2.content).count(2).result(content2)964 expect(node2.content).count(2).result(content2)
965 expect(node2.public_url).count(2).result(None)
848966
849 # user967 # user
850 user = mocker.mock()968 user = mocker.mock()
@@ -880,6 +998,7 @@
880 self.assertEqual(node1['deflated_size'], 'deflated_size1')998 self.assertEqual(node1['deflated_size'], 'deflated_size1')
881 self.assertEqual(node1['storage_key'], 'storage_key1')999 self.assertEqual(node1['storage_key'], 'storage_key1')
882 self.assertEqual(node1['last_modified'], 'last_modified1')1000 self.assertEqual(node1['last_modified'], 'last_modified1')
1001 self.assertEqual(node1['public_url'], 'public url')
8831002
884 self.assertEqual(node2['id'], 'node_id2')1003 self.assertEqual(node2['id'], 'node_id2')
885 self.assertEqual(node2['path'], 'path2')1004 self.assertEqual(node2['path'], 'path2')
@@ -896,6 +1015,7 @@
896 self.assertEqual(node2['deflated_size'], 'deflated_size2')1015 self.assertEqual(node2['deflated_size'], 'deflated_size2')
897 self.assertEqual(node2['storage_key'], 'storage_key2')1016 self.assertEqual(node2['storage_key'], 'storage_key2')
898 self.assertEqual(node2['last_modified'], 'last_modified2')1017 self.assertEqual(node2['last_modified'], 'last_modified2')
1018 self.assertEqual(node2['public_url'], None)
8991019
900 def test_get_user(self):1020 def test_get_user(self):
901 """Get accessable nodes and their hashes."""1021 """Get accessable nodes and their hashes."""
9021022
=== modified file 'magicicada/server/content.py'
--- magicicada/server/content.py 2016-08-07 22:40:29 +0000
+++ magicicada/server/content.py 2016-12-27 22:00:10 +0000
@@ -95,6 +95,7 @@
95 self.is_live = node['is_live']95 self.is_live = node['is_live']
96 self.generation = node['generation']96 self.generation = node['generation']
97 self.is_public = node['is_public']97 self.is_public = node['is_public']
98 self.public_url = node['public_url']
98 last_modif = node['last_modified']99 last_modif = node['last_modified']
99100
100 # special cases for no content101 # special cases for no content
@@ -774,6 +775,27 @@
774 r['name'], r['mimetype']))775 r['name'], r['mimetype']))
775776
776 @defer.inlineCallbacks777 @defer.inlineCallbacks
778 def list_public_files(self):
779 """List the public files for an user."""
780 r = yield self.rpc_dal.call('list_public_files', user_id=self.id)
781 nodes = [Node(self.manager, n) for n in r['public_files']]
782 defer.returnValue(nodes)
783
784 @defer.inlineCallbacks
785 def change_public_access(self, volume_id, node_id,
786 is_public, session_id=None):
787 """Change public access of a node.
788
789 @param volume_id: the id of the volume of the node.
790 @param node_id: the id of the node.
791 @param is_public: if the node should be public or not.
792 """
793 r = yield self.rpc_dal.call('change_public_access', user_id=self.id,
794 volume_id=volume_id, node_id=node_id,
795 is_public=is_public, session_id=session_id)
796 defer.returnValue(r['public_url'])
797
798 @defer.inlineCallbacks
777 def get_upload_job(self, vol_id, node_id, previous_hash, hash_value, crc32,799 def get_upload_job(self, vol_id, node_id, previous_hash, hash_value, crc32,
778 inflated_size, deflated_size, session_id=None,800 inflated_size, deflated_size, session_id=None,
779 magic_hash=None, upload_id=None):801 magic_hash=None, upload_id=None):
780802
=== modified file 'magicicada/server/integration/integtests_udf.py'
--- magicicada/server/integration/integtests_udf.py 2016-05-29 20:58:45 +0000
+++ magicicada/server/integration/integtests_udf.py 2016-12-27 22:00:10 +0000
@@ -300,6 +300,7 @@
300 assert actual2 == expected_with_conflict, \300 assert actual2 == expected_with_conflict, \
301 'directory merge must be correct for SD2'301 'directory merge must be correct for SD2'
302302
303
303test_merge_directories_with_overlap.skip = """304test_merge_directories_with_overlap.skip = """
304 The noconflict.txt file gets into conflict! Bug: #711389305 The noconflict.txt file gets into conflict! Bug: #711389
305"""306"""
@@ -419,6 +420,7 @@
419 debug(prefix, 'contents for SD2', udf_content)420 debug(prefix, 'contents for SD2', udf_content)
420 assert udf_content == [], msg421 assert udf_content == [], msg
421422
423
422test_remove_udf.skip = """424test_remove_udf.skip = """
423 This test exposes a problem we have now in SD: deleting everything425 This test exposes a problem we have now in SD: deleting everything
424 under the UDF depends on timing of operations between one client426 under the UDF depends on timing of operations between one client
425427
=== modified file 'magicicada/server/integtests/test_sync.py'
--- magicicada/server/integtests/test_sync.py 2016-06-03 21:44:35 +0000
+++ magicicada/server/integtests/test_sync.py 2016-12-27 22:00:10 +0000
@@ -112,7 +112,6 @@
112 self.source_dir = self.mktemp("source/root")112 self.source_dir = self.mktemp("source/root")
113 self.share_source_dir = self.mktemp("source/share")113 self.share_source_dir = self.mktemp("source/share")
114114
115 self.patch(Main, "start_status_listener", self.no_op)
116 self.patch(hash_queue, "HASHQUEUE_DELAY", 0.1)115 self.patch(hash_queue, "HASHQUEUE_DELAY", 0.1)
117 self.main = Main(root_dir, shares_dir, data_dir, partials_dir,116 self.main = Main(root_dir, shares_dir, data_dir, partials_dir,
118 "localhost", self.ssl_port, dns_srv=None, ssl=True,117 "localhost", self.ssl_port, dns_srv=None, ssl=True,
119118
=== modified file 'magicicada/server/server.py'
--- magicicada/server/server.py 2016-08-14 21:51:15 +0000
+++ magicicada/server/server.py 2016-12-27 22:00:10 +0000
@@ -535,6 +535,16 @@
535 request = Unlink(self, message)535 request = Unlink(self, message)
536 request.start()536 request.start()
537537
538 def handle_LIST_PUBLIC_FILES(self, message):
539 """Handle LIST_PUBLIC_FILES message."""
540 request = ListPublicFiles(self, message)
541 request.start()
542
543 def handle_CHANGE_PUBLIC_ACCESS(self, message):
544 """Handle UNLINK message."""
545 request = ChangePublicAccess(self, message)
546 request.start()
547
538 def handle_CREATE_UDF(self, message):548 def handle_CREATE_UDF(self, message):
539 """Handle CREATE_UDF message."""549 """Handle CREATE_UDF message."""
540 request = CreateUDF(self, message)550 request = CreateUDF(self, message)
@@ -1299,6 +1309,74 @@
1299 share_id, node_id, kind, mime, extension)1309 share_id, node_id, kind, mime, extension)
13001310
13011311
1312class ListPublicFiles(SimpleRequestResponse):
1313 """LIST_PUBLIC_FILES Request Response."""
1314
1315 __slots__ = ()
1316
1317 @inlineCallbacks
1318 def _process(self):
1319 """List public files for the client."""
1320 user = self.protocol.user
1321 public_files = yield user.list_public_files()
1322
1323 counter = 0
1324 for node in public_files:
1325 message = protocol_pb2.Message()
1326 message.type = protocol_pb2.Message.PUBLIC_FILE_INFO
1327 message.public_file_info.share = node.volume_id or ''
1328 message.public_file_info.node = str(node.id)
1329 message.public_file_info.is_public = node.is_public
1330 message.public_file_info.public_url = str(node.public_url)
1331 self.sendMessage(message)
1332 counter += 1
1333
1334 # we're done!
1335 self.length = counter
1336 response = protocol_pb2.Message()
1337 response.type = protocol_pb2.Message.PUBLIC_FILE_INFO_END
1338 self.sendMessage(response)
1339
1340 # save data to be logged on operation end
1341 self.operation_data = 'public_files=%d' % len(public_files)
1342
1343
1344class ChangePublicAccess(SimpleRequestResponse):
1345 """CHANGE_PUBLIC_ACCESS Request Response."""
1346
1347 __slots__ = ()
1348
1349 expected_foreign_errors = [dataerror.NoPermission]
1350
1351 user_activity = 'sync_activity'
1352
1353 def _get_node_info(self):
1354 """Return node info from the message."""
1355 node_id = self.source_message.change_public_access.node
1356 return 'node: %r' % (node_id,)
1357
1358 @inlineCallbacks
1359 def _process(self):
1360 """Change the public access to a node."""
1361 share_id = self.convert_share_id(
1362 self.source_message.change_public_access.share)
1363 node_id = self.source_message.change_public_access.node
1364 is_public = self.source_message.change_public_access.is_public
1365 public_url = yield self.protocol.user.change_public_access(
1366 share_id, node_id, is_public, session_id=self.protocol.session_id)
1367
1368 # answer the ok to original user
1369 response = protocol_pb2.Message()
1370 response.public_url = bytes(public_url)
1371 response.type = protocol_pb2.Message.OK
1372 self.sendMessage(response)
1373
1374 # save data to be logged on operation end
1375 self.operation_data = (
1376 'vol_id=%s node_id=%s is_public=%s public_url=%r' % (
1377 share_id, node_id, is_public, public_url))
1378
1379
1302class BytesMessageProducer(object):1380class BytesMessageProducer(object):
1303 """Adapt a bytes producer to produce BYTES messages."""1381 """Adapt a bytes producer to produce BYTES messages."""
13041382
13051383
=== modified file 'magicicada/server/testing/aq_helpers.py'
--- magicicada/server/testing/aq_helpers.py 2016-08-30 00:50:31 +0000
+++ magicicada/server/testing/aq_helpers.py 2016-12-27 22:00:10 +0000
@@ -573,6 +573,7 @@
573 def __cmp__(self, other):573 def __cmp__(self, other):
574 return cmp(self.shares, other.shares)574 return cmp(self.shares, other.shares)
575575
576
576aHash = _HashPlaceholder('a hash')577aHash = _HashPlaceholder('a hash')
577anUUID = _UUIDPlaceholder('an UUID')578anUUID = _UUIDPlaceholder('an UUID')
578aShareUUID = _UUIDPlaceholder('a share UUID', ('',))579aShareUUID = _UUIDPlaceholder('a share UUID', ('',))
579580
=== modified file 'magicicada/server/testing/testcase.py'
--- magicicada/server/testing/testcase.py 2016-08-14 21:51:15 +0000
+++ magicicada/server/testing/testcase.py 2016-12-27 22:00:10 +0000
@@ -55,6 +55,7 @@
55 """In the present we trust."""55 """In the present we trust."""
56 return int(time.time())56 return int(time.time())
5757
58
58# need to patch this timestamp checker so it doesn't go to the real server59# need to patch this timestamp checker so it doesn't go to the real server
59client.tx_timestamp_checker = FakeTimestampChecker()60client.tx_timestamp_checker = FakeTimestampChecker()
6061
6162
=== modified file 'magicicada/server/tests/test_content.py'
--- magicicada/server/tests/test_content.py 2016-09-15 11:46:39 +0000
+++ magicicada/server/tests/test_content.py 2016-12-27 22:00:10 +0000
@@ -1700,13 +1700,13 @@
1700 root = yield client.get_root()1700 root = yield client.get_root()
1701 filename = 'hola_12'1701 filename = 'hola_12'
1702 mkfile_req = yield client.make_file(request.ROOT, root, filename)1702 mkfile_req = yield client.make_file(request.ROOT, root, filename)
1703 upload_id = []1703 upload_info = []
1704 try:1704 try:
1705 yield client.put_content(1705 yield client.put_content(
1706 request.ROOT, mkfile_req.new_id, NO_CONTENT_HASH,1706 request.ROOT, mkfile_req.new_id, NO_CONTENT_HASH,
1707 hash_value, crc32_value, size, deflated_size,1707 hash_value, crc32_value, size, deflated_size,
1708 StringIO(deflated_data),1708 StringIO(deflated_data),
1709 upload_id_cb=upload_id.append)1709 upload_id_cb=lambda *a: upload_info.append(a))
1710 except EOFError:1710 except EOFError:
1711 # check upload stat and log, with the offset sent,1711 # check upload stat and log, with the offset sent,
1712 # first time tarts from beginning.1712 # first time tarts from beginning.
@@ -1745,7 +1745,7 @@
1745 req = sp_client.PutContent(1745 req = sp_client.PutContent(
1746 client, request.ROOT, mkfile_req.new_id, NO_CONTENT_HASH,1746 client, request.ROOT, mkfile_req.new_id, NO_CONTENT_HASH,
1747 hash_value, crc32_value, size, deflated_size,1747 hash_value, crc32_value, size, deflated_size,
1748 StringIO(deflated_data), upload_id=str(upload_id[0]))1748 StringIO(deflated_data), upload_id=str(upload_info[0][0]))
1749 req.start()1749 req.start()
1750 yield req.deferred1750 yield req.deferred
17511751
@@ -1800,19 +1800,21 @@
1800 yield client.dummy_authenticate("open sesame")1800 yield client.dummy_authenticate("open sesame")
1801 root = yield client.get_root()1801 root = yield client.get_root()
1802 mkfile_req = yield client.make_file(request.ROOT, root, 'hola')1802 mkfile_req = yield client.make_file(request.ROOT, root, 'hola')
1803 upload_id = []1803 upload_info = []
1804 req = client.put_content_request(1804 req = client.put_content_request(
1805 request.ROOT, mkfile_req.new_id, NO_CONTENT_HASH,1805 request.ROOT, mkfile_req.new_id, NO_CONTENT_HASH,
1806 hash_value, crc32_value, size, deflated_size,1806 hash_value, crc32_value, size, deflated_size,
1807 StringIO(deflated_data), upload_id="invalid id",1807 StringIO(deflated_data), upload_id="invalid id",
1808 upload_id_cb=upload_id.append)1808 upload_id_cb=lambda *a: upload_info.append(a))
1809 yield req.deferred1809 yield req.deferred
1810 self.assertTrue(('UploadJob.upload', 0) in gauge)1810 self.assertTrue(('UploadJob.upload', 0) in gauge)
1811 self.assertTrue(('UploadJob.upload.begin', 1) in meter)1811 self.assertTrue(('UploadJob.upload.begin', 1) in meter)
1812 self.handler.assert_debug(1812 self.handler.assert_debug(
1813 "UploadJob begin content from offset 0")1813 "UploadJob begin content from offset 0")
1814 self.assertEqual(len(upload_id), 1)1814 self.assertEqual(len(upload_info), 1)
1815 self.assertIsInstance(uuid.UUID(upload_id[0]), uuid.UUID)1815 upload_id, start_from = upload_info[0]
1816 self.assertIsInstance(uuid.UUID(upload_id), uuid.UUID)
1817 self.assertEqual(start_from, 0)
18161818
1817 yield self.callback_test(auth, add_default_callbacks=True)1819 yield self.callback_test(auth, add_default_callbacks=True)
18181820
@@ -2302,6 +2304,36 @@
2302 d = self.user.get_free_bytes(share.id)2304 d = self.user.get_free_bytes(share.id)
2303 yield self.assertFailure(d, errors.DoesNotExist)2305 yield self.assertFailure(d, errors.DoesNotExist)
23042306
2307 @defer.inlineCallbacks
2308 def test_change_public_access(self):
2309 """Test change public access action."""
2310 root_id, root_gen = yield self.user.get_root()
2311 volume_id = yield self.user.get_volume_id(root_id)
2312 node_id, generation, _ = yield self.user.make_file(
2313 volume_id, root_id, u"name")
2314 public_url = yield self.user.change_public_access(
2315 volume_id, node_id, True)
2316 self.assertTrue(public_url.startswith(settings.PUBLIC_URL_PREFIX))
2317
2318 @defer.inlineCallbacks
2319 def test_list_public_files(self):
2320 """Test the public files listing."""
2321 root_id, _ = yield self.user.get_root()
2322 volume_id = yield self.user.get_volume_id(root_id)
2323
2324 # create three files, make two public
2325 node_id_1, _, _ = yield self.user.make_file(
2326 volume_id, root_id, u"name1")
2327 yield self.user.make_file(volume_id, root_id, u"name2")
2328 node_id_3, _, _ = yield self.user.make_file(
2329 volume_id, root_id, u"name3")
2330 yield self.user.change_public_access(volume_id, node_id_1, True)
2331 yield self.user.change_public_access(volume_id, node_id_3, True)
2332
2333 public_files = yield self.user.list_public_files()
2334 self.assertEqual(set(node.id for node in public_files),
2335 {node_id_1, node_id_3})
2336
23052337
2306class TestUploadJob(TestWithDatabase):2338class TestUploadJob(TestWithDatabase):
2307 """Tests for UploadJob class."""2339 """Tests for UploadJob class."""
23082340
=== modified file 'magicicada/server/tests/test_fileops.py'
--- magicicada/server/tests/test_fileops.py 2016-05-29 20:58:45 +0000
+++ magicicada/server/tests/test_fileops.py 2016-12-27 22:00:10 +0000
@@ -1,5 +1,5 @@
1# Copyright 2008-2015 Canonical1# Copyright 2008-2015 Canonical
2# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)2# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
3#3#
4# This program is free software: you can redistribute it and/or modify4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as5# it under the terms of the GNU Affero General Public License as
@@ -421,3 +421,90 @@
421 self.assertEqual(unlink_req.new_generation,421 self.assertEqual(unlink_req.new_generation,
422 make_req.new_generation + 1)422 make_req.new_generation + 1)
423 return self.callback_test(test, add_default_callbacks=True)423 return self.callback_test(test, add_default_callbacks=True)
424
425
426class TestPublicFiles(TestWithDatabase):
427 """Test the public files management."""
428
429 def test_set_public_file_true(self):
430 @defer.inlineCallbacks
431 def auth(client):
432 yield client.dummy_authenticate("open sesame")
433 root = yield client.get_root()
434 req = yield client.make_file(request.ROOT, root, "hola")
435 resp = yield client.change_public_access(
436 request.ROOT, req.new_id, True)
437 fileobj = self.usr0.get_node(req.new_id)
438 self.assertTrue(fileobj.is_public)
439 self.assertEqual(resp.public_url, fileobj.public_url)
440
441 return self.callback_test(auth, add_default_callbacks=True)
442
443 def test_set_public_file_false(self):
444 @defer.inlineCallbacks
445 def auth(client):
446 yield client.dummy_authenticate("open sesame")
447 root = yield client.get_root()
448 req = yield client.make_file(request.ROOT, root, "hola")
449
450 # set it to public first
451 yield client.change_public_access(request.ROOT, req.new_id, True)
452 fileobj = self.usr0.get_node(req.new_id)
453 assert fileobj.is_public
454
455 # set it to false, check
456 yield client.change_public_access(request.ROOT, req.new_id, False)
457 fileobj = self.usr0.get_node(req.new_id)
458 self.assertFalse(fileobj.is_public)
459
460 return self.callback_test(auth, add_default_callbacks=True)
461
462 def test_list_public_files_none(self):
463 @defer.inlineCallbacks
464 def auth(client):
465 yield client.dummy_authenticate("open sesame")
466
467 # list and check
468 resp = yield client.list_public_files()
469 self.assertEqual(resp.public_files, [])
470
471 return self.callback_test(auth, add_default_callbacks=True)
472
473 def test_list_public_files_several(self):
474 @defer.inlineCallbacks
475 def auth(client):
476 yield client.dummy_authenticate("open sesame")
477 root = yield client.get_root()
478
479 # create three files, and set two of them to be public
480 req1 = yield client.make_file(request.ROOT, root, "file1")
481 yield client.make_file(request.ROOT, root, "file2")
482 req3 = yield client.make_file(request.ROOT, root, "file3")
483 yield client.change_public_access(request.ROOT, req1.new_id, True)
484 yield client.change_public_access(request.ROOT, req3.new_id, True)
485
486 # list and check
487 resp = yield client.list_public_files()
488 self.assertEqual({node.node_id for node in resp.public_files},
489 set([req1.new_id, req3.new_id]))
490
491 return self.callback_test(auth, add_default_callbacks=True)
492
493 def test_list_public_files_unpublished(self):
494 @defer.inlineCallbacks
495 def auth(client):
496 yield client.dummy_authenticate("open sesame")
497 root = yield client.get_root()
498
499 # create a file, publish, and assert
500 req = yield client.make_file(request.ROOT, root, "file")
501 yield client.change_public_access(request.ROOT, req.new_id, True)
502 resp = yield client.list_public_files()
503 assert [node.node_id for node in resp.public_files] == [req.new_id]
504
505 # unpublish it and check
506 yield client.change_public_access(request.ROOT, req.new_id, False)
507 resp = yield client.list_public_files()
508 self.assertEqual(resp.public_files, [])
509
510 return self.callback_test(auth, add_default_callbacks=True)
424511
=== modified file 'magicicada/server/tests/test_server.py'
--- magicicada/server/tests/test_server.py 2016-08-26 21:53:42 +0000
+++ magicicada/server/tests/test_server.py 2016-12-27 22:00:10 +0000
@@ -48,6 +48,7 @@
48 Action,48 Action,
49 AuthenticateResponse,49 AuthenticateResponse,
50 BytesMessageProducer,50 BytesMessageProducer,
51 ChangePublicAccess,
51 CreateShare,52 CreateShare,
52 CreateUDF,53 CreateUDF,
53 DeleteShare,54 DeleteShare,
@@ -56,6 +57,7 @@
56 GetContentResponse,57 GetContentResponse,
57 GetDeltaResponse,58 GetDeltaResponse,
58 ListShares,59 ListShares,
60 ListPublicFiles,
59 ListVolumes,61 ListVolumes,
60 LoopingPing,62 LoopingPing,
61 MakeResponse,63 MakeResponse,
@@ -99,6 +101,8 @@
99 last_modified = 2334524101 last_modified = 2334524
100 is_public = False102 is_public = False
101 path = u"path"103 path = u"path"
104 volume_id = 'volumeid'
105 public_url = 'public_url'
102106
103107
104class FakeUser(object):108class FakeUser(object):
@@ -1177,6 +1181,35 @@
1177 self.assertEqual(self.response.length, 6)1181 self.assertEqual(self.response.length, 6)
11781182
11791183
1184class ChangePublicAccessTestCase(SimpleRequestResponseTestCase):
1185 """Test the ChangePublicAccess class."""
1186
1187 response_class = ChangePublicAccess
1188
1189
1190class ListPublicFilesTestCase(SimpleRequestResponseTestCase):
1191 """Test the ListPublicFiles class."""
1192
1193 response_class = ListPublicFiles
1194
1195 @defer.inlineCallbacks
1196 def test_process_set_values(self):
1197 """Set length attribute and operation data while processing."""
1198 mocker = Mocker()
1199
1200 user = mocker.mock()
1201 self.response.protocol.user = user
1202
1203 nodes = [FakeNode(), FakeNode()]
1204 expect(user.list_public_files()).result(nodes)
1205
1206 with mocker:
1207 yield self.response._process()
1208
1209 self.assertEqual(self.response.length, 2)
1210 self.assertEqual(self.response.operation_data, "public_files=2")
1211
1212
1180class UnlinkTestCase(SimpleRequestResponseTestCase):1213class UnlinkTestCase(SimpleRequestResponseTestCase):
1181 """Test the Unlink class."""1214 """Test the Unlink class."""
11821215
11831216
=== modified file 'magicicada/settings/__init__.py'
--- magicicada/settings/__init__.py 2016-09-15 11:46:39 +0000
+++ magicicada/settings/__init__.py 2016-12-27 22:00:10 +0000
@@ -147,6 +147,7 @@
147 if self.isEnabledFor(TRACE):147 if self.isEnabledFor(TRACE):
148 self._log(TRACE, msg, args, **kwargs)148 self._log(TRACE, msg, args, **kwargs)
149149
150
150logging.setLoggerClass(MagicicadaLogger)151logging.setLoggerClass(MagicicadaLogger)
151152
152153
153154
=== modified file 'test'
--- test 2016-09-15 11:46:39 +0000
+++ test 2016-12-27 22:00:10 +0000
@@ -1,7 +1,7 @@
1#!/usr/bin/env python1#!/usr/bin/env python
22
3# Copyright 2008-2015 Canonical3# Copyright 2008-2015 Canonical
4# Copyright 2015 Chicharreros (https://launchpad.net/~chicharreros)4# Copyright 2015-2016 Chicharreros (https://launchpad.net/~chicharreros)
5#5#
6# This program is free software: you can redistribute it and/or modify6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU Affero General Public License as7# it under the terms of the GNU Affero General Public License as
@@ -44,6 +44,11 @@
44 os.environ.setdefault(44 os.environ.setdefault(
45 'XDG_CACHE_HOME', os.path.join(ROOTDIR, 'tmp', 'xdg_cache'))45 'XDG_CACHE_HOME', os.path.join(ROOTDIR, 'tmp', 'xdg_cache'))
4646
47 # repeated setting from makefile, as some tests check this, to work
48 # ok when running them directly from ./test
49 os.environ.setdefault('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION', 'cpp')
50 os.environ.setdefault('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION', '2')
51
47 dbus_address_file = os.path.join(ROOTDIR, 'tmp', 'dbus.address')52 dbus_address_file = os.path.join(ROOTDIR, 'tmp', 'dbus.address')
48 if os.path.exists(dbus_address_file):53 if os.path.exists(dbus_address_file):
49 with open(dbus_address_file) as fh:54 with open(dbus_address_file) as fh:

Subscribers

People subscribed via source and target branches

to all changes: