Browse Source

show payment request details

283
ThomasV 11 years ago
parent
commit
440f972fd3
  1. 6
      gui/qt/__init__.py
  2. 28
      gui/qt/main_window.py
  3. 16
      gui/qt/util.py
  4. 80
      lib/paymentrequest.py

6
gui/qt/__init__.py

@ -169,11 +169,7 @@ class ElectrumGui:
QMessageBox.warning(self.main_window, _('Error'), _('Invalid Amount'), _('OK')) QMessageBox.warning(self.main_window, _('Error'), _('Invalid Amount'), _('OK'))
if request_url: if request_url:
try: from electrum import paymentrequest
from electrum import paymentrequest
except:
print "cannot import paymentrequest"
request_url = None
if not request_url: if not request_url:
self.main_window.set_send(address, amount, label, message) self.main_window.set_send(address, amount, label, message)

28
gui/qt/main_window.py

@ -933,7 +933,8 @@ class ElectrumWindow(QMainWindow):
self.update_invoices_tab() self.update_invoices_tab()
self.payto_help.show() 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.setGreen()
self.payto_e.setText(pr.domain) self.payto_e.setText(pr.domain)
self.amount_e.setText(self.format_amount(pr.get_amount())) self.amount_e.setText(self.format_amount(pr.get_amount()))
@ -973,7 +974,6 @@ class ElectrumWindow(QMainWindow):
h.show() h.show()
self.payto_help.set_alt(None) self.payto_help.set_alt(None)
self.set_pay_from([]) self.set_pay_from([])
self.update_status() self.update_status()
@ -1211,18 +1211,36 @@ class ElectrumWindow(QMainWindow):
menu.exec_(self.contacts_list.viewport().mapToGlobal(position)) menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
def delete_invoice(self, item): def delete_invoice(self, item):
k = self.invoices_list.indexOfTopLevelItem(item)
key = self.invoices.keys()[k]
self.invoices.pop(key) self.invoices.pop(key)
self.wallet.storage.put('invoices', self.invoices) self.wallet.storage.put('invoices', self.invoices)
self.update_invoices_tab() 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): def create_invoice_menu(self, position):
item = self.invoices_list.itemAt(position) item = self.invoices_list.itemAt(position)
if not item: if not item:
return return
k = self.invoices_list.indexOfTopLevelItem(item)
key = self.invoices.keys()[k]
menu = QMenu() 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)) menu.exec_(self.invoices_list.viewport().mapToGlobal(position))

16
gui/qt/util.py

@ -56,17 +56,19 @@ class HelpButton(QPushButton):
def __init__(self, text): def __init__(self, text):
QPushButton.__init__(self, '?') QPushButton.__init__(self, '?')
self.help_text = text self.help_text = text
self.alt_text = None
self.setFocusPolicy(Qt.NoFocus) self.setFocusPolicy(Qt.NoFocus)
self.setFixedWidth(20) 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): def set_alt(self, func):
return self.alt_text if self.alt_text else self.help_text self.alt = func
def set_alt(self, t):
self.alt_text = t
def onclick(self):
if self.alt:
apply(self.alt)
else:
QMessageBox.information(self, 'Help', self.help_text, 'OK')

80
lib/paymentrequest.py

@ -7,20 +7,19 @@ import threading
import time import time
import traceback import traceback
import urllib2 import urllib2
import urlparse
try: try:
import paymentrequest_pb2 import paymentrequest_pb2
except: except:
print "protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto" sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'protoc --proto_path=lib/ --python_out=lib/ lib/paymentrequest.proto'")
raise Exception()
try: try:
import requests import requests
except ImportError: except ImportError:
sys.exit("Error: requests does not seem to be installed. Try 'sudo pip install requests'") sys.exit("Error: requests does not seem to be installed. Try 'sudo pip install requests'")
import urlparse
import bitcoin import bitcoin
import util import util
@ -35,8 +34,7 @@ PR_UNPAID = 0
PR_EXPIRED = 1 PR_EXPIRED = 1
PR_SENT = 2 # sent but not propagated PR_SENT = 2 # sent but not propagated
PR_PAID = 3 # send and propagated PR_PAID = 3 # send and propagated
PR_ERROR = 4 # could not parse
ca_list = {} ca_list = {}
@ -77,10 +75,12 @@ class PaymentRequest:
self.config = config self.config = config
self.outputs = [] self.outputs = []
self.error = "" 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): def read(self, url):
self.url = url self.url = url
u = urlparse.urlparse(url) u = urlparse.urlparse(url)
self.domain = u.netloc self.domain = u.netloc
try: try:
@ -97,6 +97,30 @@ class PaymentRequest:
self.error = "cannot read" self.error = "cannot read"
return 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: try:
self.data = paymentrequest_pb2.PaymentRequest() self.data = paymentrequest_pb2.PaymentRequest()
self.data.ParseFromString(r) self.data.ParseFromString(r)
@ -104,17 +128,6 @@ class PaymentRequest:
self.error = "cannot parse payment request" self.error = "cannot parse payment request"
return 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): def verify(self):
try: try:
@ -217,25 +230,28 @@ class PaymentRequest:
### SIG Verified ### SIG Verified
self.payment_details = pay_det = paymentrequest_pb2.PaymentDetails() self.details = pay_det = paymentrequest_pb2.PaymentDetails()
pay_det.ParseFromString(paymntreq.serialized_payment_details) self.details.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
for o in pay_det.outputs: for o in pay_det.outputs:
addr = transaction.get_address_from_output_script(o.script)[1] addr = transaction.get_address_from_output_script(o.script)[1]
self.outputs.append( (addr, o.amount) ) self.outputs.append( (addr, o.amount) )
self.memo = pay_det.memo self.memo = self.details.memo
if CA_match: if CA_match:
self.status = 'Signed by Trusted CA:\n' + CA_OU 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 return True
def has_expired(self):
return self.details.expires and self.details.expires < int(time.time())
def get_amount(self): def get_amount(self):
return sum(map(lambda x:x[1], self.outputs)) return sum(map(lambda x:x[1], self.outputs))
@ -246,10 +262,16 @@ class PaymentRequest:
def get_id(self): def get_id(self):
return self.id return self.id
def get_outputs(self):
return self.outputs
def send_ack(self, raw_tx, refund_addr): def send_ack(self, raw_tx, refund_addr):
pay_det = self.payment_details if self.has_expired():
if not pay_det.payment_url: return False, "has expired"
pay_det = self.details
if not self.details.payment_url:
return False, "no url" return False, "no url"
paymnt = paymentrequest_pb2.Payment() paymnt = paymentrequest_pb2.Payment()
@ -302,7 +324,7 @@ if __name__ == "__main__":
print 'Payment Request Verified Domain: ', pr.domain print 'Payment Request Verified Domain: ', pr.domain
print 'outputs', pr.outputs print 'outputs', pr.outputs
print 'Payment Memo: ', pr.payment_details.memo print 'Payment Memo: ', pr.details.memo
tx = "blah" tx = "blah"
pr.send_ack(tx, refund_addr = "1vXAXUnGitimzinpXrqDWVU4tyAAQ34RA") pr.send_ack(tx, refund_addr = "1vXAXUnGitimzinpXrqDWVU4tyAAQ34RA")

Loading…
Cancel
Save