Add --import-qr to run the QR->CSV step before importing
Wrap the QR decode/append step behind --import-qr on the importer so a single command runs the whole pipeline: decode QR images, append only new credentials to the CSV (deduped on otpauth://, existing entries silently skipped), then validate and import. QR folder defaults to the CSV's folder; override with --qr-images. Refactor qr_to_sheet into reusable collect_candidates / apply_new_candidates / run_qr_import.
This commit is contained in:
31
test_qr.py
31
test_qr.py
@@ -4,7 +4,8 @@ import tempfile
|
||||
import unittest
|
||||
|
||||
from otpauth import parse_otpauth, canonical_key
|
||||
from qr_to_sheet import existing_keys, dedup_new, append_csv, read_csv_rows
|
||||
from qr_to_sheet import (existing_keys, dedup_new, append_csv, read_csv_rows,
|
||||
apply_new_candidates)
|
||||
|
||||
|
||||
class TestParseOtpauth(unittest.TestCase):
|
||||
@@ -83,5 +84,33 @@ class TestCsvIO(unittest.TestCase):
|
||||
self.assertEqual(read_csv_rows(os.path.join(tempfile.mkdtemp(), "nope.csv")), [])
|
||||
|
||||
|
||||
class TestApplyNewCandidates(unittest.TestCase):
|
||||
def _csv_with_A(self):
|
||||
p = os.path.join(tempfile.mkdtemp(), "otp-keys.csv")
|
||||
append_csv(p, [{"issuer": "X", "account": "a", "otpauth_uri": A, "source_file": "a.png"}])
|
||||
return p
|
||||
|
||||
def test_only_new_otpauth_is_appended(self):
|
||||
p = self._csv_with_A()
|
||||
summary = apply_new_candidates([(A, "a2.png"), (B, "b.png"), (B, "b2.png")], p)
|
||||
self.assertEqual(summary["added"], 1)
|
||||
self.assertEqual(summary["duplicates"], 2)
|
||||
rows = read_csv_rows(p)
|
||||
self.assertEqual(len(rows), 2) # existing A + new B only
|
||||
self.assertEqual(rows[1]["otpauth_uri"], B)
|
||||
|
||||
def test_all_existing_appends_nothing(self):
|
||||
p = self._csv_with_A()
|
||||
summary = apply_new_candidates([(A, "a2.png")], p)
|
||||
self.assertEqual((summary["added"], summary["duplicates"]), (0, 1))
|
||||
self.assertEqual(len(read_csv_rows(p)), 1) # unchanged
|
||||
|
||||
def test_dry_run_reports_but_does_not_write(self):
|
||||
p = self._csv_with_A()
|
||||
summary = apply_new_candidates([(B, "b.png")], p, dry_run=True)
|
||||
self.assertEqual(summary["added"], 1)
|
||||
self.assertEqual(len(read_csv_rows(p)), 1) # not written
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user