mirror of
https://github.com/basicswap/basicswap.git
synced 2024-12-23 11:59:36 +00:00
ui: Add pagination and filters to smsgaddresses page
This commit is contained in:
parent
b5a4df9908
commit
22576c0316
6 changed files with 273 additions and 128 deletions
|
@ -6178,17 +6178,35 @@ class BasicSwap(BaseApp):
|
||||||
finally:
|
finally:
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
|
||||||
def listAllSMSGAddresses(self, addr_id=None):
|
def listAllSMSGAddresses(self, filters={}):
|
||||||
filters = ''
|
query_str = 'SELECT addr_id, addr, use_type, active_ind, created_at, note, pubkey FROM smsgaddresses'
|
||||||
if addr_id is not None:
|
query_str += ' WHERE active_ind = 1 '
|
||||||
filters += f' WHERE addr_id = {addr_id} '
|
query_data = {}
|
||||||
self.mxDB.acquire()
|
|
||||||
try:
|
|
||||||
session = scoped_session(self.session_factory)
|
|
||||||
rv = []
|
|
||||||
query_str = f'SELECT addr_id, addr, use_type, active_ind, created_at, note, pubkey FROM smsgaddresses {filters} ORDER BY created_at'
|
|
||||||
|
|
||||||
q = session.execute(query_str)
|
if 'addr_id' in filters:
|
||||||
|
query_str += ' AND addr_id = :addr_id '
|
||||||
|
query_data['addr_id'] = filters['addr_id']
|
||||||
|
if 'addressnote' in filters:
|
||||||
|
query_str += ' AND note LIKE :note '
|
||||||
|
query_data['note'] = '%' + filters['addressnote'] + '%'
|
||||||
|
if 'addr_type' in filters and filters['addr_type'] > -1:
|
||||||
|
query_str += ' AND use_type = :addr_type '
|
||||||
|
query_data['addr_type'] = filters['addr_type']
|
||||||
|
|
||||||
|
sort_dir = filters.get('sort_dir', 'DESC').upper()
|
||||||
|
sort_by = filters.get('sort_by', 'created_at')
|
||||||
|
query_str += f' ORDER BY {sort_by} {sort_dir}'
|
||||||
|
limit = filters.get('limit', None)
|
||||||
|
if limit is not None:
|
||||||
|
query_str += f' LIMIT {limit}'
|
||||||
|
offset = filters.get('offset', None)
|
||||||
|
if offset is not None:
|
||||||
|
query_str += f' OFFSET {offset}'
|
||||||
|
|
||||||
|
try:
|
||||||
|
session = self.openSession()
|
||||||
|
rv = []
|
||||||
|
q = session.execute(query_str, query_data)
|
||||||
for row in q:
|
for row in q:
|
||||||
rv.append({
|
rv.append({
|
||||||
'id': row[0],
|
'id': row[0],
|
||||||
|
@ -6201,9 +6219,27 @@ class BasicSwap(BaseApp):
|
||||||
})
|
})
|
||||||
return rv
|
return rv
|
||||||
finally:
|
finally:
|
||||||
session.close()
|
self.closeSession(session, commit=False)
|
||||||
session.remove()
|
|
||||||
self.mxDB.release()
|
def listSmsgAddresses(self, use_type_str):
|
||||||
|
if use_type_str == 'offer_send_from':
|
||||||
|
use_type = AddressTypes.OFFER
|
||||||
|
elif use_type_str == 'offer_send_to':
|
||||||
|
use_type = AddressTypes.SEND_OFFER
|
||||||
|
elif use_type_str == 'bid':
|
||||||
|
use_type = AddressTypes.BID
|
||||||
|
else:
|
||||||
|
raise ValueError('Unknown address type')
|
||||||
|
|
||||||
|
try:
|
||||||
|
session = self.openSession()
|
||||||
|
rv = []
|
||||||
|
q = session.execute('SELECT sa.addr, ki.label FROM smsgaddresses AS sa LEFT JOIN knownidentities AS ki ON sa.addr = ki.address WHERE sa.use_type = {} AND sa.active_ind = 1 ORDER BY sa.addr_id DESC'.format(use_type))
|
||||||
|
for row in q:
|
||||||
|
rv.append((row[0], row[1]))
|
||||||
|
return rv
|
||||||
|
finally:
|
||||||
|
self.closeSession(session, commit=False)
|
||||||
|
|
||||||
def listAutomationStrategies(self, filters={}):
|
def listAutomationStrategies(self, filters={}):
|
||||||
try:
|
try:
|
||||||
|
@ -6341,29 +6377,6 @@ class BasicSwap(BaseApp):
|
||||||
session.remove()
|
session.remove()
|
||||||
self.mxDB.release()
|
self.mxDB.release()
|
||||||
|
|
||||||
def listSmsgAddresses(self, use_type_str):
|
|
||||||
if use_type_str == 'offer_send_from':
|
|
||||||
use_type = AddressTypes.OFFER
|
|
||||||
elif use_type_str == 'offer_send_to':
|
|
||||||
use_type = AddressTypes.SEND_OFFER
|
|
||||||
elif use_type_str == 'bid':
|
|
||||||
use_type = AddressTypes.BID
|
|
||||||
else:
|
|
||||||
raise ValueError('Unknown address type')
|
|
||||||
|
|
||||||
self.mxDB.acquire()
|
|
||||||
try:
|
|
||||||
session = scoped_session(self.session_factory)
|
|
||||||
rv = []
|
|
||||||
q = session.execute('SELECT sa.addr, ki.label FROM smsgaddresses AS sa LEFT JOIN knownidentities AS ki ON sa.addr = ki.address WHERE sa.use_type = {} AND sa.active_ind = 1 ORDER BY sa.addr_id DESC'.format(use_type))
|
|
||||||
for row in q:
|
|
||||||
rv.append((row[0], row[1]))
|
|
||||||
return rv
|
|
||||||
finally:
|
|
||||||
session.close()
|
|
||||||
session.remove()
|
|
||||||
self.mxDB.release()
|
|
||||||
|
|
||||||
def createCoinALockRefundSwipeTx(self, ci, bid, offer, xmr_swap, xmr_offer):
|
def createCoinALockRefundSwipeTx(self, ci, bid, offer, xmr_swap, xmr_offer):
|
||||||
self.log.debug('Creating %s lock refund swipe tx', ci.coin_name())
|
self.log.debug('Creating %s lock refund swipe tx', ci.coin_name())
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ from jinja2 import Environment, PackageLoader
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .util import (
|
from .util import (
|
||||||
dumpj,
|
dumpj,
|
||||||
ensure,
|
|
||||||
toBool,
|
toBool,
|
||||||
LockedCoinError,
|
LockedCoinError,
|
||||||
format_timestamp,
|
format_timestamp,
|
||||||
|
@ -29,7 +28,6 @@ from .chainparams import (
|
||||||
from .basicswap_util import (
|
from .basicswap_util import (
|
||||||
strTxState,
|
strTxState,
|
||||||
strBidState,
|
strBidState,
|
||||||
strAddressType,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from .js_server import (
|
from .js_server import (
|
||||||
|
@ -56,21 +54,12 @@ from .ui.page_wallet import page_wallets, page_wallet
|
||||||
from .ui.page_settings import page_settings
|
from .ui.page_settings import page_settings
|
||||||
from .ui.page_encryption import page_changepassword, page_unlock, page_lock
|
from .ui.page_encryption import page_changepassword, page_unlock, page_lock
|
||||||
from .ui.page_identity import page_identity
|
from .ui.page_identity import page_identity
|
||||||
|
from .ui.page_smsgaddresses import page_smsgaddresses
|
||||||
|
|
||||||
env = Environment(loader=PackageLoader('basicswap', 'templates'))
|
env = Environment(loader=PackageLoader('basicswap', 'templates'))
|
||||||
env.filters['formatts'] = format_timestamp
|
env.filters['formatts'] = format_timestamp
|
||||||
|
|
||||||
|
|
||||||
def validateTextInput(text, name, messages, max_length=None):
|
|
||||||
if max_length is not None and len(text) > max_length:
|
|
||||||
messages.append(f'Error: {name} is too long')
|
|
||||||
return False
|
|
||||||
if len(text) > 0 and all(c.isalnum() or c.isspace() for c in text) is False:
|
|
||||||
messages.append(f'Error: {name} must consist of only letters and digits')
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def extractDomain(url):
|
def extractDomain(url):
|
||||||
return url.split('://', 1)[1].split('/', 1)[0]
|
return url.split('://', 1)[1].split('/', 1)[0]
|
||||||
|
|
||||||
|
@ -396,82 +385,6 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
'summary': summary,
|
'summary': summary,
|
||||||
})
|
})
|
||||||
|
|
||||||
def page_smsgaddresses(self, url_split, post_string):
|
|
||||||
swap_client = self.server.swap_client
|
|
||||||
swap_client.checkSystemStatus()
|
|
||||||
summary = swap_client.getSummary()
|
|
||||||
|
|
||||||
page_data = {}
|
|
||||||
messages = []
|
|
||||||
err_messages = []
|
|
||||||
smsgaddresses = []
|
|
||||||
|
|
||||||
listaddresses = True
|
|
||||||
form_data = self.checkForm(post_string, 'smsgaddresses', err_messages)
|
|
||||||
if form_data:
|
|
||||||
edit_address_id = None
|
|
||||||
for key in form_data:
|
|
||||||
if key.startswith(b'editaddr_'):
|
|
||||||
edit_address_id = int(key.split(b'_')[1])
|
|
||||||
break
|
|
||||||
if edit_address_id is not None:
|
|
||||||
listaddresses = False
|
|
||||||
page_data['edit_address'] = edit_address_id
|
|
||||||
page_data['addr_data'] = swap_client.listAllSMSGAddresses(addr_id=edit_address_id)[0]
|
|
||||||
elif b'saveaddr' in form_data:
|
|
||||||
edit_address_id = int(form_data[b'edit_address_id'][0].decode('utf-8'))
|
|
||||||
edit_addr = form_data[b'edit_address'][0].decode('utf-8')
|
|
||||||
active_ind = int(form_data[b'active_ind'][0].decode('utf-8'))
|
|
||||||
ensure(active_ind in (0, 1), 'Invalid sort by')
|
|
||||||
addressnote = '' if b'addressnote' not in form_data else form_data[b'addressnote'][0].decode('utf-8')
|
|
||||||
if not validateTextInput(addressnote, 'Address note', messages, max_length=30):
|
|
||||||
listaddresses = False
|
|
||||||
page_data['edit_address'] = edit_address_id
|
|
||||||
else:
|
|
||||||
swap_client.editSMSGAddress(edit_addr, active_ind=active_ind, addressnote=addressnote)
|
|
||||||
messages.append(f'Edited address {edit_addr}')
|
|
||||||
elif b'shownewaddr' in form_data:
|
|
||||||
listaddresses = False
|
|
||||||
page_data['new_address'] = True
|
|
||||||
elif b'showaddaddr' in form_data:
|
|
||||||
listaddresses = False
|
|
||||||
page_data['new_send_address'] = True
|
|
||||||
elif b'createnewaddr' in form_data:
|
|
||||||
addressnote = '' if b'addressnote' not in form_data else form_data[b'addressnote'][0].decode('utf-8')
|
|
||||||
if not validateTextInput(addressnote, 'Address note', messages, max_length=30):
|
|
||||||
listaddresses = False
|
|
||||||
page_data['new_address'] = True
|
|
||||||
else:
|
|
||||||
new_addr, pubkey = swap_client.newSMSGAddress(addressnote=addressnote)
|
|
||||||
messages.append(f'Created address {new_addr}, pubkey {pubkey}')
|
|
||||||
elif b'createnewsendaddr' in form_data:
|
|
||||||
pubkey_hex = form_data[b'addresspubkey'][0].decode('utf-8')
|
|
||||||
addressnote = '' if b'addressnote' not in form_data else form_data[b'addressnote'][0].decode('utf-8')
|
|
||||||
if not validateTextInput(addressnote, 'Address note', messages, max_length=30) or \
|
|
||||||
not validateTextInput(pubkey_hex, 'Pubkey', messages, max_length=66):
|
|
||||||
listaddresses = False
|
|
||||||
page_data['new_send_address'] = True
|
|
||||||
else:
|
|
||||||
new_addr = swap_client.addSMSGAddress(pubkey_hex, addressnote=addressnote)
|
|
||||||
messages.append(f'Added address {new_addr}')
|
|
||||||
|
|
||||||
if listaddresses is True:
|
|
||||||
smsgaddresses = swap_client.listAllSMSGAddresses()
|
|
||||||
network_addr = swap_client.network_addr
|
|
||||||
|
|
||||||
for addr in smsgaddresses:
|
|
||||||
addr['type'] = strAddressType(addr['type'])
|
|
||||||
|
|
||||||
template = env.get_template('smsgaddresses.html')
|
|
||||||
return self.render_template(template, {
|
|
||||||
'messages': messages,
|
|
||||||
'err_messages': err_messages,
|
|
||||||
'data': page_data,
|
|
||||||
'smsgaddresses': smsgaddresses,
|
|
||||||
'network_addr': network_addr,
|
|
||||||
'summary': summary,
|
|
||||||
})
|
|
||||||
|
|
||||||
def page_shutdown(self, url_split, post_string):
|
def page_shutdown(self, url_split, post_string):
|
||||||
swap_client = self.server.swap_client
|
swap_client = self.server.swap_client
|
||||||
|
|
||||||
|
@ -611,7 +524,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
if page == 'watched':
|
if page == 'watched':
|
||||||
return self.page_watched(url_split, post_string)
|
return self.page_watched(url_split, post_string)
|
||||||
if page == 'smsgaddresses':
|
if page == 'smsgaddresses':
|
||||||
return self.page_smsgaddresses(url_split, post_string)
|
return page_smsgaddresses(self, url_split, post_string)
|
||||||
if page == 'identity':
|
if page == 'identity':
|
||||||
return page_identity(self, url_split, post_string)
|
return page_identity(self, url_split, post_string)
|
||||||
if page == 'tor':
|
if page == 'tor':
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
<div class="w-full md:w-0/12">
|
<div class="w-full md:w-0/12">
|
||||||
<div class="flex flex-wrap justify-end -m-1.5">
|
<div class="flex flex-wrap justify-end -m-1.5">
|
||||||
<div class="w-full md:w-auto p-1.5 ml-2">
|
<div class="w-full md:w-auto p-1.5 ml-2">
|
||||||
<button name="saveaddr" value="Save Address" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none "><svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="square" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="miter" class="nc-icon-wrapper" stroke-miterlimit="10"><line x1="12" y1="7" x2="12" y2="17" stroke="#ffffff"></line> <line x1="17" y1="12" x2="7" y2="12" stroke="#ffffff"></line> <circle cx="12" cy="12" r="11"></circle></g></svg>Create Address</button>
|
<button name="saveaddr" value="Save Address" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none "><svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="square" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="miter" class="nc-icon-wrapper" stroke-miterlimit="10"><line x1="12" y1="7" x2="12" y2="17" stroke="#ffffff"></line> <line x1="17" y1="12" x2="7" y2="12" stroke="#ffffff"></line> <circle cx="12" cy="12" r="11"></circle></g></svg>Save Address</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full md:w-auto p-1.5 ml-2">
|
<div class="w-full md:w-auto p-1.5 ml-2">
|
||||||
<button name="cancel" value="Cancel" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"><svg class="text-gray-500 w-5 h-5 mr-2" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="square" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="miter" class="nc-icon-wrapper" stroke-miterlimit="10"><line data-cap="butt" x1="18" y1="12" x2="7" y2="12" stroke-linecap="butt" stroke="#556987"></line> <polyline points=" 11,16 7,12 11,8 " stroke="#5569878"></polyline> <circle cx="12" cy="12" r="11"></circle></g></svg>Go Back</button>
|
<button name="cancel" value="Cancel" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"><svg class="text-gray-500 w-5 h-5 mr-2" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="square" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="miter" class="nc-icon-wrapper" stroke-miterlimit="10"><line data-cap="butt" x1="18" y1="12" x2="7" y2="12" stroke-linecap="butt" stroke="#556987"></line> <polyline points=" 11,16 7,12 11,8 " stroke="#5569878"></polyline> <circle cx="12" cy="12" r="11"></circle></g></svg>Go Back</button>
|
||||||
|
@ -186,6 +186,85 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
<div class="container px-0 mx-auto mt-5">
|
||||||
|
<div class="overflow-x-auto relative border sm:rounded-lg">
|
||||||
|
<table class="w-full text-sm text-left text-gray-500 outline-none border-gray-300">
|
||||||
|
<thead class="text-xs text-gray-700 border-b uppercase bg-gray-50 outline-none border-gray-300">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="py-3 px-6">Filter</th>
|
||||||
|
<th scope="col" class="py-3 px-6"></th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr class="bg-white border-t hover:bg-gray-50">
|
||||||
|
<td class="py-4 px-6 bold w-96"> Sort by: </td>
|
||||||
|
<td class="py-4 bold w-96">
|
||||||
|
<select class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="sort_by">
|
||||||
|
<option value="created_at" {% if filters.sort_by=='created_at' %} selected{% endif %}>Created At</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td class="py-4 px-6 pr-5">
|
||||||
|
<select class="pr-15 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="sort_dir">
|
||||||
|
<option value="asc" {% if filters.sort_dir=='asc' %} selected{% endif %}>Ascending</option>
|
||||||
|
<option value="desc" {% if filters.sort_dir=='desc' %} selected{% endif %}>Descending</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-white border-t hover:bg-gray-50">
|
||||||
|
<td class="py-4 px-6 bold w-96">Note</td>
|
||||||
|
<td class="py-4 pr-5">
|
||||||
|
<input class="appearance-none bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block p-2.5 w-full" name="filter_addressnote" type="text" value="{{ filters.addressnote }}" maxlength="30"> </td>
|
||||||
|
</tr>
|
||||||
|
<tr class="bg-white border-t hover:bg-gray-50">
|
||||||
|
<td class="py-4 px-6 bold w-96">Type</td>
|
||||||
|
<td class="py-4 pr-5">
|
||||||
|
<select class="appearance-none bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg outline-none focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" name="filter_addr_type">
|
||||||
|
<option{% if filters.addr_type=="-1" %} selected{% endif %} value="-1">Any</option>
|
||||||
|
{% for a in page_data.addr_types %}
|
||||||
|
<option{% if filters.addr_type==a[0] %} selected{% endif %} value="{{ a[0] }}">{{ a[1] }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pt-10 bg-white bg-opacity-60 rounded-b-md">
|
||||||
|
<div class="w-full md:w-0/12">
|
||||||
|
<div class="flex flex-wrap justify-end -m-1.5">
|
||||||
|
<div class="w-full md:w-auto p-1.5">
|
||||||
|
<button type="submit" name='pageback' value="Page Back" class="outline-none flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none">
|
||||||
|
<svg aria-hidden="true" class="mr-2 w-5 h-5" fill="#556987" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M7.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l2.293 2.293a1 1 0 010 1.414z" clip-rule="evenodd"></path>
|
||||||
|
</svg> <span>Page Back</span> </button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="w-full md:w-auto p-1.5">
|
||||||
|
<p class="text-sm font-heading">Page: {{ filters.page_no }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full md:w-auto p-1.5">
|
||||||
|
<button type="submit" name='pageforwards' value="Page Forwards" class="outline-none flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"> <span>Page Forwards</span>
|
||||||
|
<svg aria-hidden="true" class="ml-2 w-5 h-5" fill="#556987" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="w-full md:w-auto p-1.5 ml-2">
|
||||||
|
<button name='clearfilters' value="Clear Filters" class="flex flex-wrap justify-center w-full px-4 py-2.5 font-medium text-sm text-coolGray-500 hover:text-coolGray-600 border border-coolGray-200 hover:border-coolGray-300 bg-white rounded-md shadow-button focus:ring-0 focus:outline-none"> <svg class="mr-2 w-5 h-5" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24">
|
||||||
|
<g stroke-linecap="round" stroke-width="2" fill="none" stroke="#556987" stroke-linejoin="round" class="nc-icon-wrapper">
|
||||||
|
<rect x="2" y="2" width="7" height="7"></rect>
|
||||||
|
<rect x="15" y="15" width="7" height="7"></rect>
|
||||||
|
<rect x="2" y="15" width="7" height="7"></rect>
|
||||||
|
<polyline points="15 6 17 8 22 3" stroke="#556987"></polyline>
|
||||||
|
</g>
|
||||||
|
</svg> Clear Filters</button>
|
||||||
|
</div>
|
||||||
|
<div class="w-full md:w-auto p-1.5 ml-2">
|
||||||
|
<button name="" value="Submit" type="submit" class="flex flex-wrap justify-center w-full px-4 py-2.5 bg-blue-500 hover:bg-blue-600 font-medium text-sm text-white border border-blue-500 rounded-md shadow-button focus:ring-0 focus:outline-none"><svg class="text-gray-500 w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><g stroke-linecap="round" stroke-width="2" fill="none" stroke="#ffffff" stroke-linejoin="round" ><polyline points=" 6,12 10,16 18,8 " stroke="#ffffff"></polyline> <circle cx="12" cy="12" r="11"></circle></g></svg> Apply</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="container px-0 mx-auto mt-5">
|
<div class="container px-0 mx-auto mt-5">
|
||||||
<div class="overflow-x-auto relative border sm:rounded-lg">
|
<div class="overflow-x-auto relative border sm:rounded-lg">
|
||||||
<table class="w-full text-sm text-left text-gray-500 outline-none border-gray-300">
|
<table class="w-full text-sm text-left text-gray-500 outline-none border-gray-300">
|
||||||
|
@ -200,7 +279,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr class="bg-white border-t hover:bg-gray-50">
|
<tr class="bg-white border-t hover:bg-gray-50">
|
||||||
<td class="py-6 px-6"><b class="monospace">{{ network_addr }}</b></td>
|
<td class="py-6 px-6"><b class="monospace">{{ page_data.network_addr }}</b></td>
|
||||||
<td class="py-4">Network Address
|
<td class="py-4">Network Address
|
||||||
<td />
|
<td />
|
||||||
<td class="py-4">
|
<td class="py-4">
|
||||||
|
@ -233,6 +312,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<input type="hidden" name="pageno" value="{{ filters.page_no }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<input type="hidden" name="formid" value="{{ form_id }}"></form>
|
<input type="hidden" name="formid" value="{{ form_id }}"></form>
|
||||||
</div>
|
</div>
|
||||||
|
|
128
basicswap/ui/page_smsgaddresses.py
Normal file
128
basicswap/ui/page_smsgaddresses.py
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2023 tecnovert
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
|
||||||
|
from .util import (
|
||||||
|
PAGE_LIMIT,
|
||||||
|
get_data_entry,
|
||||||
|
have_data_entry,
|
||||||
|
get_data_entry_or,
|
||||||
|
validateTextInput,
|
||||||
|
set_pagination_filters,
|
||||||
|
)
|
||||||
|
from basicswap.util import (
|
||||||
|
ensure,
|
||||||
|
)
|
||||||
|
from basicswap.basicswap_util import (
|
||||||
|
AddressTypes,
|
||||||
|
strAddressType,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def page_smsgaddresses(self, url_split, post_string):
|
||||||
|
swap_client = self.server.swap_client
|
||||||
|
swap_client.checkSystemStatus()
|
||||||
|
summary = swap_client.getSummary()
|
||||||
|
|
||||||
|
filters = {
|
||||||
|
'page_no': 1,
|
||||||
|
'limit': PAGE_LIMIT,
|
||||||
|
'sort_by': 'created_at',
|
||||||
|
'sort_dir': 'desc',
|
||||||
|
'addr_type': -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
page_data = {}
|
||||||
|
messages = []
|
||||||
|
err_messages = []
|
||||||
|
smsgaddresses = []
|
||||||
|
|
||||||
|
listaddresses = True
|
||||||
|
form_data = self.checkForm(post_string, 'smsgaddresses', err_messages)
|
||||||
|
if form_data:
|
||||||
|
edit_address_id = None
|
||||||
|
for key in form_data:
|
||||||
|
if key.startswith(b'editaddr_'):
|
||||||
|
edit_address_id = int(key.split(b'_')[1])
|
||||||
|
break
|
||||||
|
if edit_address_id is not None:
|
||||||
|
listaddresses = False
|
||||||
|
page_data['edit_address'] = edit_address_id
|
||||||
|
page_data['addr_data'] = swap_client.listAllSMSGAddresses({'addr_id': edit_address_id})[0]
|
||||||
|
elif have_data_entry(form_data, 'saveaddr'):
|
||||||
|
edit_address_id = int(get_data_entry(form_data, 'edit_address_id'))
|
||||||
|
edit_addr = get_data_entry(form_data, 'edit_address')
|
||||||
|
active_ind = int(get_data_entry(form_data, 'active_ind'))
|
||||||
|
ensure(active_ind in (0, 1), 'Invalid sort by')
|
||||||
|
addressnote = get_data_entry_or(form_data, 'addressnote', '')
|
||||||
|
if not validateTextInput(addressnote, 'Address note', err_messages, max_length=30):
|
||||||
|
listaddresses = False
|
||||||
|
page_data['edit_address'] = edit_address_id
|
||||||
|
else:
|
||||||
|
swap_client.editSMSGAddress(edit_addr, active_ind=active_ind, addressnote=addressnote)
|
||||||
|
messages.append(f'Edited address {edit_addr}')
|
||||||
|
elif have_data_entry(form_data, 'shownewaddr'):
|
||||||
|
listaddresses = False
|
||||||
|
page_data['new_address'] = True
|
||||||
|
elif have_data_entry(form_data, 'showaddaddr'):
|
||||||
|
listaddresses = False
|
||||||
|
page_data['new_send_address'] = True
|
||||||
|
elif have_data_entry(form_data, 'createnewaddr'):
|
||||||
|
addressnote = get_data_entry_or(form_data, 'addressnote', '')
|
||||||
|
if not validateTextInput(addressnote, 'Address note', err_messages, max_length=30):
|
||||||
|
listaddresses = False
|
||||||
|
page_data['new_address'] = True
|
||||||
|
else:
|
||||||
|
new_addr, pubkey = swap_client.newSMSGAddress(addressnote=addressnote)
|
||||||
|
messages.append(f'Created address {new_addr}, pubkey {pubkey}')
|
||||||
|
elif have_data_entry(form_data, 'createnewsendaddr'):
|
||||||
|
pubkey_hex = get_data_entry(form_data, 'addresspubkey')
|
||||||
|
addressnote = get_data_entry_or(form_data, 'addressnote', '')
|
||||||
|
if not validateTextInput(addressnote, 'Address note', messages, max_length=30) or \
|
||||||
|
not validateTextInput(pubkey_hex, 'Pubkey', messages, max_length=66):
|
||||||
|
listaddresses = False
|
||||||
|
page_data['new_send_address'] = True
|
||||||
|
else:
|
||||||
|
new_addr = swap_client.addSMSGAddress(pubkey_hex, addressnote=addressnote)
|
||||||
|
messages.append(f'Added address {new_addr}')
|
||||||
|
|
||||||
|
if not have_data_entry(form_data, 'clearfilters'):
|
||||||
|
if have_data_entry(form_data, 'sort_by'):
|
||||||
|
sort_by = get_data_entry(form_data, 'sort_by')
|
||||||
|
ensure(sort_by in ['created_at', 'rate'], 'Invalid sort by')
|
||||||
|
filters['sort_by'] = sort_by
|
||||||
|
if have_data_entry(form_data, 'sort_dir'):
|
||||||
|
sort_dir = get_data_entry(form_data, 'sort_dir')
|
||||||
|
ensure(sort_dir in ['asc', 'desc'], 'Invalid sort dir')
|
||||||
|
filters['sort_dir'] = sort_dir
|
||||||
|
if have_data_entry(form_data, 'filter_addressnote'):
|
||||||
|
addressnote = get_data_entry(form_data, 'filter_addressnote')
|
||||||
|
if validateTextInput(addressnote, 'Address note', err_messages, max_length=30):
|
||||||
|
filters['addressnote'] = addressnote
|
||||||
|
if have_data_entry(form_data, 'filter_addr_type'):
|
||||||
|
filters['addr_type'] = int(get_data_entry(form_data, 'filter_addr_type'))
|
||||||
|
|
||||||
|
set_pagination_filters(form_data, filters)
|
||||||
|
|
||||||
|
if listaddresses is True:
|
||||||
|
smsgaddresses = swap_client.listAllSMSGAddresses(filters)
|
||||||
|
|
||||||
|
page_data['addr_types'] = [(int(t), strAddressType(t)) for t in AddressTypes]
|
||||||
|
page_data['network_addr'] = swap_client.network_addr
|
||||||
|
|
||||||
|
for addr in smsgaddresses:
|
||||||
|
addr['type'] = strAddressType(addr['type'])
|
||||||
|
|
||||||
|
template = self.server.env.get_template('smsgaddresses.html')
|
||||||
|
return self.render_template(template, {
|
||||||
|
'messages': messages,
|
||||||
|
'err_messages': err_messages,
|
||||||
|
'filters': filters,
|
||||||
|
'data': page_data,
|
||||||
|
'smsgaddresses': smsgaddresses,
|
||||||
|
'page_data': page_data,
|
||||||
|
'summary': summary,
|
||||||
|
})
|
|
@ -446,3 +446,13 @@ def checkAddressesOwned(swap_client, ci, wallet_info):
|
||||||
wallet_info['deposit_address'] = 'Error: unowned address'
|
wallet_info['deposit_address'] = 'Error: unowned address'
|
||||||
elif swap_client._restrict_unknown_seed_wallets and not ci.knownWalletSeed():
|
elif swap_client._restrict_unknown_seed_wallets and not ci.knownWalletSeed():
|
||||||
wallet_info['deposit_address'] = 'WARNING: Unknown wallet seed'
|
wallet_info['deposit_address'] = 'WARNING: Unknown wallet seed'
|
||||||
|
|
||||||
|
|
||||||
|
def validateTextInput(text, name, messages, max_length=None):
|
||||||
|
if max_length is not None and len(text) > max_length:
|
||||||
|
messages.append(f'Error: {name} is too long')
|
||||||
|
return False
|
||||||
|
if len(text) > 0 and all(c.isalnum() or c.isspace() for c in text) is False:
|
||||||
|
messages.append(f'Error: {name} must consist of only letters and digits')
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
- Accepted bids will timeout if the peer does not respond within an hour after the bid expires.
|
- Accepted bids will timeout if the peer does not respond within an hour after the bid expires.
|
||||||
- Ensure messages are always sent from and to the expected addresses.
|
- Ensure messages are always sent from and to the expected addresses.
|
||||||
|
- ui: Add pagination and filters to smsgaddresses page
|
||||||
|
|
||||||
|
|
||||||
0.0.59
|
0.0.59
|
||||||
|
|
Loading…
Reference in a new issue