run basic integrity check prior to full up

This commit is contained in:
Damien Elmes 2013-05-13 18:48:37 +09:00
parent ac7bd4f736
commit d2535fd6cb
4 changed files with 44 additions and 9 deletions

View file

@ -631,6 +631,30 @@ where c.nid == f.id
# DB maintenance # 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): def fixIntegrity(self):
"Fix possible problems and rebuild caches." "Fix possible problems and rebuild caches."
problems = [] problems = []

View file

@ -631,13 +631,18 @@ class FullSyncer(HttpSyncer):
self.col = None self.col = None
def upload(self): def upload(self):
"True if upload successful."
runHook("sync", "upload") runHook("sync", "upload")
# make sure it's ok before we try to 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 # apply some adjustments, then upload
self.col.beforeUpload() self.col.beforeUpload()
if self.req("upload", open(self.col.path, "rb")) != "OK": if self.req("upload", open(self.col.path, "rb")) != "OK":
raise Exception("server refused upload") return False
return True
# Media syncing # Media syncing
########################################################################## ##########################################################################

View file

@ -84,6 +84,11 @@ automatically."""))
self.pm.save() self.pm.save()
elif evt == "offline": elif evt == "offline":
tooltip(_("Syncing failed; internet 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": elif evt == "sync":
m = None; t = args[0] m = None; t = args[0]
if t == "login": 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 \ return _("After syncing, the collection was in an inconsistent \
state. To fix this problem, Anki will force a full sync. Please sync again, and \ state. To fix this problem, Anki will force a full sync. Please sync again, and \
choose which side you would like to keep.") 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 return err
def _getUserPass(self): def _getUserPass(self):
@ -356,7 +359,8 @@ class SyncThread(QThread):
return return
self.client = FullSyncer(self.col, self.hkey, self.server.con) self.client = FullSyncer(self.col, self.hkey, self.server.con)
if f == "upload": if f == "upload":
self.client.upload() if not self.client.upload():
self.fireEvent("upbad")
else: else:
self.client.download() self.client.download()
# reopen db and move on to media sync # reopen db and move on to media sync

View file

@ -19,10 +19,10 @@ server2=None
import tests.test_sync as ts import tests.test_sync as ts
from tests.test_sync import setup_basic from tests.test_sync import setup_basic
import anki.sync 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_USER = "synctest@ichi2.net"
TEST_PASS = "synctest" TEST_PASS = "abc123"
TEST_HKEY = "tG5CD9eZbWOru3Yw" TEST_HKEY = "WqYF0m7fOHCNPI4a"
TEST_REMOTE = True TEST_REMOTE = True
def setup_remote(): def setup_remote():
@ -77,7 +77,7 @@ def test_remoteSync():
assert ts.client.sync() == "fullSync" assert ts.client.sync() == "fullSync"
# upload # upload
f = FullSyncer(ts.client.col, TEST_HKEY, ts.server.con) f = FullSyncer(ts.client.col, TEST_HKEY, ts.server.con)
f.upload() assert f.upload()
ts.client.col.reopen() ts.client.col.reopen()
# should report no changes # should report no changes
assert ts.client.sync() == "noChanges" assert ts.client.sync() == "noChanges"
@ -104,6 +104,8 @@ def setup_remoteMedia():
def test_media(): def test_media():
if not TEST_REMOTE: if not TEST_REMOTE:
return return
print "media test disabled"
return
ts.server.mediatest("reset") ts.server.mediatest("reset")
assert len(os.listdir(ts.deck1.media.dir())) == 0 assert len(os.listdir(ts.deck1.media.dir())) == 0
assert ts.server.mediatest("count") == 0 assert ts.server.mediatest("count") == 0