Browse Source

More work on label cloud plugin

master
Maran 13 years ago
parent
commit
9df4451c6f
  1. 5
      gui/gui_classic.py
  2. 141
      plugins/labels.py

5
gui/gui_classic.py

@ -374,7 +374,8 @@ class ElectrumWindow(QMainWindow):
if old_text: if old_text:
self.wallet.labels.pop(name) self.wallet.labels.pop(name)
changed = True changed = True
run_hook('set_label', name, text, changed)
self.run_hook('set_label', (name, text, changed,))
return changed return changed
@ -2110,7 +2111,7 @@ class ElectrumWindow(QMainWindow):
self.config.set_key('currency', cur_request, True) self.config.set_key('currency', cur_request, True)
self.update_wallet() self.update_wallet()
self.run_hook('close_setting_dialog', (self,)) self.run_hook('close_settings_dialog', (self,))
if need_restart: if need_restart:
QMessageBox.warning(self, _('Success'), _('Please restart Electrum to activate the new GUI settings'), _('OK')) QMessageBox.warning(self, _('Success'), _('Please restart Electrum to activate the new GUI settings'), _('OK'))

141
plugins/labels.py

@ -1,4 +1,5 @@
from electrum.util import print_error from electrum.util import print_error
from electrum_gui.i18n import _
import httplib, urllib import httplib, urllib
import hashlib import hashlib
import json import json
@ -14,83 +15,136 @@ import PyQt4.QtCore as QtCore
import PyQt4.QtGui as QtGui import PyQt4.QtGui as QtGui
target_host = 'labelectrum.herokuapp.com' target_host = 'labelectrum.herokuapp.com'
config = {}
def is_available():
return True
def auth_token():
global config
return config.get("plugin_label_api_key")
def init(gui): def init(gui):
"""If you want to give this a spin create a account at the target_host url and put it in your user dir config """If you want to give this a spin create a account at the target_host url and put it in your user dir config
file with the label_api_key.""" file with the label_api_key."""
global auth_token global config
auth_token = gui.config.get("label_api_key") config = gui.config
if not auth_token:
return if config.get('plugin_label_enabled'):
gui.set_hook('create_settings_tab', add_settings_tab)
gui.set_hook('close_settings_dialog', close_settings_dialog)
if not auth_token():
return
cloud_wallet = CloudWallet(gui.wallet) cloud_wallet = CloudWallet(gui.wallet)
gui.set_hook('create_settings_tab', add_settings_tab) gui.set_hook('set_label', set_label)
gui.set_hook('label_changed', label_changed)
cloud_wallet.full_pull()
def wallet_id(wallet): cloud_wallet.full_pull()
return hashlib.sha256(str(wallet.get_master_public_key())).digest().encode('hex')
def wallet_id():
global config
return hashlib.sha256(str(config.get("master_public_key"))).digest().encode('hex')
def set_label(item,label, changed):
if not changed:
return
def label_changed(gui,item,label):
print "Label changed! Item: %s Label: %s label" % ( item, label) print "Label changed! Item: %s Label: %s label" % ( item, label)
global auth_token, target_host global target_host
hashed = hashlib.sha256(item).digest().encode('hex') hashed = hashlib.sha256(item).digest().encode('hex')
bundle = {"label": {"external_id": hashed, "text": label}} bundle = {"label": {"external_id": hashed, "text": label}}
params = json.dumps(bundle) params = json.dumps(bundle)
connection = httplib.HTTPConnection(target_host) connection = httplib.HTTPConnection(target_host)
wallet = wallet_id(gui.wallet) connection.request("POST", ("/api/wallets/%s/labels.json?auth_token=%s" % (wallet_id(), auth_token())), params, {'Content-Type': 'application/json'})
connection.request("POST", ("/api/wallets/%s/labels.json?auth_token=%s" % (wallet, auth_token)), params, {'Content-Type': 'application/json'})
response = connection.getresponse() response = connection.getresponse()
if response.reason == httplib.responses[httplib.NOT_FOUND]: if response.reason == httplib.responses[httplib.NOT_FOUND]:
return return
response = json.loads(response.read()) response = json.loads(response.read())
def close_settings_dialog(gui):
global config
# When you enable the plugin for the first time this won't exist.
if is_enabled():
if hasattr(gui, 'auth_token_edit'):
config.set_key("plugin_label_api_key", str(gui.auth_token_edit.text()))
else:
QMessageBox.information(None, _("Cloud plugin loaded"), _("Please open the settings again to configure the label-cloud plugin."))
def add_settings_tab(gui, tabs): def add_settings_tab(gui, tabs):
cloud_tab = QWidget() def check_for_api_key(api_key):
layout = QGridLayout(cloud_tab) global config
layout.addWidget(QLabel("API Key: "),0,0) if api_key and len(api_key) > 12:
layout.addWidget(QLineEdit(auth_token), 0,2) config.set_key("plugin_label_api_key", str(gui.auth_token_edit.text()))
upload.setEnabled(True)
download.setEnabled(True)
else:
upload.setEnabled(False)
download.setEnabled(False)
cloud_tab = QWidget()
layout = QGridLayout(cloud_tab)
layout.addWidget(QLabel("API Key: "),0,0)
layout.addWidget(QLabel("Label sync options: "),1,0) # TODO: I need to add it to the Electrum GUI here so I can retrieve it later when the settings dialog is closed, is there a better way to do this?
gui.auth_token_edit = QLineEdit(auth_token())
gui.auth_token_edit.textChanged.connect(check_for_api_key)
upload = QPushButton("Force upload") layout.addWidget(gui.auth_token_edit, 0,1,1,2)
upload.clicked.connect(lambda: full_push(gui.wallet)) layout.addWidget(QLabel("Label cloud options: "),1,0)
layout.addWidget(upload, 1,1)
download = QPushButton("Force download") upload = QPushButton("Force upload")
download.clicked.connect(lambda: full_pull(gui.wallet)) upload.clicked.connect(lambda: full_push(gui.wallet))
layout.addWidget(download, 1,2) layout.addWidget(upload, 1,1)
tabs.addTab(cloud_tab, "Label cloud") download = QPushButton("Force download")
download.clicked.connect(lambda: full_pull(gui.wallet))
layout.addWidget(download, 1,2)
gui.cloud_tab = cloud_tab
check_for_api_key(auth_token())
tabs.addTab(cloud_tab, "Label cloud")
def full_push(wallet): def full_push(wallet):
cloud_wallet = CloudWallet(wallet) cloud_wallet = CloudWallet(wallet)
cloud_wallet.full_push() cloud_wallet.full_push()
print "Labels pushed" QMessageBox.information(None, _("Labels synced"), _("Your labels have been uploaded."))
def full_pull(wallet): def full_pull(wallet):
cloud_wallet = CloudWallet(wallet) cloud_wallet = CloudWallet(wallet)
cloud_wallet.full_pull(True) cloud_wallet.full_pull(True)
print "Labels pulled, please restart your client" QMessageBox.information(None, _("Labels synced"), _("Your labels have been synced, please restart Electrum for the changes to take effect."))
def show(): def show():
print 'showing' print 'showing'
def get_info(): def get_info():
return 'Label sync', "Syncs your labels with LabElectrum. Labels are not encrypted, transactions and addresses are however. This code might increase the load of your wallet with a few micoseconds as it will sync labels on each startup." return 'Label sync', "Syncs your labels with 'the cloud'. Labels are not encrypted, transactions and addresses are however. This code might increase the load of your wallet with a few micoseconds as it will sync labels on each startup."
def is_enabled(): def is_enabled():
return True return config.get('plugin_label_enabled') is True
def toggle(gui): def toggle(gui):
return is_enabled() if not is_enabled():
enabled = True
else:
enabled = False
gui.unset_hook('create_settings_tab', add_settings_tab)
gui.unset_hook('close_settings_dialog', close_settings_dialog)
config.set_key('plugin_label_enabled', enabled, True)
if enabled:
init(gui)
return enabled
# This can probably be refactored into plain top level methods instead of a class # This can probably be refactored into plain top level methods instead of a class
class CloudWallet(): class CloudWallet():
def __init__(self, wallet): def __init__(self, wallet):
self.mpk = hashlib.sha256(str(wallet.get_master_public_key())).digest().encode('hex')
self.labels = wallet.labels self.labels = wallet.labels
self.transactions = wallet.transactions self.transactions = wallet.transactions
@ -101,11 +155,10 @@ class CloudWallet():
self.addresses = addresses self.addresses = addresses
def full_pull(self, force = False): def full_pull(self, force = False):
global target_host, auth_token global target_host
connection = httplib.HTTPConnection(target_host) connection = httplib.HTTPConnection(target_host)
connection.request("GET", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.mpk, auth_token)),"", {'Content-Type': 'application/json'}) connection.request("GET", ("/api/wallets/%s/labels.json?auth_token=%s" % (wallet_id(), auth_token())),"", {'Content-Type': 'application/json'})
response = connection.getresponse() response = connection.getresponse()
if response.reason == httplib.responses[httplib.NOT_FOUND]: if response.reason == httplib.responses[httplib.NOT_FOUND]:
return return
@ -114,6 +167,10 @@ class CloudWallet():
except ValueError as e: except ValueError as e:
return return
if "error" in response:
QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"]))
return
for label in response: for label in response:
for key in self.addresses: for key in self.addresses:
target_hashed = hashlib.sha256(key).digest().encode('hex') target_hashed = hashlib.sha256(key).digest().encode('hex')
@ -127,7 +184,7 @@ class CloudWallet():
self.labels[key] = label["text"] self.labels[key] = label["text"]
def full_push(self): def full_push(self):
global target_host, auth_token global target_host
bundle = {"labels": {}} bundle = {"labels": {}}
for key, value in self.labels.iteritems(): for key, value in self.labels.iteritems():
@ -136,10 +193,16 @@ class CloudWallet():
params = json.dumps(bundle) params = json.dumps(bundle)
connection = httplib.HTTPConnection(target_host) connection = httplib.HTTPConnection(target_host)
connection.request("POST", ("/api/wallets/%s/labels/batch.json?auth_token=%s" % (self.mpk, auth_token)), params, {'Content-Type': 'application/json'}) connection.request("POST", ("/api/wallets/%s/labels/batch.json?auth_token=%s" % (wallet_id(), auth_token())), params, {'Content-Type': 'application/json'})
response = connection.getresponse() response = connection.getresponse()
if response.reason == httplib.responses[httplib.NOT_FOUND]: if response.reason == httplib.responses[httplib.NOT_FOUND]:
return return
response = json.loads(response.read()) try:
print response response = json.loads(response.read())
except ValueError as e:
return
if "error" in response:
QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"]))
return

Loading…
Cancel
Save