import/exports to json files:
- fix #5737 - add import/export or requests
This commit is contained in:
@@ -27,7 +27,7 @@ from dns.exception import DNSException
|
|||||||
|
|
||||||
from . import bitcoin
|
from . import bitcoin
|
||||||
from . import dnssec
|
from . import dnssec
|
||||||
from .util import export_meta, import_meta, to_string
|
from .util import read_json_file, write_json_file, to_string
|
||||||
from .logging import Logger
|
from .logging import Logger
|
||||||
|
|
||||||
|
|
||||||
@@ -52,14 +52,13 @@ class Contacts(dict, Logger):
|
|||||||
self.db.put('contacts', dict(self))
|
self.db.put('contacts', dict(self))
|
||||||
|
|
||||||
def import_file(self, path):
|
def import_file(self, path):
|
||||||
import_meta(path, self._validate, self.load_meta)
|
data = read_json_file(path)
|
||||||
|
data = self._validate(data)
|
||||||
def load_meta(self, data):
|
|
||||||
self.update(data)
|
self.update(data)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def export_file(self, filename):
|
def export_file(self, path):
|
||||||
export_meta(self, filename)
|
write_json_file(path, self)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
dict.__setitem__(self, key, value)
|
dict.__setitem__(self, key, value)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from electrum.bitcoin import is_address
|
|||||||
from electrum.util import block_explorer_URL
|
from electrum.util import block_explorer_URL
|
||||||
from electrum.plugin import run_hook
|
from electrum.plugin import run_hook
|
||||||
|
|
||||||
from .util import MyTreeView, import_meta_gui, export_meta_gui, webopen
|
from .util import MyTreeView, webopen
|
||||||
|
|
||||||
|
|
||||||
class ContactList(MyTreeView):
|
class ContactList(MyTreeView):
|
||||||
@@ -63,12 +63,6 @@ class ContactList(MyTreeView):
|
|||||||
self.parent.set_contact(text, user_role)
|
self.parent.set_contact(text, user_role)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def import_contacts(self):
|
|
||||||
import_meta_gui(self.parent, _('contacts'), self.parent.contacts.import_file, self.update)
|
|
||||||
|
|
||||||
def export_contacts(self):
|
|
||||||
export_meta_gui(self.parent, _('contacts'), self.parent.contacts.export_file)
|
|
||||||
|
|
||||||
def create_menu(self, position):
|
def create_menu(self, position):
|
||||||
menu = QMenu()
|
menu = QMenu()
|
||||||
idx = self.indexAt(position)
|
idx = self.indexAt(position)
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ from electrum.util import format_time
|
|||||||
from electrum.invoices import Invoice, PR_UNPAID, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_TYPE_ONCHAIN, PR_TYPE_LN
|
from electrum.invoices import Invoice, PR_UNPAID, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_TYPE_ONCHAIN, PR_TYPE_LN
|
||||||
from electrum.lnutil import PaymentAttemptLog
|
from electrum.lnutil import PaymentAttemptLog
|
||||||
|
|
||||||
from .util import (MyTreeView, read_QIcon, MySortModel,
|
from .util import MyTreeView, read_QIcon, MySortModel, pr_icons
|
||||||
import_meta_gui, export_meta_gui, pr_icons)
|
|
||||||
from .util import CloseButton, Buttons
|
from .util import CloseButton, Buttons
|
||||||
from .util import WindowModalDialog
|
from .util import WindowModalDialog
|
||||||
|
|
||||||
@@ -136,12 +135,6 @@ class InvoiceList(MyTreeView):
|
|||||||
self.setVisible(b)
|
self.setVisible(b)
|
||||||
self.parent.invoices_label.setVisible(b)
|
self.parent.invoices_label.setVisible(b)
|
||||||
|
|
||||||
def import_invoices(self):
|
|
||||||
import_meta_gui(self.parent, _('invoices'), self.parent.invoices.import_file, self.update)
|
|
||||||
|
|
||||||
def export_invoices(self):
|
|
||||||
export_meta_gui(self.parent, _('invoices'), self.parent.invoices.export_file)
|
|
||||||
|
|
||||||
def create_menu(self, position):
|
def create_menu(self, position):
|
||||||
wallet = self.parent.wallet
|
wallet = self.parent.wallet
|
||||||
items = self.selected_in_column(0)
|
items = self.selected_in_column(0)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ from electrum.i18n import _
|
|||||||
from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
|
from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
|
||||||
format_satoshis_plain,
|
format_satoshis_plain,
|
||||||
UserCancelled, profiler,
|
UserCancelled, profiler,
|
||||||
export_meta, import_meta, bh2u, bfh, InvalidPassword,
|
bh2u, bfh, InvalidPassword,
|
||||||
UserFacingException,
|
UserFacingException,
|
||||||
get_new_wallet_name, send_exception_to_crash_reporter,
|
get_new_wallet_name, send_exception_to_crash_reporter,
|
||||||
InvalidBitcoinURI, maybe_extract_bolt11_invoice, NotEnoughFunds,
|
InvalidBitcoinURI, maybe_extract_bolt11_invoice, NotEnoughFunds,
|
||||||
@@ -670,11 +670,14 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||||||
history_menu.addAction(_("&Export"), self.history_list.export_history_dialog)
|
history_menu.addAction(_("&Export"), self.history_list.export_history_dialog)
|
||||||
contacts_menu = wallet_menu.addMenu(_("Contacts"))
|
contacts_menu = wallet_menu.addMenu(_("Contacts"))
|
||||||
contacts_menu.addAction(_("&New"), self.new_contact_dialog)
|
contacts_menu.addAction(_("&New"), self.new_contact_dialog)
|
||||||
contacts_menu.addAction(_("Import"), lambda: self.contact_list.import_contacts())
|
contacts_menu.addAction(_("Import"), lambda: self.import_contacts())
|
||||||
contacts_menu.addAction(_("Export"), lambda: self.contact_list.export_contacts())
|
contacts_menu.addAction(_("Export"), lambda: self.export_contacts())
|
||||||
invoices_menu = wallet_menu.addMenu(_("Invoices"))
|
invoices_menu = wallet_menu.addMenu(_("Invoices"))
|
||||||
invoices_menu.addAction(_("Import"), lambda: self.invoice_list.import_invoices())
|
invoices_menu.addAction(_("Import"), lambda: self.import_invoices())
|
||||||
invoices_menu.addAction(_("Export"), lambda: self.invoice_list.export_invoices())
|
invoices_menu.addAction(_("Export"), lambda: self.export_invoices())
|
||||||
|
requests_menu = wallet_menu.addMenu(_("Requests"))
|
||||||
|
requests_menu.addAction(_("Import"), lambda: self.import_requests())
|
||||||
|
requests_menu.addAction(_("Export"), lambda: self.export_requests())
|
||||||
|
|
||||||
wallet_menu.addSeparator()
|
wallet_menu.addSeparator()
|
||||||
wallet_menu.addAction(_("Find"), self.toggle_search).setShortcut(QKeySequence("Ctrl+F"))
|
wallet_menu.addAction(_("Find"), self.toggle_search).setShortcut(QKeySequence("Ctrl+F"))
|
||||||
@@ -2754,23 +2757,31 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||||||
f.write(json.dumps(pklist, indent = 4))
|
f.write(json.dumps(pklist, indent = 4))
|
||||||
|
|
||||||
def do_import_labels(self):
|
def do_import_labels(self):
|
||||||
def import_labels(path):
|
|
||||||
def _validate(data):
|
|
||||||
return data # TODO
|
|
||||||
|
|
||||||
def import_labels_assign(data):
|
|
||||||
for key, value in data.items():
|
|
||||||
self.wallet.set_label(key, value)
|
|
||||||
import_meta(path, _validate, import_labels_assign)
|
|
||||||
|
|
||||||
def on_import():
|
def on_import():
|
||||||
self.need_update.set()
|
self.need_update.set()
|
||||||
import_meta_gui(self, _('labels'), import_labels, on_import)
|
import_meta_gui(self, _('labels'), self.wallet.import_labels, on_import)
|
||||||
|
|
||||||
def do_export_labels(self):
|
def do_export_labels(self):
|
||||||
def export_labels(filename):
|
export_meta_gui(self, _('labels'), self.wallet.export_labels)
|
||||||
export_meta(self.wallet.labels, filename)
|
|
||||||
export_meta_gui(self, _('labels'), export_labels)
|
def import_invoices(self):
|
||||||
|
import_meta_gui(self, _('invoices'), self.wallet.import_invoices, self.invoice_list.update)
|
||||||
|
|
||||||
|
def export_invoices(self):
|
||||||
|
export_meta_gui(self, _('invoices'), self.wallet.export_invoices)
|
||||||
|
|
||||||
|
def import_requests(self):
|
||||||
|
import_meta_gui(self, _('requests'), self.wallet.import_requests, self.request_list.update)
|
||||||
|
|
||||||
|
def export_requests(self):
|
||||||
|
export_meta_gui(self, _('requests'), self.wallet.export_requests)
|
||||||
|
|
||||||
|
def import_contacts(self):
|
||||||
|
import_meta_gui(self, _('contacts'), self.contacts.import_file, self.contact_list.update)
|
||||||
|
|
||||||
|
def export_contacts(self):
|
||||||
|
export_meta_gui(self, _('contacts'), self.contacts.export_file)
|
||||||
|
|
||||||
|
|
||||||
def sweep_key_dialog(self):
|
def sweep_key_dialog(self):
|
||||||
d = WindowModalDialog(self, title=_('Sweep private keys'))
|
d = WindowModalDialog(self, title=_('Sweep private keys'))
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ except ImportError:
|
|||||||
sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=electrum/ --python_out=electrum/ electrum/paymentrequest.proto'")
|
sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=electrum/ --python_out=electrum/ electrum/paymentrequest.proto'")
|
||||||
|
|
||||||
from . import bitcoin, ecc, util, transaction, x509, rsakey
|
from . import bitcoin, ecc, util, transaction, x509, rsakey
|
||||||
from .util import bh2u, bfh, export_meta, import_meta, make_aiohttp_session
|
from .util import bh2u, bfh, make_aiohttp_session
|
||||||
from .invoices import PR_UNPAID, PR_EXPIRED, PR_PAID, PR_UNKNOWN, PR_INFLIGHT
|
from .invoices import PR_UNPAID, PR_EXPIRED, PR_PAID, PR_UNKNOWN, PR_INFLIGHT
|
||||||
from .crypto import sha256
|
from .crypto import sha256
|
||||||
from .bitcoin import address_to_script
|
from .bitcoin import address_to_script
|
||||||
|
|||||||
@@ -952,11 +952,10 @@ def versiontuple(v):
|
|||||||
return tuple(map(int, (v.split("."))))
|
return tuple(map(int, (v.split("."))))
|
||||||
|
|
||||||
|
|
||||||
def import_meta(path, validater, load_meta):
|
def read_json_file(path):
|
||||||
try:
|
try:
|
||||||
with open(path, 'r', encoding='utf-8') as f:
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
d = validater(json.loads(f.read()))
|
data = json.loads(f.read())
|
||||||
load_meta(d)
|
|
||||||
#backwards compatibility for JSONDecodeError
|
#backwards compatibility for JSONDecodeError
|
||||||
except ValueError:
|
except ValueError:
|
||||||
_logger.exception('')
|
_logger.exception('')
|
||||||
@@ -964,12 +963,12 @@ def import_meta(path, validater, load_meta):
|
|||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
_logger.exception('')
|
_logger.exception('')
|
||||||
raise FileImportFailed(e)
|
raise FileImportFailed(e)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def write_json_file(path, data):
|
||||||
def export_meta(meta, fileName):
|
|
||||||
try:
|
try:
|
||||||
with open(fileName, 'w+', encoding='utf-8') as f:
|
with open(path, 'w+', encoding='utf-8') as f:
|
||||||
json.dump(meta, f, indent=4, sort_keys=True)
|
json.dump(data, f, indent=4, sort_keys=True, cls=MyEncoder)
|
||||||
except (IOError, os.error) as e:
|
except (IOError, os.error) as e:
|
||||||
_logger.exception('')
|
_logger.exception('')
|
||||||
raise FileExportFailed(e)
|
raise FileExportFailed(e)
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ from .mnemonic import Mnemonic
|
|||||||
from .logging import get_logger
|
from .logging import get_logger
|
||||||
from .lnworker import LNWallet, LNBackups
|
from .lnworker import LNWallet, LNBackups
|
||||||
from .paymentrequest import PaymentRequest
|
from .paymentrequest import PaymentRequest
|
||||||
|
from .util import read_json_file, write_json_file
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .network import Network
|
from .network import Network
|
||||||
@@ -421,6 +422,14 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
|||||||
run_hook('set_label', self, name, text)
|
run_hook('set_label', self, name, text)
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
def import_labels(self, path):
|
||||||
|
data = read_json_file(path)
|
||||||
|
for key, value in data.items():
|
||||||
|
self.set_label(key, value)
|
||||||
|
|
||||||
|
def export_labels(self, path):
|
||||||
|
write_json_file(path, self.labels)
|
||||||
|
|
||||||
def set_fiat_value(self, txid, ccy, text, fx, value_sat):
|
def set_fiat_value(self, txid, ccy, text, fx, value_sat):
|
||||||
if not self.db.get_transaction(txid):
|
if not self.db.get_transaction(txid):
|
||||||
return
|
return
|
||||||
@@ -707,6 +716,24 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
|||||||
def get_invoice(self, key):
|
def get_invoice(self, key):
|
||||||
return self.invoices.get(key)
|
return self.invoices.get(key)
|
||||||
|
|
||||||
|
def import_requests(self, path):
|
||||||
|
data = read_json_file(path)
|
||||||
|
for x in data:
|
||||||
|
req = invoice_from_json(x)
|
||||||
|
self.add_payment_request(req)
|
||||||
|
|
||||||
|
def export_requests(self, path):
|
||||||
|
write_json_file(path, list(self.receive_requests.values()))
|
||||||
|
|
||||||
|
def import_invoices(self, path):
|
||||||
|
data = read_json_file(path)
|
||||||
|
for x in data:
|
||||||
|
invoice = invoice_from_json(x)
|
||||||
|
self.save_invoice(invoice)
|
||||||
|
|
||||||
|
def export_invoices(self, path):
|
||||||
|
write_json_file(path, list(self.invoices.values()))
|
||||||
|
|
||||||
def _get_relevant_invoice_keys_for_tx(self, tx: Transaction) -> Set[str]:
|
def _get_relevant_invoice_keys_for_tx(self, tx: Transaction) -> Set[str]:
|
||||||
relevant_invoice_keys = set()
|
relevant_invoice_keys = set()
|
||||||
for txout in tx.outputs():
|
for txout in tx.outputs():
|
||||||
|
|||||||
Reference in New Issue
Block a user