From d2535fd6cbfe8e03f62a052d86235de2a8af6513 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 13 May 2013 18:48:37 +0900 Subject: [PATCH] run basic integrity check prior to full up --- anki/collection.py | 24 ++++++++++++++++++++++++ anki/sync.py | 9 +++++++-- aqt/sync.py | 10 +++++++--- tests/test_remote_sync.py | 10 ++++++---- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/anki/collection.py b/anki/collection.py index 0da7b6a24..09a69046c 100644 --- a/anki/collection.py +++ b/anki/collection.py @@ -631,6 +631,30 @@ where c.nid == f.id # DB maintenance ########################################################################## + def basicCheck(self): + "Basic integrity check for syncing. True if ok." + # cards without notes + if self.db.scalar(""" +select 1 from cards where nid not in (select id from notes) limit 1"""): + return + # notes without cards or models + if self.db.scalar(""" +select 1 from notes where id not in (select distinct nid from cards) +or mid not in %s limit 1""" % ids2str(self.models.ids())): + return + # invalid ords + for m in self.models.all(): + # ignore clozes + if m['type'] != MODEL_STD: + continue + if self.db.scalar(""" +select 1 from cards where ord not in %s and nid in ( +select id from notes where mid = ?) limit 1""" % + ids2str([t['ord'] for t in m['tmpls']]), + m['id']): + return + return True + def fixIntegrity(self): "Fix possible problems and rebuild caches." problems = [] diff --git a/anki/sync.py b/anki/sync.py index 2df4c662e..53c937f01 100644 --- a/anki/sync.py +++ b/anki/sync.py @@ -631,13 +631,18 @@ class FullSyncer(HttpSyncer): self.col = None def upload(self): + "True if upload successful." runHook("sync", "upload") # make sure it's ok before we try to upload - assert self.col.db.scalar("pragma integrity_check") == "ok" + if self.col.db.scalar("pragma integrity_check") != "ok": + return False + if not self.col.basicCheck(): + return False # apply some adjustments, then upload self.col.beforeUpload() if self.req("upload", open(self.col.path, "rb")) != "OK": - raise Exception("server refused upload") + return False + return True # Media syncing ########################################################################## diff --git a/aqt/sync.py b/aqt/sync.py index 8fc35003c..fdd500288 100644 --- a/aqt/sync.py +++ b/aqt/sync.py @@ -84,6 +84,11 @@ automatically.""")) self.pm.save() elif evt == "offline": tooltip(_("Syncing failed; internet offline.")) + elif evt == "upbad": + self._didFullUp = False + showWarning(_("""\ +The upload was aborted because errors were found in your collection. \ +Please check your collection with Tools>Maintenance>Check Database.""")) elif evt == "sync": m = None; t = args[0] if t == "login": @@ -157,8 +162,6 @@ AnkiWeb is too busy at the moment. Please try again in a few minutes.""") return _("After syncing, the collection was in an inconsistent \ state. To fix this problem, Anki will force a full sync. Please sync again, and \ choose which side you would like to keep.") - elif "server refused upload" in err: - return _("The server said our uploaded file was corrupt. Please try again.") return err def _getUserPass(self): @@ -356,7 +359,8 @@ class SyncThread(QThread): return self.client = FullSyncer(self.col, self.hkey, self.server.con) if f == "upload": - self.client.upload() + if not self.client.upload(): + self.fireEvent("upbad") else: self.client.download() # reopen db and move on to media sync diff --git a/tests/test_remote_sync.py b/tests/test_remote_sync.py index ef51bf037..c4d90caed 100644 --- a/tests/test_remote_sync.py +++ b/tests/test_remote_sync.py @@ -19,10 +19,10 @@ server2=None import tests.test_sync as ts from tests.test_sync import setup_basic import anki.sync -anki.sync.SYNC_URL = "http://localhost:6543/sync/" +anki.sync.SYNC_URL = "http://localhost:5000/sync/" TEST_USER = "synctest@ichi2.net" -TEST_PASS = "synctest" -TEST_HKEY = "tG5CD9eZbWOru3Yw" +TEST_PASS = "abc123" +TEST_HKEY = "WqYF0m7fOHCNPI4a" TEST_REMOTE = True def setup_remote(): @@ -77,7 +77,7 @@ def test_remoteSync(): assert ts.client.sync() == "fullSync" # upload f = FullSyncer(ts.client.col, TEST_HKEY, ts.server.con) - f.upload() + assert f.upload() ts.client.col.reopen() # should report no changes assert ts.client.sync() == "noChanges" @@ -104,6 +104,8 @@ def setup_remoteMedia(): def test_media(): if not TEST_REMOTE: return + print "media test disabled" + return ts.server.mediatest("reset") assert len(os.listdir(ts.deck1.media.dir())) == 0 assert ts.server.mediatest("count") == 0