tshow payment request details - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 440f972fd3eab0cac7f486e1de8e028a34df3fb9 DIR parent 0838b350584fbc3f3f09e65be3bc79534a709ae2 HTML Author: ThomasV <thomasv@gitorious> Date: Sat, 7 Jun 2014 19:53:54 +0200 show payment request details Diffstat: M gui/qt/__init__.py | 6 +----- M gui/qt/main_window.py | 28 +++++++++++++++++++++++----- M gui/qt/util.py | 16 +++++++++------- M lib/paymentrequest.py | 80 ++++++++++++++++++++----------- 4 files changed, 84 insertions(+), 46 deletions(-) --- DIR diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py t@@ -169,11 +169,7 @@ class ElectrumGui: QMessageBox.warning(self.main_window, _('Error'), _('Invalid Amount'), _('OK')) if request_url: - try: - from electrum import paymentrequest - except: - print "cannot import paymentrequest" - request_url = None + from electrum import paymentrequest if not request_url: self.main_window.set_send(address, amount, label, message) DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py t@@ -933,7 +933,8 @@ class ElectrumWindow(QMainWindow): self.update_invoices_tab() self.payto_help.show() - self.payto_help.set_alt(pr.status) + self.payto_help.set_alt(lambda: self.show_pr_details(pr)) + self.payto_e.setGreen() self.payto_e.setText(pr.domain) self.amount_e.setText(self.format_amount(pr.get_amount())) t@@ -973,7 +974,6 @@ class ElectrumWindow(QMainWindow): h.show() self.payto_help.set_alt(None) - self.set_pay_from([]) self.update_status() t@@ -1211,18 +1211,36 @@ class ElectrumWindow(QMainWindow): menu.exec_(self.contacts_list.viewport().mapToGlobal(position)) def delete_invoice(self, item): - k = self.invoices_list.indexOfTopLevelItem(item) - key = self.invoices.keys()[k] self.invoices.pop(key) self.wallet.storage.put('invoices', self.invoices) self.update_invoices_tab() + def show_invoice(self, key): + from electrum.paymentrequest import PaymentRequest + domain, value = self.invoices[key] + pr = PaymentRequest(self.config) + pr.read_file(key) + pr.domain = domain + pr.verify() + self.show_pr_details(pr) + + def show_pr_details(self, pr): + msg = 'Domain: ' + pr.domain + msg += '\nStatus: ' + pr.get_status() + msg += '\nMemo: ' + pr.memo + msg += '\nPayment URL: ' + pr.payment_url + msg += '\n\nOutputs:\n' + '\n'.join(map(lambda x: x[0] + ' ' + self.format_amount(x[1])+ self.base_unit(), pr.get_outputs())) + QMessageBox.information(self, 'Invoice', msg , 'OK') + def create_invoice_menu(self, position): item = self.invoices_list.itemAt(position) if not item: return + k = self.invoices_list.indexOfTopLevelItem(item) + key = self.invoices.keys()[k] menu = QMenu() - menu.addAction(_("Delete"), lambda: self.delete_invoice(item)) + menu.addAction(_("Details"), lambda: self.show_invoice(key)) + menu.addAction(_("Delete"), lambda: self.delete_invoice(key)) menu.exec_(self.invoices_list.viewport().mapToGlobal(position)) DIR diff --git a/gui/qt/util.py b/gui/qt/util.py t@@ -56,17 +56,19 @@ class HelpButton(QPushButton): def __init__(self, text): QPushButton.__init__(self, '?') self.help_text = text - self.alt_text = None self.setFocusPolicy(Qt.NoFocus) self.setFixedWidth(20) - self.clicked.connect(lambda: QMessageBox.information(self, 'Help', self.get_text(), 'OK') ) + self.alt = None + self.clicked.connect(self.onclick) - def get_text(self): - return self.alt_text if self.alt_text else self.help_text - - def set_alt(self, t): - self.alt_text = t + def set_alt(self, func): + self.alt = func + def onclick(self): + if self.alt: + apply(self.alt) + else: + QMessageBox.information(self, 'Help', self.help_text, 'OK') DIR diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py t@@ -7,20 +7,19 @@ import threading import time import traceback import urllib2 +import urlparse + try: import paymentrequest_pb2 except: - print "protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto" - raise Exception() + sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto'") try: import requests except ImportError: sys.exit("Error: requests does not seem to be installed. Try 'sudo pip install requests'") -import urlparse - import bitcoin import util t@@ -35,8 +34,7 @@ PR_UNPAID = 0 PR_EXPIRED = 1 PR_SENT = 2 # sent but not propagated PR_PAID = 3 # send and propagated - - +PR_ERROR = 4 # could not parse ca_list = {} t@@ -77,10 +75,12 @@ class PaymentRequest: self.config = config self.outputs = [] self.error = "" + self.dir_path = os.path.join( self.config.path, 'requests') + if not os.path.exists(self.dir_path): + os.mkdir(self.dir_path) def read(self, url): self.url = url - u = urlparse.urlparse(url) self.domain = u.netloc try: t@@ -97,6 +97,30 @@ class PaymentRequest: self.error = "cannot read" return + self.id = bitcoin.sha256(r)[0:16].encode('hex') + filename = os.path.join(self.dir_path, self.id) + with open(filename,'w') as f: + f.write(r) + + return self.parse(r) + + + def get_status(self): + if self.error: + return self.error + else: + return self.status + + + def read_file(self, key): + filename = os.path.join(self.dir_path, key) + with open(filename,'r') as f: + r = f.read() + + self.parse(r) + + + def parse(self, r): try: self.data = paymentrequest_pb2.PaymentRequest() self.data.ParseFromString(r) t@@ -104,17 +128,6 @@ class PaymentRequest: self.error = "cannot parse payment request" return - self.id = bitcoin.sha256(r)[0:16].encode('hex') - print self.id - - dir_path = os.path.join( self.config.path, 'requests') - if not os.path.exists(dir_path): - os.mkdir(dir_path) - filename = os.path.join(dir_path, self.id) - with open(filename,'w') as f: - f.write(r) - - def verify(self): try: t@@ -217,25 +230,28 @@ class PaymentRequest: ### SIG Verified - self.payment_details = pay_det = paymentrequest_pb2.PaymentDetails() - pay_det.ParseFromString(paymntreq.serialized_payment_details) - - if pay_det.expires and pay_det.expires < int(time.time()): - self.error = "ERROR: Payment Request has Expired." - return False + self.details = pay_det = paymentrequest_pb2.PaymentDetails() + self.details.ParseFromString(paymntreq.serialized_payment_details) for o in pay_det.outputs: addr = transaction.get_address_from_output_script(o.script)[1] self.outputs.append( (addr, o.amount) ) - self.memo = pay_det.memo + self.memo = self.details.memo if CA_match: self.status = 'Signed by Trusted CA:\n' + CA_OU - print "payment url", pay_det.payment_url + self.payment_url = self.details.payment_url + + if self.has_expired(): + self.error = "ERROR: Payment Request has Expired." + return False + return True + def has_expired(self): + return self.details.expires and self.details.expires < int(time.time()) def get_amount(self): return sum(map(lambda x:x[1], self.outputs)) t@@ -246,10 +262,16 @@ class PaymentRequest: def get_id(self): return self.id + def get_outputs(self): + return self.outputs + def send_ack(self, raw_tx, refund_addr): - pay_det = self.payment_details - if not pay_det.payment_url: + if self.has_expired(): + return False, "has expired" + + pay_det = self.details + if not self.details.payment_url: return False, "no url" paymnt = paymentrequest_pb2.Payment() t@@ -302,7 +324,7 @@ if __name__ == "__main__": print 'Payment Request Verified Domain: ', pr.domain print 'outputs', pr.outputs - print 'Payment Memo: ', pr.payment_details.memo + print 'Payment Memo: ', pr.details.memo tx = "blah" pr.send_ack(tx, refund_addr = "1vXAXUnGitimzinpXrqDWVU4tyAAQ34RA")