summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/leap/soledad/client/_db/blobs/__init__.py12
-rw-r--r--src/leap/soledad/client/_db/blobs/sql.py1
-rw-r--r--src/leap/soledad/client/_db/blobs/sync.py4
-rw-r--r--tests/blobs/test_blob_manager.py13
4 files changed, 27 insertions, 3 deletions
diff --git a/src/leap/soledad/client/_db/blobs/__init__.py b/src/leap/soledad/client/_db/blobs/__init__.py
index a5b7d6e3..3c7492c6 100644
--- a/src/leap/soledad/client/_db/blobs/__init__.py
+++ b/src/leap/soledad/client/_db/blobs/__init__.py
@@ -207,7 +207,7 @@ class BlobManager(BlobsSynchronizer):
def local_list_status(self, status, namespace=''):
return self.local.list_status(status, namespace)
- def put(self, doc, size, namespace=''):
+ def put(self, doc, size, namespace='', local_only=False):
"""
Put a blob in local storage and upload it to server.
@@ -215,14 +215,16 @@ class BlobManager(BlobsSynchronizer):
:type doc: leap.soledad.client._document.BlobDoc
:param size: The size of the blob.
:type size: int
+ :param local_only: Avoids sync (doesn't send to server).
+ :type local_only: bool
:param namespace:
Optional parameter to restrict operation to a given namespace.
:type namespace: str
"""
- return self.semaphore.run(self._put, doc, size, namespace)
+ return self.semaphore.run(self._put, doc, size, namespace, local_only)
@defer.inlineCallbacks
- def _put(self, doc, size, namespace):
+ def _put(self, doc, size, namespace, local_only=False):
if (yield self.local.exists(doc.blob_id, namespace=namespace)):
error_message = "Blob already exists: %s" % doc.blob_id
raise BlobAlreadyExistsError(error_message)
@@ -230,6 +232,10 @@ class BlobManager(BlobsSynchronizer):
# TODO this is a tee really, but ok... could do db and upload
# concurrently. not sure if we'd gain something.
yield self.local.put(doc.blob_id, fd, size=size, namespace=namespace)
+ if local_only:
+ yield self.local.update_sync_status(
+ doc.blob_id, SyncStatus.LOCAL_ONLY)
+ defer.returnValue(None)
yield self.local.update_sync_status(
doc.blob_id, SyncStatus.PENDING_UPLOAD)
# In fact, some kind of pipe is needed here, where each write on db
diff --git a/src/leap/soledad/client/_db/blobs/sql.py b/src/leap/soledad/client/_db/blobs/sql.py
index 5337ab87..ebd6c095 100644
--- a/src/leap/soledad/client/_db/blobs/sql.py
+++ b/src/leap/soledad/client/_db/blobs/sql.py
@@ -42,6 +42,7 @@ class SyncStatus:
FAILED_UPLOAD = 4
FAILED_DOWNLOAD = 5
PENDING_DELETE = 6
+ LOCAL_ONLY = 7
UNAVAILABLE_STATUSES = (3, 5)
diff --git a/src/leap/soledad/client/_db/blobs/sync.py b/src/leap/soledad/client/_db/blobs/sync.py
index bdfbb983..3ee60305 100644
--- a/src/leap/soledad/client/_db/blobs/sync.py
+++ b/src/leap/soledad/client/_db/blobs/sync.py
@@ -77,6 +77,10 @@ class BlobsSynchronizer(object):
remote_deletions = self.remote_list(namespace=namespace, deleted=True)
remote_deletions = yield remote_deletions
yield self.local.batch_delete(remote_deletions)
+ yield self.local.update_batch_sync_status(
+ remote_deletions,
+ SyncStatus.SYNCED,
+ namespace=namespace)
@defer.inlineCallbacks
def send_missing(self, namespace=''):
diff --git a/tests/blobs/test_blob_manager.py b/tests/blobs/test_blob_manager.py
index 58f99790..c7bbb0d3 100644
--- a/tests/blobs/test_blob_manager.py
+++ b/tests/blobs/test_blob_manager.py
@@ -83,6 +83,19 @@ class BlobManagerTestCase(unittest.TestCase):
@defer.inlineCallbacks
@pytest.mark.usefixtures("method_tmpdir")
+ def test_put_local_only_doesnt_send_to_server(self):
+ self.manager._encrypt_and_upload = Mock(return_value=None)
+ msg, blob_id = "Hey Joe", uuid4().hex
+ doc = BlobDoc(BytesIO(msg), blob_id=blob_id)
+ yield self.manager.put(doc, size=len(msg), local_only=True)
+ result = yield self.manager.local.get(blob_id)
+ status, _ = yield self.manager.local.get_sync_status(blob_id)
+ self.assertEquals(result.getvalue(), msg)
+ self.assertEquals(status, SyncStatus.LOCAL_ONLY)
+ self.assertFalse(self.manager._encrypt_and_upload.called)
+
+ @defer.inlineCallbacks
+ @pytest.mark.usefixtures("method_tmpdir")
def test_put_then_get_using_real_file_descriptor(self):
self.manager._encrypt_and_upload = Mock(return_value=None)
self.manager._download_and_decrypt = Mock(return_value=None)