From 8e344ecf4b30b5ddc9734a58e8e1b85efca0929a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 30 Dec 2022 09:24:31 +0100 Subject: [PATCH 01/27] gerty mypy fixes --- lnbits/extensions/gerty/__init__.py | 2 - lnbits/extensions/gerty/crud.py | 7 ++- lnbits/extensions/gerty/helpers.py | 93 ++++++++++------------------ lnbits/extensions/gerty/models.py | 1 - lnbits/extensions/gerty/views.py | 6 +- lnbits/extensions/gerty/views_api.py | 33 ++++------ pyproject.toml | 1 - 7 files changed, 49 insertions(+), 94 deletions(-) diff --git a/lnbits/extensions/gerty/__init__.py b/lnbits/extensions/gerty/__init__.py index bd353c78..5b24718a 100644 --- a/lnbits/extensions/gerty/__init__.py +++ b/lnbits/extensions/gerty/__init__.py @@ -5,11 +5,9 @@ from fastapi.staticfiles import StaticFiles from lnbits.db import Database from lnbits.helpers import template_renderer -from lnbits.tasks import catch_everything_and_restart db = Database("ext_gerty") - gerty_static_files = [ { "path": "/gerty/static", diff --git a/lnbits/extensions/gerty/crud.py b/lnbits/extensions/gerty/crud.py index 1164b6ee..3012eeae 100644 --- a/lnbits/extensions/gerty/crud.py +++ b/lnbits/extensions/gerty/crud.py @@ -55,7 +55,10 @@ async def update_gerty(gerty_id: str, **kwargs) -> Gerty: await db.execute( f"UPDATE gerty.gertys SET {q} WHERE id = ?", (*kwargs.values(), gerty_id) ) - return await get_gerty(gerty_id) + + gerty = await get_gerty(gerty_id) + assert gerty + return gerty async def get_gerty(gerty_id: str) -> Optional[Gerty]: @@ -82,7 +85,7 @@ async def delete_gerty(gerty_id: str) -> None: #############MEMPOOL########### -async def get_mempool_info(endPoint: str, gerty) -> Optional[Mempool]: +async def get_mempool_info(endPoint: str, gerty) -> dict: logger.debug(endPoint) endpoints = MempoolEndpoint() url = "" diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 24b22b5d..5897423e 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -3,15 +3,16 @@ import os import random import textwrap from datetime import datetime, timedelta +from typing import List import httpx from loguru import logger -from lnbits.core.crud import get_user, get_wallet_for_key +from lnbits.core.crud import get_wallet_for_key from lnbits.settings import settings from lnbits.utils.exchange_rates import satoshis_amount_as_fiat -from .crud import get_gerty, get_mempool_info +from .crud import get_mempool_info from .number_prefixer import * @@ -24,8 +25,8 @@ def get_percent_difference(current, previous, precision=3): def get_text_item_dict( text: str, font_size: int, - x_pos: int = None, - y_pos: int = None, + x_pos: int = -1, + y_pos: int = -1, gerty_type: str = "Gerty", ): # Get line size by font size @@ -63,12 +64,12 @@ def get_text_item_dict( # logger.debug('multilineText') # logger.debug(multilineText) - text = {"value": multilineText, "size": font_size} - if x_pos is None and y_pos is None: - text["position"] = "center" + data_text = {"value": multilineText, "size": font_size} + if x_pos == -1 and y_pos == -1: + data_text["position"] = "center" else: - text["x"] = x_pos - text["y"] = y_pos + data_text["x"] = x_pos if x_pos > 0 else 0 + data_text["y"] = y_pos if x_pos > 0 else 0 return text @@ -293,8 +294,7 @@ def get_next_update_time(sleep_time_seconds: int = 0, utc_offset: int = 0): def gerty_should_sleep(utc_offset: int = 0): utc_now = datetime.utcnow() local_time = utc_now + timedelta(hours=utc_offset) - hours = local_time.strftime("%H") - hours = int(hours) + hours = int(local_time.strftime("%H")) if hours >= 22 and hours <= 23: return True else: @@ -380,23 +380,19 @@ async def get_mining_stat(stat_slug: str, gerty): async def api_get_mining_stat(stat_slug: str, gerty): - stat = "" + stat = {} if stat_slug == "mining_current_hash_rate": - async with httpx.AsyncClient() as client: - r = await get_mempool_info("hashrate_1m", gerty) - data = r - stat = {} - stat["current"] = data["currentHashrate"] - stat["1w"] = data["hashrates"][len(data["hashrates"]) - 7]["avgHashrate"] + r = await get_mempool_info("hashrate_1m", gerty) + data = r + stat["current"] = data["currentHashrate"] + stat["1w"] = data["hashrates"][len(data["hashrates"]) - 7]["avgHashrate"] elif stat_slug == "mining_current_difficulty": - async with httpx.AsyncClient() as client: - r = await get_mempool_info("hashrate_1m", gerty) - data = r - stat = {} - stat["current"] = data["currentDifficulty"] - stat["previous"] = data["difficulty"][len(data["difficulty"]) - 2][ - "difficulty" - ] + r = await get_mempool_info("hashrate_1m", gerty) + data = r + stat["current"] = data["currentDifficulty"] + stat["previous"] = data["difficulty"][len(data["difficulty"]) - 2][ + "difficulty" + ] return stat @@ -427,10 +423,10 @@ def get_screen_slug_by_index(index: int, screens_list): # Get a list of text items for the screen number -async def get_screen_data(screen_num: int, screens_list: dict, gerty): +async def get_screen_data(screen_num: int, screens_list: list, gerty): screen_slug = get_screen_slug_by_index(screen_num, screens_list) # first get the relevant slug from the display_preferences - areas = [] + areas: List = [] title = "" if screen_slug == "dashboard": @@ -533,9 +529,10 @@ async def get_screen_data(screen_num: int, screens_list: dict, gerty): title = "Lightning Network" areas = await get_lightning_stats(gerty) - data = {} - data["title"] = title - data["areas"] = areas + data = { + "title": title, + "areas": areas, + } return data @@ -598,7 +595,7 @@ async def get_dashboard(gerty): text = [] text.append( get_text_item_dict( - text=await get_time_remaining_next_difficulty_adjustment(gerty), + text=await get_time_remaining_next_difficulty_adjustment(gerty) or "0", font_size=15, gerty_type=gerty.type, ) @@ -630,7 +627,7 @@ async def get_lnbits_wallet_balances(gerty): return wallets -async def get_placeholder_text(): +async def get_placeholder_text(gerty): return [ get_text_item_dict( text="Some placeholder text", @@ -838,14 +835,14 @@ async def get_time_remaining_next_difficulty_adjustment(gerty): r = await get_mempool_info("difficulty_adjustment", gerty) stat = r["remainingTime"] time = get_time_remaining(stat / 1000, 3) - return time + return time async def get_mempool_stat(stat_slug: str, gerty): text = [] if isinstance(gerty.mempool_endpoint, str): if stat_slug == "mempool_tx_count": - r = get_mempool_info("mempool", gerty) + r = await get_mempool_info("mempool", gerty) if stat_slug == "mempool_tx_count": stat = round(r["count"]) text.append( @@ -951,29 +948,3 @@ async def get_mempool_stat(stat_slug: str, gerty): return text -def get_date_suffix(dayNumber): - if 4 <= dayNumber <= 20 or 24 <= dayNumber <= 30: - return "th" - else: - return ["st", "nd", "rd"][dayNumber % 10 - 1] - - -def get_time_remaining(seconds, granularity=2): - intervals = ( - # ('weeks', 604800), # 60 * 60 * 24 * 7 - ("days", 86400), # 60 * 60 * 24 - ("hours", 3600), # 60 * 60 - ("minutes", 60), - ("seconds", 1), - ) - - result = [] - - for name, count in intervals: - value = seconds // count - if value: - seconds -= value * count - if value == 1: - name = name.rstrip("s") - result.append("{} {}".format(round(value), name)) - return ", ".join(result[:granularity]) diff --git a/lnbits/extensions/gerty/models.py b/lnbits/extensions/gerty/models.py index 9ff29bda..cb19c2bc 100644 --- a/lnbits/extensions/gerty/models.py +++ b/lnbits/extensions/gerty/models.py @@ -1,5 +1,4 @@ from sqlite3 import Row -from typing import Optional from fastapi import Query from pydantic import BaseModel diff --git a/lnbits/extensions/gerty/views.py b/lnbits/extensions/gerty/views.py index 66194a50..238e3721 100644 --- a/lnbits/extensions/gerty/views.py +++ b/lnbits/extensions/gerty/views.py @@ -1,10 +1,7 @@ -import json from http import HTTPStatus -from fastapi import Request -from fastapi.params import Depends +from fastapi import Request, Depends from fastapi.templating import Jinja2Templates -from loguru import logger from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse @@ -13,7 +10,6 @@ from lnbits.decorators import check_user_exists from . import gerty_ext, gerty_renderer from .crud import get_gerty -from .views_api import api_gerty_json templates = Jinja2Templates(directory="templates") diff --git a/lnbits/extensions/gerty/views_api.py b/lnbits/extensions/gerty/views_api.py index 7272fb7d..81c84c1d 100644 --- a/lnbits/extensions/gerty/views_api.py +++ b/lnbits/extensions/gerty/views_api.py @@ -1,24 +1,12 @@ import json -import math -import os -import random -import time -from datetime import datetime from http import HTTPStatus -import httpx -from fastapi import Query -from fastapi.params import Depends -from fastapi.templating import Jinja2Templates -from lnurl import decode as decode_lnurl +from fastapi import Query, Depends from loguru import logger from starlette.exceptions import HTTPException -from lnbits.core.crud import get_user, get_wallet_for_key -from lnbits.core.services import create_invoice -from lnbits.core.views.api import api_payment, api_wallet +from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key -from lnbits.utils.exchange_rates import satoshis_amount_as_fiat from . import gerty_ext from .crud import ( @@ -29,8 +17,9 @@ from .crud import ( get_mempool_info, update_gerty, ) + from .helpers import * -from .models import Gerty, MempoolEndpoint +from .models import Gerty @gerty_ext.get("/api/v1/gerty", status_code=HTTPStatus.OK) @@ -39,7 +28,8 @@ async def api_gertys( ): wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] return [gerty.dict() for gerty in await get_gertys(wallet_ids)] @@ -51,7 +41,6 @@ async def api_link_create_or_update( wallet: WalletTypeInfo = Depends(get_key_type), gerty_id: str = Query(None), ): - logger.debug(data) if gerty_id: gerty = await get_gerty(gerty_id) if not gerty: @@ -91,13 +80,13 @@ async def api_gerty_delete( raise HTTPException(status_code=HTTPStatus.NO_CONTENT) -@gerty_ext.get("/api/v1/gerty/satoshiquote", status_code=HTTPStatus.OK) -async def api_gerty_satoshi(): - return await get_satoshi +# @gerty_ext.get("/api/v1/gerty/satoshiquote", status_code=HTTPStatus.OK) +# async def api_gerty_satoshi(): +# return await get_satoshi @gerty_ext.get("/api/v1/gerty/pages/{gerty_id}/{p}") -async def api_gerty_json(gerty_id: str, p: int = None): # page number +async def api_gerty_json(gerty_id: str, p: int = 0): # page number gerty = await get_gerty(gerty_id) if not gerty: @@ -117,7 +106,7 @@ async def api_gerty_json(gerty_id: str, p: int = None): # page number enabled_screen_count += 1 enabled_screens.append(screen_slug) - logger.debug("Screeens " + str(enabled_screens)) + logger.debug("Screens " + str(enabled_screens)) data = await get_screen_data(p, enabled_screens, gerty) next_screen_number = 0 if ((p + 1) >= enabled_screen_count) else p + 1 diff --git a/pyproject.toml b/pyproject.toml index 573eef1b..fa81bcff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,6 @@ exclude = """(?x)( | ^lnbits/extensions/boltz. | ^lnbits/extensions/boltcards. | ^lnbits/extensions/events. - | ^lnbits/extensions/gerty. | ^lnbits/extensions/hivemind. | ^lnbits/extensions/invoices. | ^lnbits/extensions/livestream. From f3e0bd49074e94a192db8e29d441ec6d606d5022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 30 Dec 2022 09:47:49 +0100 Subject: [PATCH 02/27] formatting --- lnbits/extensions/gerty/helpers.py | 6 +----- lnbits/extensions/gerty/views.py | 2 +- lnbits/extensions/gerty/views_api.py | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 5897423e..8c2cc9ea 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -390,9 +390,7 @@ async def api_get_mining_stat(stat_slug: str, gerty): r = await get_mempool_info("hashrate_1m", gerty) data = r stat["current"] = data["currentDifficulty"] - stat["previous"] = data["difficulty"][len(data["difficulty"]) - 2][ - "difficulty" - ] + stat["previous"] = data["difficulty"][len(data["difficulty"]) - 2]["difficulty"] return stat @@ -946,5 +944,3 @@ async def get_mempool_stat(stat_slug: str, gerty): ) ) return text - - diff --git a/lnbits/extensions/gerty/views.py b/lnbits/extensions/gerty/views.py index 238e3721..33e95d3e 100644 --- a/lnbits/extensions/gerty/views.py +++ b/lnbits/extensions/gerty/views.py @@ -1,6 +1,6 @@ from http import HTTPStatus -from fastapi import Request, Depends +from fastapi import Depends, Request from fastapi.templating import Jinja2Templates from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse diff --git a/lnbits/extensions/gerty/views_api.py b/lnbits/extensions/gerty/views_api.py index 81c84c1d..62e92b75 100644 --- a/lnbits/extensions/gerty/views_api.py +++ b/lnbits/extensions/gerty/views_api.py @@ -1,7 +1,7 @@ import json from http import HTTPStatus -from fastapi import Query, Depends +from fastapi import Depends, Query from loguru import logger from starlette.exceptions import HTTPException @@ -17,7 +17,6 @@ from .crud import ( get_mempool_info, update_gerty, ) - from .helpers import * from .models import Gerty From 6d29cc85b08e3a21b025d361d490a0748fc9c17f Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 3 Jan 2023 11:35:10 +0100 Subject: [PATCH 03/27] use proper typing --- lnbits/extensions/gerty/crud.py | 6 ++---- lnbits/extensions/gerty/views_api.py | 3 +++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/gerty/crud.py b/lnbits/extensions/gerty/crud.py index 3012eeae..cfa8de11 100644 --- a/lnbits/extensions/gerty/crud.py +++ b/lnbits/extensions/gerty/crud.py @@ -50,15 +50,13 @@ async def create_gerty(wallet_id: str, data: Gerty) -> Gerty: return gerty -async def update_gerty(gerty_id: str, **kwargs) -> Gerty: +async def update_gerty(gerty_id: str, **kwargs) -> Optional[Gerty]: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) await db.execute( f"UPDATE gerty.gertys SET {q} WHERE id = ?", (*kwargs.values(), gerty_id) ) - gerty = await get_gerty(gerty_id) - assert gerty - return gerty + return await get_gerty(gerty_id) async def get_gerty(gerty_id: str) -> Optional[Gerty]: diff --git a/lnbits/extensions/gerty/views_api.py b/lnbits/extensions/gerty/views_api.py index 62e92b75..b0d4fb9e 100644 --- a/lnbits/extensions/gerty/views_api.py +++ b/lnbits/extensions/gerty/views_api.py @@ -55,6 +55,9 @@ async def api_link_create_or_update( data.wallet = wallet.wallet.id gerty = await update_gerty(gerty_id, **data.dict()) + assert gerty, HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Gerty does not exist" + ) else: gerty = await create_gerty(wallet_id=wallet.wallet.id, data=data) From 24e72d1e48be577815878fce08e62e1bf83a90ab Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 3 Jan 2023 11:37:43 +0100 Subject: [PATCH 04/27] fix gerty nitpicks --- lnbits/extensions/gerty/helpers.py | 2 +- lnbits/extensions/gerty/views_api.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 8c2cc9ea..cda84dab 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -406,7 +406,7 @@ async def get_satoshi(): quote = satoshiQuotes[random.randint(0, len(satoshiQuotes) - 1)] # logger.debug(quote.text) if len(quote["text"]) > maxQuoteLength: - logger.debug("Quote is too long, getting another") + logger.trace("Quote is too long, getting another") return await get_satoshi() else: return quote diff --git a/lnbits/extensions/gerty/views_api.py b/lnbits/extensions/gerty/views_api.py index b0d4fb9e..f71bec42 100644 --- a/lnbits/extensions/gerty/views_api.py +++ b/lnbits/extensions/gerty/views_api.py @@ -82,9 +82,9 @@ async def api_gerty_delete( raise HTTPException(status_code=HTTPStatus.NO_CONTENT) -# @gerty_ext.get("/api/v1/gerty/satoshiquote", status_code=HTTPStatus.OK) -# async def api_gerty_satoshi(): -# return await get_satoshi +@gerty_ext.get("/api/v1/gerty/satoshiquote", status_code=HTTPStatus.OK) +async def api_gerty_satoshi(): + return await get_satoshi @gerty_ext.get("/api/v1/gerty/pages/{gerty_id}/{p}") From 19ef282581c61abcbf751cffb26f18bc5beb97b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 11:17:30 +0100 Subject: [PATCH 05/27] adding back removed functions --- lnbits/extensions/gerty/helpers.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 2e936399..036aa011 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -73,6 +73,34 @@ def get_text_item_dict( return text +def get_date_suffix(dayNumber): + if 4 <= dayNumber <= 20 or 24 <= dayNumber <= 30: + return "th" + else: + return ["st", "nd", "rd"][dayNumber % 10 - 1] + + +def get_time_remaining(seconds, granularity=2): + intervals = ( + # ('weeks', 604800), # 60 * 60 * 24 * 7 + ("days", 86400), # 60 * 60 * 24 + ("hours", 3600), # 60 * 60 + ("minutes", 60), + ("seconds", 1), + ) + + result = [] + + for name, count in intervals: + value = seconds // count + if value: + seconds -= value * count + if value == 1: + name = name.rstrip("s") + result.append("{} {}".format(round(value), name)) + return ", ".join(result[:granularity]) + + # format a number for nice display output def format_number(number, precision=None): return "{:,}".format(round(number, precision)) From 908369efffdda8eb331ab597c0423a3fb69dab97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 11:32:33 +0100 Subject: [PATCH 06/27] fix tpos mypy issue --- lnbits/extensions/tpos/tasks.py | 18 +++++++++++++----- lnbits/extensions/tpos/views.py | 3 +-- lnbits/extensions/tpos/views_api.py | 17 +++++++++-------- pyproject.toml | 1 - 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py index 6eb1d5d1..ea414072 100644 --- a/lnbits/extensions/tpos/tasks.py +++ b/lnbits/extensions/tpos/tasks.py @@ -20,10 +20,9 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") != "tpos": + if not payment.extra or payment.extra.get("tag") != "tpos": return - tpos = await get_tpos(payment.extra.get("tposId")) tipAmount = payment.extra.get("tipAmount") strippedPayment = { @@ -34,14 +33,23 @@ async def on_invoice_paid(payment: Payment) -> None: "bolt11": payment.bolt11, } - await websocketUpdater(payment.extra.get("tposId"), str(strippedPayment)) + tpos_id = payment.extra.get("tposId") + assert tpos_id - if tipAmount is None: + tpos = await get_tpos(tpos_id) + assert tpos + + await websocketUpdater(tpos_id, str(strippedPayment)) + + if not tipAmount: # no tip amount return + wallet_id = tpos.tip_wallet + assert wallet_id + payment_hash, payment_request = await create_invoice( - wallet_id=tpos.tip_wallet, + wallet_id=wallet_id, amount=int(tipAmount), # sats internal=True, memo=f"tpos tip", diff --git a/lnbits/extensions/tpos/views.py b/lnbits/extensions/tpos/views.py index dac129a9..fee5914f 100644 --- a/lnbits/extensions/tpos/views.py +++ b/lnbits/extensions/tpos/views.py @@ -1,7 +1,6 @@ from http import HTTPStatus -from fastapi import Request -from fastapi.params import Depends +from fastapi import Depends, Request from fastapi.templating import Jinja2Templates from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index 3a51238a..05537f84 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -1,8 +1,7 @@ from http import HTTPStatus import httpx -from fastapi import Query -from fastapi.params import Depends +from fastapi import Depends, Query from lnurl import decode as decode_lnurl from loguru import logger from starlette.exceptions import HTTPException @@ -25,7 +24,8 @@ async def api_tposs( ): wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] return [tpos.dict() for tpos in await get_tposs(wallet_ids)] @@ -58,8 +58,9 @@ async def api_tpos_delete( @tpos_ext.post("/api/v1/tposs/{tpos_id}/invoices", status_code=HTTPStatus.CREATED) async def api_tpos_create_invoice( - amount: int = Query(..., ge=1), tipAmount: int = None, tpos_id: str = None -): + tpos_id: str, amount: int = Query(..., ge=1), tipAmount: int = 0 +) -> dict: + tpos = await get_tpos(tpos_id) if not tpos: @@ -67,7 +68,7 @@ async def api_tpos_create_invoice( status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." ) - if tipAmount: + if tipAmount > 0: amount += tipAmount try: @@ -84,7 +85,7 @@ async def api_tpos_create_invoice( @tpos_ext.get("/api/v1/tposs/{tpos_id}/invoices") -async def api_tpos_get_latest_invoices(tpos_id: str = None): +async def api_tpos_get_latest_invoices(tpos_id: str): try: payments = [ Payment.from_row(row) @@ -111,7 +112,7 @@ async def api_tpos_get_latest_invoices(tpos_id: str = None): "/api/v1/tposs/{tpos_id}/invoices/{payment_request}/pay", status_code=HTTPStatus.OK ) async def api_tpos_pay_invoice( - lnurl_data: PayLnurlWData, payment_request: str = None, tpos_id: str = None + lnurl_data: PayLnurlWData, payment_request: str, tpos_id: str ): tpos = await get_tpos(tpos_id) diff --git a/pyproject.toml b/pyproject.toml index 186e2123..81a36ee5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,7 +102,6 @@ exclude = """(?x)( | ^lnbits/extensions/offlineshop. | ^lnbits/extensions/satspay. | ^lnbits/extensions/streamalerts. - | ^lnbits/extensions/tpos. | ^lnbits/extensions/watchonly. | ^lnbits/extensions/withdraw. | ^lnbits/wallets/lnd_grpc_files. From 239d35a60a730eb828e33ef6e1df005afb2609b4 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 11:49:50 +0000 Subject: [PATCH 07/27] trying to fix errors in software gerty --- .../gerty/templates/gerty/gerty.html | 76 +++++++++++-------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/lnbits/extensions/gerty/templates/gerty/gerty.html b/lnbits/extensions/gerty/templates/gerty/gerty.html index d45484a4..b2fb86b6 100644 --- a/lnbits/extensions/gerty/templates/gerty/gerty.html +++ b/lnbits/extensions/gerty/templates/gerty/gerty.html @@ -3,39 +3,39 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
- {{fun_exchange_market_rate["amount"]}} + {{elements.fun_exchange_market_rate["amount"]}} {{fun_exchange_market_rate["unit"].split(" ")[1]}}{{elements.fun_exchange_market_rate["unit"].split(" ")[1]}}
-

"{{fun_satoshi_quotes["quote"]}}"

- ~ Satoshi {{fun_satoshi_quotes["date"]}} +

"{{elements.fun_satoshi_quotes["quote"]}}"

+ ~ Satoshi {{elements.fun_satoshi_quotes["date"]}}
-
+
@@ -61,40 +61,40 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
Onchain
-

+

{{item[0].value}}: {{item[1].value}}

- +
Mining
-

+

{{item[0].value}}: {{item[1].value}}

- +
Lightning (Last 7 days)
-

+

{{item[0].value}}: {{item[1].value}}

- +
Servers to check
-
+
@@ -150,10 +150,15 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %} mixins: [windowMixin], data: function () { return { - lnbits_wallets_balance: {}, - dashboard_onchain: {}, - fun_satoshi_quotes: {}, - fun_exchange_market_rate: {}, + elements:{ + lnbits_wallets_balance: [], + dashboard_onchain: [], + fun_satoshi_quotes: [], + fun_exchange_market_rate: [], + lightning_dashboard: [], + url_checker: [], + dashboard_mining: [], + }, gerty: [], gerty_id: `{{gerty}}`, gertyname: '', @@ -177,16 +182,20 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %} 'GET', `/gerty/api/v1/gerty/pages/${this.gerty_id}/${i}` ) - this.gerty[i] = data + console.log(data.screen.slug) + if(data.screen.slug){ + this.gerty[i] = data + } + } catch (error) { LNbits.utils.notifyApiError(error) } } - console.log(this.gerty) + console.log(this.gerty[0].screen.group) for (let i = 0; i < this.gerty.length; i++) { if (this.gerty[i].screen.group == 'lnbits_wallets_balance') { for (let q = 0; q < this.gerty[i].screen.areas.length; q++) { - this.lnbits_wallets_balance[q] = { + this.elements.lnbits_wallets_balance[q] = { name: this.gerty[i].screen.areas[q][0].value, amount: this.gerty[i].screen.areas[q][1].value, color1: this.walletColors[q].first, @@ -196,35 +205,36 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %} } } if (this.gerty[i].screen.group == 'url_checker') { - this.url_checker = this.gerty[i].screen.areas + this.elements.url_checker = this.gerty[i].screen.areas this.gertyname = this.gerty[i].settings.name } if (this.gerty[i].screen.group == 'dashboard_onchain') { - this.dashboard_onchain = this.gerty[i].screen.areas + this.elements.dashboard_onchain = this.gerty[i].screen.areas this.gertyname = this.gerty[i].settings.name } if (this.gerty[i].screen.group == 'dashboard_mining') { - this.dashboard_mining = this.gerty[i].screen.areas + this.elements.dashboard_mining = this.gerty[i].screen.areas this.gertyname = this.gerty[i].settings.name } if (this.gerty[i].screen.group == 'lightning_dashboard') { - this.lightning_dashboard = this.gerty[i].screen.areas + this.elements.lightning_dashboard = this.gerty[i].screen.areas this.gertyname = this.gerty[i].settings.name } if (this.gerty[i].screen.group == 'fun_satoshi_quotes') { - this.fun_satoshi_quotes['quote'] = this.gerty[ + console.log(this.gerty[i]); + this.elements.fun_satoshi_quotes['quote'] = this.gerty[ i ].screen.areas[0][0].value - this.fun_satoshi_quotes['date'] = this.gerty[ + this.elements.fun_satoshi_quotes['date'] = this.gerty[ i ].screen.areas[0][1].value this.gertyname = this.gerty[i].settings.name } if (this.gerty[i].screen.group == 'fun_exchange_market_rate') { - this.fun_exchange_market_rate['unit'] = this.gerty[ + this.elements.fun_exchange_market_rate['unit'] = this.gerty[ i ].screen.areas[0][0].value - this.fun_exchange_market_rate['amount'] = this.gerty[ + this.elements.fun_exchange_market_rate['amount'] = this.gerty[ i ].screen.areas[0][1].value this.gertyname = this.gerty[i].settings.name From a521b950706d0795885da436a168393958b8274f Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Wed, 4 Jan 2023 12:01:27 +0000 Subject: [PATCH 08/27] Revert "remove duplicit functions " --- lnbits/extensions/gerty/helpers.py | 28 ++++++++++++++++++ lnbits/extensions/satspay/crud.py | 47 ++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 65c69073..24b22b5d 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -301,6 +301,34 @@ def gerty_should_sleep(utc_offset: int = 0): return False +def get_date_suffix(dayNumber): + if 4 <= dayNumber <= 20 or 24 <= dayNumber <= 30: + return "th" + else: + return ["st", "nd", "rd"][dayNumber % 10 - 1] + + +def get_time_remaining(seconds, granularity=2): + intervals = ( + # ('weeks', 604800), # 60 * 60 * 24 * 7 + ("days", 86400), # 60 * 60 * 24 + ("hours", 3600), # 60 * 60 + ("minutes", 60), + ("seconds", 1), + ) + + result = [] + + for name, count in intervals: + value = seconds // count + if value: + seconds -= value * count + if value == 1: + name = name.rstrip("s") + result.append("{} {}".format(round(value), name)) + return ", ".join(result[:granularity]) + + async def get_mining_stat(stat_slug: str, gerty): text = [] if stat_slug == "mining_current_hash_rate": diff --git a/lnbits/extensions/satspay/crud.py b/lnbits/extensions/satspay/crud.py index 78433838..7cbcec5f 100644 --- a/lnbits/extensions/satspay/crud.py +++ b/lnbits/extensions/satspay/crud.py @@ -131,6 +131,53 @@ async def check_address_balance(charge_id: str) -> Optional[Charges]: ################## SETTINGS ################### +async def save_theme(data: SatsPayThemes, css_id: str = None): + # insert or update + if css_id: + await db.execute( + """ + UPDATE satspay.themes SET custom_css = ?, title = ? WHERE css_id = ? + """, + (data.custom_css, data.title, css_id), + ) + else: + css_id = urlsafe_short_hash() + await db.execute( + """ + INSERT INTO satspay.themes ( + css_id, + title, + user, + custom_css + ) + VALUES (?, ?, ?, ?) + """, + ( + css_id, + data.title, + data.user, + data.custom_css, + ), + ) + return await get_theme(css_id) + + +async def get_theme(css_id: str) -> SatsPayThemes: + row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,)) + return SatsPayThemes.from_row(row) if row else None + + +async def get_themes(user_id: str) -> List[SatsPayThemes]: + rows = await db.fetchall( + """SELECT * FROM satspay.themes WHERE "user" = ? ORDER BY "timestamp" DESC """, + (user_id,), + ) + return await get_config(row.user) + + +################## SETTINGS ################### + + async def save_theme(data: SatsPayThemes, css_id: str = None): # insert or update if css_id: From 487646e2e3d7d5eb3e40804f6d0e9a9538260266 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 12:19:16 +0000 Subject: [PATCH 09/27] timestamp being saved as int --- lnbits/extensions/gerty/crud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/gerty/crud.py b/lnbits/extensions/gerty/crud.py index 1164b6ee..2fc0a7c1 100644 --- a/lnbits/extensions/gerty/crud.py +++ b/lnbits/extensions/gerty/crud.py @@ -116,7 +116,7 @@ async def get_mempool_info(endPoint: str, gerty) -> Optional[Mempool]: mempool_id, json.dumps(response.json()), endPoint, - int(time.time()), + time.time(), gerty.mempool_endpoint, ), ) @@ -128,7 +128,7 @@ async def get_mempool_info(endPoint: str, gerty) -> Optional[Mempool]: "UPDATE gerty.mempool SET data = ?, time = ? WHERE endpoint = ? AND mempool_endpoint = ?", ( json.dumps(response.json()), - int(time.time()), + time.time(), endPoint, gerty.mempool_endpoint, ), From 9d2ef274b9b3f6c2378ca646b08951a1ca8e0e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 13:24:45 +0100 Subject: [PATCH 10/27] fix lnurlp and lnurlpayout mypy issue --- lnbits/extensions/lnurlp/tasks.py | 28 +++---- lnbits/extensions/lnurlp/views.py | 3 +- lnbits/extensions/lnurlp/views_api.py | 8 +- lnbits/extensions/lnurlpayout/crud.py | 2 +- lnbits/extensions/lnurlpayout/tasks.py | 12 +-- lnbits/extensions/lnurlpayout/views.py | 5 +- lnbits/extensions/lnurlpayout/views_api.py | 86 +++++++++------------- pyproject.toml | 1 - 8 files changed, 60 insertions(+), 85 deletions(-) diff --git a/lnbits/extensions/lnurlp/tasks.py b/lnbits/extensions/lnurlp/tasks.py index b8da5e43..38485f74 100644 --- a/lnbits/extensions/lnurlp/tasks.py +++ b/lnbits/extensions/lnurlp/tasks.py @@ -4,7 +4,6 @@ import json import httpx from loguru import logger -from lnbits.core import db as core_db from lnbits.core.crud import update_payment_extra from lnbits.core.models import Payment from lnbits.helpers import get_current_extension_name @@ -22,9 +21,8 @@ async def wait_for_paid_invoices(): await on_invoice_paid(payment) -async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") != "lnurlp": - # not an lnurlp invoice +async def on_invoice_paid(payment: Payment): + if not payment.extra or payment.extra.get("tag") != "lnurlp": return if payment.extra.get("wh_status"): @@ -35,22 +33,24 @@ async def on_invoice_paid(payment: Payment) -> None: if pay_link and pay_link.webhook_url: async with httpx.AsyncClient() as client: try: - kwargs = { - "json": { + r: httpx.Response = await client.post( + pay_link.webhook_url, + json={ "payment_hash": payment.payment_hash, "payment_request": payment.bolt11, "amount": payment.amount, "comment": payment.extra.get("comment"), "lnurlp": pay_link.id, + "lnurlp": pay_link.id, + "body": json.loads(pay_link.webhook_body) + if pay_link.webhook_body + else "", }, - "timeout": 40, - } - if pay_link.webhook_body: - kwargs["json"]["body"] = json.loads(pay_link.webhook_body) - if pay_link.webhook_headers: - kwargs["headers"] = json.loads(pay_link.webhook_headers) - - r: httpx.Response = await client.post(pay_link.webhook_url, **kwargs) + headers=json.loads(pay_link.webhook_headers) + if pay_link.webhook_headers + else None, + timeout=40, + ) await mark_webhook_sent( payment.payment_hash, r.status_code, diff --git a/lnbits/extensions/lnurlp/views.py b/lnbits/extensions/lnurlp/views.py index 4e9f487c..9bc78056 100644 --- a/lnbits/extensions/lnurlp/views.py +++ b/lnbits/extensions/lnurlp/views.py @@ -1,7 +1,6 @@ from http import HTTPStatus -from fastapi import Request -from fastapi.params import Depends +from fastapi import Depends, Request from fastapi.templating import Jinja2Templates from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse diff --git a/lnbits/extensions/lnurlp/views_api.py b/lnbits/extensions/lnurlp/views_api.py index d5966bf6..0fa739b0 100644 --- a/lnbits/extensions/lnurlp/views_api.py +++ b/lnbits/extensions/lnurlp/views_api.py @@ -1,9 +1,7 @@ import json from http import HTTPStatus -from fastapi import Request -from fastapi.param_functions import Query -from fastapi.params import Depends +from fastapi import Depends, Query, Request from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore from starlette.exceptions import HTTPException @@ -36,7 +34,8 @@ async def api_links( wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] try: return [ @@ -137,6 +136,7 @@ async def api_link_create_or_update( link = await update_pay_link(**data.dict(), link_id=link_id) else: link = await create_pay_link(data, wallet_id=wallet.wallet.id) + assert link return {**link.dict(), "lnurl": link.lnurl(request)} diff --git a/lnbits/extensions/lnurlpayout/crud.py b/lnbits/extensions/lnurlpayout/crud.py index 0f9f98ac..ccbca120 100644 --- a/lnbits/extensions/lnurlpayout/crud.py +++ b/lnbits/extensions/lnurlpayout/crud.py @@ -53,7 +53,7 @@ async def get_lnurlpayouts(wallet_ids: Union[str, List[str]]) -> List[lnurlpayou f"SELECT * FROM lnurlpayout.lnurlpayouts WHERE wallet IN ({q})", (*wallet_ids,) ) - return [lnurlpayout(**row) if row else None for row in rows] + return [lnurlpayout(**row) for row in rows] async def delete_lnurlpayout(lnurlpayout_id: str) -> None: diff --git a/lnbits/extensions/lnurlpayout/tasks.py b/lnbits/extensions/lnurlpayout/tasks.py index 71f299be..7de26d15 100644 --- a/lnbits/extensions/lnurlpayout/tasks.py +++ b/lnbits/extensions/lnurlpayout/tasks.py @@ -2,14 +2,13 @@ import asyncio from http import HTTPStatus import httpx +from lnurl import decode as lnurl_decode from loguru import logger from starlette.exceptions import HTTPException -from lnbits.core import db as core_db from lnbits.core.crud import get_wallet from lnbits.core.models import Payment from lnbits.core.services import pay_invoice -from lnbits.core.views.api import api_payments_decode from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener @@ -35,6 +34,7 @@ async def on_invoice_paid(payment: Payment) -> None: # Check the wallet balance is more than the threshold wallet = await get_wallet(lnurlpayout_link.wallet) + assert wallet threshold = lnurlpayout_link.threshold + (lnurlpayout_link.threshold * 0.02) if wallet.balance < threshold: @@ -42,14 +42,10 @@ async def on_invoice_paid(payment: Payment) -> None: # Get the invoice from the LNURL to pay async with httpx.AsyncClient() as client: try: - url = await api_payments_decode({"data": lnurlpayout_link.lnurlpay}) - if str(url["domain"])[0:4] != "http": - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="LNURL broken" - ) + url = lnurl_decode(lnurlpayout_link.lnurlpay) try: - r = await client.get(str(url["domain"]), timeout=40) + r = await client.get(str(url), timeout=40) res = r.json() try: r = await client.get( diff --git a/lnbits/extensions/lnurlpayout/views.py b/lnbits/extensions/lnurlpayout/views.py index 454a3332..c3c00c5b 100644 --- a/lnbits/extensions/lnurlpayout/views.py +++ b/lnbits/extensions/lnurlpayout/views.py @@ -1,16 +1,13 @@ from http import HTTPStatus -from fastapi import Request -from fastapi.params import Depends +from fastapi import Depends, Request from fastapi.templating import Jinja2Templates -from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse from lnbits.core.models import User from lnbits.decorators import check_user_exists from . import lnurlpayout_ext, lnurlpayout_renderer -from .crud import get_lnurlpayout templates = Jinja2Templates(directory="templates") diff --git a/lnbits/extensions/lnurlpayout/views_api.py b/lnbits/extensions/lnurlpayout/views_api.py index 324eb5dd..02feba15 100644 --- a/lnbits/extensions/lnurlpayout/views_api.py +++ b/lnbits/extensions/lnurlpayout/views_api.py @@ -1,13 +1,10 @@ from http import HTTPStatus -from fastapi import Query -from fastapi.params import Depends +from fastapi import Depends, Query +from lnurl import decode as lnurl_decode from starlette.exceptions import HTTPException -from lnbits.core.crud import get_payments, get_user -from lnbits.core.models import Payment -from lnbits.core.services import create_invoice -from lnbits.core.views.api import api_payment, api_payments_decode +from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import lnurlpayout_ext @@ -18,8 +15,9 @@ from .crud import ( get_lnurlpayout_from_wallet, get_lnurlpayouts, ) -from .models import CreateLnurlPayoutData, lnurlpayout -from .tasks import on_invoice_paid +from .models import CreateLnurlPayoutData + +# from .tasks import on_invoice_paid @lnurlpayout_ext.get("/api/v1/lnurlpayouts", status_code=HTTPStatus.OK) @@ -28,7 +26,8 @@ async def api_lnurlpayouts( ): wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] return [lnurlpayout.dict() for lnurlpayout in await get_lnurlpayouts(wallet_ids)] @@ -42,24 +41,16 @@ async def api_lnurlpayout_create( status_code=HTTPStatus.FORBIDDEN, detail="Wallet already has lnurlpayout set", ) - return - url = await api_payments_decode({"data": data.lnurlpay}) - if "domain" not in url: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="LNURL could not be decoded" - ) - return - if str(url["domain"])[0:4] != "http": - raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not valid LNURL") - return + _ = lnurl_decode(data.lnurlpay) lnurlpayout = await create_lnurlpayout( wallet_id=wallet.wallet.id, admin_key=wallet.wallet.adminkey, data=data ) + if not lnurlpayout: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Failed to save LNURLPayout" ) - return + return lnurlpayout.dict() @@ -83,36 +74,29 @@ async def api_lnurlpayout_delete( return "", HTTPStatus.NO_CONTENT -@lnurlpayout_ext.get("/api/v1/lnurlpayouts/{lnurlpayout_id}", status_code=HTTPStatus.OK) -async def api_lnurlpayout_check( - lnurlpayout_id: str, wallet: WalletTypeInfo = Depends(get_key_type) -): - lnurlpayout = await get_lnurlpayout(lnurlpayout_id) - ## THIS - mock_payment = Payment( - checking_id="mock", - pending=False, - amount=1, - fee=1, - time=0000, - bolt11="mock", - preimage="mock", - payment_hash="mock", - wallet_id=lnurlpayout.wallet, - ) - ## INSTEAD OF THIS - # payments = await get_payments( - # wallet_id=lnurlpayout.wallet, complete=True, pending=False, outgoing=True, incoming=True - # ) +# TODO: what is this?! - result = await on_invoice_paid(mock_payment) - return +# @lnurlpayout_ext.get("/api/v1/lnurlpayouts/{lnurlpayout_id}", status_code=HTTPStatus.OK) +# async def api_lnurlpayout_check( +# lnurlpayout_id: str, wallet: WalletTypeInfo = Depends(get_key_type) +# ): +# lnurlpayout = await get_lnurlpayout(lnurlpayout_id) +# ## THIS +# mock_payment = Payment( +# checking_id="mock", +# pending=False, +# amount=1, +# fee=1, +# time=0000, +# bolt11="mock", +# preimage="mock", +# payment_hash="mock", +# wallet_id=lnurlpayout.wallet, +# ) +# ## INSTEAD OF THIS +# # payments = await get_payments( +# # wallet_id=lnurlpayout.wallet, complete=True, pending=False, outgoing=True, incoming=True +# # ) - -# get payouts func -# lnurlpayouts = await get_lnurlpayouts(wallet_ids) -# for lnurlpayout in lnurlpayouts: -# payments = await get_payments( -# wallet_id=lnurlpayout.wallet, complete=True, pending=False, outgoing=True, incoming=True -# ) -# await on_invoice_paid(payments[0]) +# result = await on_invoice_paid(mock_payment) +# return diff --git a/pyproject.toml b/pyproject.toml index 186e2123..626b3dfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,6 @@ exclude = """(?x)( | ^lnbits/extensions/lnaddress. | ^lnbits/extensions/lndhub. | ^lnbits/extensions/lnurldevice. - | ^lnbits/extensions/lnurlp. | ^lnbits/extensions/offlineshop. | ^lnbits/extensions/satspay. | ^lnbits/extensions/streamalerts. From bf4070f7cbaef889a16d921284275295bfb47392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 13:26:34 +0100 Subject: [PATCH 11/27] fix duplication typo --- lnbits/extensions/lnurlp/tasks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lnbits/extensions/lnurlp/tasks.py b/lnbits/extensions/lnurlp/tasks.py index 38485f74..2b574d42 100644 --- a/lnbits/extensions/lnurlp/tasks.py +++ b/lnbits/extensions/lnurlp/tasks.py @@ -41,7 +41,6 @@ async def on_invoice_paid(payment: Payment): "amount": payment.amount, "comment": payment.extra.get("comment"), "lnurlp": pay_link.id, - "lnurlp": pay_link.id, "body": json.loads(pay_link.webhook_body) if pay_link.webhook_body else "", From c835fc28f9419b1e9c176089c6c38ce00ebb87c2 Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Wed, 4 Jan 2023 12:27:18 +0000 Subject: [PATCH 12/27] Revert "Revert "remove duplicit functions "" --- lnbits/extensions/gerty/helpers.py | 28 ------------------ lnbits/extensions/satspay/crud.py | 47 ------------------------------ 2 files changed, 75 deletions(-) diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 24b22b5d..65c69073 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -301,34 +301,6 @@ def gerty_should_sleep(utc_offset: int = 0): return False -def get_date_suffix(dayNumber): - if 4 <= dayNumber <= 20 or 24 <= dayNumber <= 30: - return "th" - else: - return ["st", "nd", "rd"][dayNumber % 10 - 1] - - -def get_time_remaining(seconds, granularity=2): - intervals = ( - # ('weeks', 604800), # 60 * 60 * 24 * 7 - ("days", 86400), # 60 * 60 * 24 - ("hours", 3600), # 60 * 60 - ("minutes", 60), - ("seconds", 1), - ) - - result = [] - - for name, count in intervals: - value = seconds // count - if value: - seconds -= value * count - if value == 1: - name = name.rstrip("s") - result.append("{} {}".format(round(value), name)) - return ", ".join(result[:granularity]) - - async def get_mining_stat(stat_slug: str, gerty): text = [] if stat_slug == "mining_current_hash_rate": diff --git a/lnbits/extensions/satspay/crud.py b/lnbits/extensions/satspay/crud.py index 7cbcec5f..78433838 100644 --- a/lnbits/extensions/satspay/crud.py +++ b/lnbits/extensions/satspay/crud.py @@ -131,53 +131,6 @@ async def check_address_balance(charge_id: str) -> Optional[Charges]: ################## SETTINGS ################### -async def save_theme(data: SatsPayThemes, css_id: str = None): - # insert or update - if css_id: - await db.execute( - """ - UPDATE satspay.themes SET custom_css = ?, title = ? WHERE css_id = ? - """, - (data.custom_css, data.title, css_id), - ) - else: - css_id = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO satspay.themes ( - css_id, - title, - user, - custom_css - ) - VALUES (?, ?, ?, ?) - """, - ( - css_id, - data.title, - data.user, - data.custom_css, - ), - ) - return await get_theme(css_id) - - -async def get_theme(css_id: str) -> SatsPayThemes: - row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,)) - return SatsPayThemes.from_row(row) if row else None - - -async def get_themes(user_id: str) -> List[SatsPayThemes]: - rows = await db.fetchall( - """SELECT * FROM satspay.themes WHERE "user" = ? ORDER BY "timestamp" DESC """, - (user_id,), - ) - return await get_config(row.user) - - -################## SETTINGS ################### - - async def save_theme(data: SatsPayThemes, css_id: str = None): # insert or update if css_id: From 64370462b9747fcf5495e5d17ec087cc57625b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 13:46:33 +0100 Subject: [PATCH 13/27] remove unused lnurlpayout ext that became scrub --- lnbits/extensions/lnurlpayout/README.md | 3 - lnbits/extensions/lnurlpayout/__init__.py | 25 -- .../lnurlpayout/config.json.example | 6 - lnbits/extensions/lnurlpayout/crud.py | 62 ---- lnbits/extensions/lnurlpayout/migrations.py | 16 -- lnbits/extensions/lnurlpayout/models.py | 18 -- lnbits/extensions/lnurlpayout/tasks.py | 87 ------ .../templates/lnurlpayout/_api_docs.html | 119 -------- .../templates/lnurlpayout/index.html | 271 ------------------ lnbits/extensions/lnurlpayout/views.py | 19 -- lnbits/extensions/lnurlpayout/views_api.py | 102 ------- 11 files changed, 728 deletions(-) delete mode 100644 lnbits/extensions/lnurlpayout/README.md delete mode 100644 lnbits/extensions/lnurlpayout/__init__.py delete mode 100644 lnbits/extensions/lnurlpayout/config.json.example delete mode 100644 lnbits/extensions/lnurlpayout/crud.py delete mode 100644 lnbits/extensions/lnurlpayout/migrations.py delete mode 100644 lnbits/extensions/lnurlpayout/models.py delete mode 100644 lnbits/extensions/lnurlpayout/tasks.py delete mode 100644 lnbits/extensions/lnurlpayout/templates/lnurlpayout/_api_docs.html delete mode 100644 lnbits/extensions/lnurlpayout/templates/lnurlpayout/index.html delete mode 100644 lnbits/extensions/lnurlpayout/views.py delete mode 100644 lnbits/extensions/lnurlpayout/views_api.py diff --git a/lnbits/extensions/lnurlpayout/README.md b/lnbits/extensions/lnurlpayout/README.md deleted file mode 100644 index ddf209fe..00000000 --- a/lnbits/extensions/lnurlpayout/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# LNURLPayOut - -## Auto-dump a wallets funds to an LNURLpay diff --git a/lnbits/extensions/lnurlpayout/__init__.py b/lnbits/extensions/lnurlpayout/__init__.py deleted file mode 100644 index 9962290c..00000000 --- a/lnbits/extensions/lnurlpayout/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -import asyncio - -from fastapi import APIRouter - -from lnbits.db import Database -from lnbits.helpers import template_renderer -from lnbits.tasks import catch_everything_and_restart - -db = Database("ext_lnurlpayout") - -lnurlpayout_ext: APIRouter = APIRouter(prefix="/lnurlpayout", tags=["lnurlpayout"]) - - -def lnurlpayout_renderer(): - return template_renderer(["lnbits/extensions/lnurlpayout/templates"]) - - -from .tasks import wait_for_paid_invoices -from .views import * # noqa -from .views_api import * # noqa - - -def lnurlpayout_start(): - loop = asyncio.get_event_loop() - loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/lnurlpayout/config.json.example b/lnbits/extensions/lnurlpayout/config.json.example deleted file mode 100644 index b4160d7b..00000000 --- a/lnbits/extensions/lnurlpayout/config.json.example +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "LNURLPayout", - "short_description": "Autodump wallet funds to LNURLpay", - "icon": "exit_to_app", - "contributors": ["arcbtc","talvasconcelos"] -} diff --git a/lnbits/extensions/lnurlpayout/crud.py b/lnbits/extensions/lnurlpayout/crud.py deleted file mode 100644 index ccbca120..00000000 --- a/lnbits/extensions/lnurlpayout/crud.py +++ /dev/null @@ -1,62 +0,0 @@ -from typing import List, Optional, Union - -from lnbits.helpers import urlsafe_short_hash - -from . import db -from .models import CreateLnurlPayoutData, lnurlpayout - - -async def create_lnurlpayout( - wallet_id: str, admin_key: str, data: CreateLnurlPayoutData -) -> lnurlpayout: - lnurlpayout_id = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO lnurlpayout.lnurlpayouts (id, title, wallet, admin_key, lnurlpay, threshold) - VALUES (?, ?, ?, ?, ?, ?) - """, - ( - lnurlpayout_id, - data.title, - wallet_id, - admin_key, - data.lnurlpay, - data.threshold, - ), - ) - - lnurlpayout = await get_lnurlpayout(lnurlpayout_id) - assert lnurlpayout, "Newly created lnurlpayout couldn't be retrieved" - return lnurlpayout - - -async def get_lnurlpayout(lnurlpayout_id: str) -> Optional[lnurlpayout]: - row = await db.fetchone( - "SELECT * FROM lnurlpayout.lnurlpayouts WHERE id = ?", (lnurlpayout_id,) - ) - return lnurlpayout(**row) if row else None - - -async def get_lnurlpayout_from_wallet(wallet_id: str) -> Optional[lnurlpayout]: - row = await db.fetchone( - "SELECT * FROM lnurlpayout.lnurlpayouts WHERE wallet = ?", (wallet_id,) - ) - return lnurlpayout(**row) if row else None - - -async def get_lnurlpayouts(wallet_ids: Union[str, List[str]]) -> List[lnurlpayout]: - if isinstance(wallet_ids, str): - wallet_ids = [wallet_ids] - - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f"SELECT * FROM lnurlpayout.lnurlpayouts WHERE wallet IN ({q})", (*wallet_ids,) - ) - - return [lnurlpayout(**row) for row in rows] - - -async def delete_lnurlpayout(lnurlpayout_id: str) -> None: - await db.execute( - "DELETE FROM lnurlpayout.lnurlpayouts WHERE id = ?", (lnurlpayout_id,) - ) diff --git a/lnbits/extensions/lnurlpayout/migrations.py b/lnbits/extensions/lnurlpayout/migrations.py deleted file mode 100644 index 7a45e495..00000000 --- a/lnbits/extensions/lnurlpayout/migrations.py +++ /dev/null @@ -1,16 +0,0 @@ -async def m001_initial(db): - """ - Initial lnurlpayouts table. - """ - await db.execute( - f""" - CREATE TABLE lnurlpayout.lnurlpayouts ( - id TEXT PRIMARY KEY, - title TEXT NOT NULL, - wallet TEXT NOT NULL, - admin_key TEXT NOT NULL, - lnurlpay TEXT NOT NULL, - threshold {db.big_int} NOT NULL - ); - """ - ) diff --git a/lnbits/extensions/lnurlpayout/models.py b/lnbits/extensions/lnurlpayout/models.py deleted file mode 100644 index fc8be575..00000000 --- a/lnbits/extensions/lnurlpayout/models.py +++ /dev/null @@ -1,18 +0,0 @@ -from sqlite3 import Row - -from pydantic import BaseModel - - -class CreateLnurlPayoutData(BaseModel): - title: str - lnurlpay: str - threshold: int - - -class lnurlpayout(BaseModel): - id: str - title: str - wallet: str - admin_key: str - lnurlpay: str - threshold: int diff --git a/lnbits/extensions/lnurlpayout/tasks.py b/lnbits/extensions/lnurlpayout/tasks.py deleted file mode 100644 index 7de26d15..00000000 --- a/lnbits/extensions/lnurlpayout/tasks.py +++ /dev/null @@ -1,87 +0,0 @@ -import asyncio -from http import HTTPStatus - -import httpx -from lnurl import decode as lnurl_decode -from loguru import logger -from starlette.exceptions import HTTPException - -from lnbits.core.crud import get_wallet -from lnbits.core.models import Payment -from lnbits.core.services import pay_invoice -from lnbits.helpers import get_current_extension_name -from lnbits.tasks import register_invoice_listener - -from .crud import get_lnurlpayout_from_wallet - - -async def wait_for_paid_invoices(): - invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue, get_current_extension_name()) - - while True: - payment = await invoice_queue.get() - await on_invoice_paid(payment) - - -async def on_invoice_paid(payment: Payment) -> None: - try: - # Check its got a payout associated with it - lnurlpayout_link = await get_lnurlpayout_from_wallet(payment.wallet_id) - logger.debug("LNURLpayout", lnurlpayout_link) - if lnurlpayout_link: - - # Check the wallet balance is more than the threshold - - wallet = await get_wallet(lnurlpayout_link.wallet) - assert wallet - threshold = lnurlpayout_link.threshold + (lnurlpayout_link.threshold * 0.02) - - if wallet.balance < threshold: - return - # Get the invoice from the LNURL to pay - async with httpx.AsyncClient() as client: - try: - url = lnurl_decode(lnurlpayout_link.lnurlpay) - - try: - r = await client.get(str(url), timeout=40) - res = r.json() - try: - r = await client.get( - res["callback"] - + "?amount=" - + str( - int((wallet.balance - wallet.balance * 0.02) * 1000) - ), - timeout=40, - ) - res = r.json() - - if hasattr(res, "status") and res["status"] == "ERROR": - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail=res["reason"], - ) - try: - await pay_invoice( - wallet_id=payment.wallet_id, - payment_request=res["pr"], - extra={"tag": "lnurlpayout"}, - ) - return - except: - pass - - except Exception as e: - print("ERROR", str(e)) - return - except (httpx.ConnectError, httpx.RequestError): - return - except Exception: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Failed to save LNURLPayout", - ) - except: - return diff --git a/lnbits/extensions/lnurlpayout/templates/lnurlpayout/_api_docs.html b/lnbits/extensions/lnurlpayout/templates/lnurlpayout/_api_docs.html deleted file mode 100644 index afe24c42..00000000 --- a/lnbits/extensions/lnurlpayout/templates/lnurlpayout/_api_docs.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - GET - /lnurlpayout/api/v1/lnurlpayouts -
Headers
- {"X-Api-Key": <invoice_key>}
-
Body (application/json)
-
- Returns 200 OK (application/json) -
- [<lnurlpayout_object>, ...] -
Curl example
- curl -X GET {{ request.base_url }}lnurlpayout/api/v1/lnurlpayouts -H - "X-Api-Key: <invoice_key>" - -
-
-
- - - - POST - /lnurlpayout/api/v1/lnurlpayouts -
Headers
- {"X-Api-Key": <invoice_key>}
-
Body (application/json)
- {"name": <string>, "currency": <string*ie USD*>} -
- Returns 201 CREATED (application/json) -
- {"currency": <string>, "id": <string>, "name": - <string>, "wallet": <string>} -
Curl example
- curl -X POST {{ request.base_url }}lnurlpayout/api/v1/lnurlpayouts -d - '{"name": <string>, "currency": <string>}' -H - "Content-type: application/json" -H "X-Api-Key: <admin_key>" - -
-
-
- - - - - DELETE - /lnurlpayout/api/v1/lnurlpayouts/<lnurlpayout_id> -
Headers
- {"X-Api-Key": <admin_key>}
-
Returns 204 NO CONTENT
- -
Curl example
- curl -X DELETE {{ request.base_url - }}lnurlpayout/api/v1/lnurlpayouts/<lnurlpayout_id> -H - "X-Api-Key: <admin_key>" - -
-
-
- - - - GET - /lnurlpayout/api/v1/lnurlpayouts/<lnurlpayout_id> -
Headers
- {"X-Api-Key": <invoice_key>}
-
Body (application/json)
-
- Returns 200 OK (application/json) -
- [<lnurlpayout_object>, ...] -
Curl example
- curl -X GET {{ request.base_url - }}lnurlpayout/api/v1/lnurlpayouts/<lnurlpayout_id> -H - "X-Api-Key: <invoice_key>" - -
-
-
-
diff --git a/lnbits/extensions/lnurlpayout/templates/lnurlpayout/index.html b/lnbits/extensions/lnurlpayout/templates/lnurlpayout/index.html deleted file mode 100644 index 98230949..00000000 --- a/lnbits/extensions/lnurlpayout/templates/lnurlpayout/index.html +++ /dev/null @@ -1,271 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} -
-
- - - New LNURLPayout - - - - - -
-
-
LNURLPayout
-
-
- Export to CSV -
-
- - {% raw %} - - - - {% endraw %} - -
-
-
- -
- - -
- {{SITE_TITLE}} LNURLPayout extension -
-
- - - - {% include "lnurlpayout/_api_docs.html" %} - - - -
-
- - - - - - - - -
- Create LNURLPayout - Cancel -
-
-
-
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }} - -{% endblock %} diff --git a/lnbits/extensions/lnurlpayout/views.py b/lnbits/extensions/lnurlpayout/views.py deleted file mode 100644 index c3c00c5b..00000000 --- a/lnbits/extensions/lnurlpayout/views.py +++ /dev/null @@ -1,19 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, Request -from fastapi.templating import Jinja2Templates -from starlette.responses import HTMLResponse - -from lnbits.core.models import User -from lnbits.decorators import check_user_exists - -from . import lnurlpayout_ext, lnurlpayout_renderer - -templates = Jinja2Templates(directory="templates") - - -@lnurlpayout_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): - return lnurlpayout_renderer().TemplateResponse( - "lnurlpayout/index.html", {"request": request, "user": user.dict()} - ) diff --git a/lnbits/extensions/lnurlpayout/views_api.py b/lnbits/extensions/lnurlpayout/views_api.py deleted file mode 100644 index 02feba15..00000000 --- a/lnbits/extensions/lnurlpayout/views_api.py +++ /dev/null @@ -1,102 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, Query -from lnurl import decode as lnurl_decode -from starlette.exceptions import HTTPException - -from lnbits.core.crud import get_user -from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key - -from . import lnurlpayout_ext -from .crud import ( - create_lnurlpayout, - delete_lnurlpayout, - get_lnurlpayout, - get_lnurlpayout_from_wallet, - get_lnurlpayouts, -) -from .models import CreateLnurlPayoutData - -# from .tasks import on_invoice_paid - - -@lnurlpayout_ext.get("/api/v1/lnurlpayouts", status_code=HTTPStatus.OK) -async def api_lnurlpayouts( - all_wallets: bool = Query(None), wallet: WalletTypeInfo = Depends(get_key_type) -): - wallet_ids = [wallet.wallet.id] - if all_wallets: - user = await get_user(wallet.wallet.user) - wallet_ids = user.wallet_ids if user else [] - - return [lnurlpayout.dict() for lnurlpayout in await get_lnurlpayouts(wallet_ids)] - - -@lnurlpayout_ext.post("/api/v1/lnurlpayouts", status_code=HTTPStatus.CREATED) -async def api_lnurlpayout_create( - data: CreateLnurlPayoutData, wallet: WalletTypeInfo = Depends(get_key_type) -): - if await get_lnurlpayout_from_wallet(wallet.wallet.id): - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Wallet already has lnurlpayout set", - ) - _ = lnurl_decode(data.lnurlpay) - lnurlpayout = await create_lnurlpayout( - wallet_id=wallet.wallet.id, admin_key=wallet.wallet.adminkey, data=data - ) - - if not lnurlpayout: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Failed to save LNURLPayout" - ) - - return lnurlpayout.dict() - - -@lnurlpayout_ext.delete("/api/v1/lnurlpayouts/{lnurlpayout_id}") -async def api_lnurlpayout_delete( - lnurlpayout_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) -): - lnurlpayout = await get_lnurlpayout(lnurlpayout_id) - - if not lnurlpayout: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="lnurlpayout does not exist." - ) - - if lnurlpayout.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not your lnurlpayout." - ) - - await delete_lnurlpayout(lnurlpayout_id) - return "", HTTPStatus.NO_CONTENT - - -# TODO: what is this?! - -# @lnurlpayout_ext.get("/api/v1/lnurlpayouts/{lnurlpayout_id}", status_code=HTTPStatus.OK) -# async def api_lnurlpayout_check( -# lnurlpayout_id: str, wallet: WalletTypeInfo = Depends(get_key_type) -# ): -# lnurlpayout = await get_lnurlpayout(lnurlpayout_id) -# ## THIS -# mock_payment = Payment( -# checking_id="mock", -# pending=False, -# amount=1, -# fee=1, -# time=0000, -# bolt11="mock", -# preimage="mock", -# payment_hash="mock", -# wallet_id=lnurlpayout.wallet, -# ) -# ## INSTEAD OF THIS -# # payments = await get_payments( -# # wallet_id=lnurlpayout.wallet, complete=True, pending=False, outgoing=True, incoming=True -# # ) - -# result = await on_invoice_paid(mock_payment) -# return From 4a2b8ab1afaee3fc05ed50d2259ee364495ba412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 13:51:18 +0100 Subject: [PATCH 14/27] add prusnak suggestion --- lnbits/extensions/tpos/tasks.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py index ea414072..f1417810 100644 --- a/lnbits/extensions/tpos/tasks.py +++ b/lnbits/extensions/tpos/tasks.py @@ -20,7 +20,9 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if not payment.extra or payment.extra.get("tag") != "tpos": + if not payment.extra: + return + if payment.extra.get("tag") != "tpos": return tipAmount = payment.extra.get("tipAmount") From 45acfb353d6cd5f2d91b053035527ff50cbbe4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 14:01:18 +0100 Subject: [PATCH 15/27] fix lndhub mypy issues --- lnbits/extensions/lndhub/views.py | 3 +-- lnbits/extensions/lndhub/views_api.py | 10 ++++------ pyproject.toml | 1 - 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lnbits/extensions/lndhub/views.py b/lnbits/extensions/lndhub/views.py index 38a33a34..b216f8b1 100644 --- a/lnbits/extensions/lndhub/views.py +++ b/lnbits/extensions/lndhub/views.py @@ -1,5 +1,4 @@ -from fastapi import Request -from fastapi.params import Depends +from fastapi import Depends, Request from lnbits.core.models import User from lnbits.decorators import check_user_exists diff --git a/lnbits/extensions/lndhub/views_api.py b/lnbits/extensions/lndhub/views_api.py index c21c0bfd..1dff5235 100644 --- a/lnbits/extensions/lndhub/views_api.py +++ b/lnbits/extensions/lndhub/views_api.py @@ -1,15 +1,13 @@ -import asyncio import time from base64 import urlsafe_b64encode from http import HTTPStatus -from fastapi.param_functions import Query -from fastapi.params import Depends +from fastapi import Depends, Query from pydantic import BaseModel from starlette.exceptions import HTTPException from lnbits import bolt11 -from lnbits.core.crud import delete_expired_invoices, get_payments +from lnbits.core.crud import get_payments from lnbits.core.services import create_invoice, pay_invoice from lnbits.decorators import WalletTypeInfo from lnbits.settings import get_wallet_class, settings @@ -73,13 +71,13 @@ async def lndhub_addinvoice( } -class Invoice(BaseModel): +class CreateInvoice(BaseModel): invoice: str = Query(...) @lndhub_ext.post("/ext/payinvoice") async def lndhub_payinvoice( - r_invoice: Invoice, wallet: WalletTypeInfo = Depends(require_admin_key) + r_invoice: CreateInvoice, wallet: WalletTypeInfo = Depends(require_admin_key) ): try: await pay_invoice( diff --git a/pyproject.toml b/pyproject.toml index 186e2123..405cf3ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,6 @@ exclude = """(?x)( | ^lnbits/extensions/invoices. | ^lnbits/extensions/livestream. | ^lnbits/extensions/lnaddress. - | ^lnbits/extensions/lndhub. | ^lnbits/extensions/lnurldevice. | ^lnbits/extensions/lnurlp. | ^lnbits/extensions/offlineshop. From 92cfcca1d9c1227e87ce7a717c96ee97ca447f7e Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 15:03:05 +0000 Subject: [PATCH 16/27] replaced with working software gerty --- .../gerty/templates/gerty/gerty.html | 483 +++++++++--------- 1 file changed, 240 insertions(+), 243 deletions(-) diff --git a/lnbits/extensions/gerty/templates/gerty/gerty.html b/lnbits/extensions/gerty/templates/gerty/gerty.html index b2fb86b6..141c3152 100644 --- a/lnbits/extensions/gerty/templates/gerty/gerty.html +++ b/lnbits/extensions/gerty/templates/gerty/gerty.html @@ -1,254 +1,251 @@ {% extends "public.html" %} {% block toolbar_title %} Gerty: {% raw %}{{ -gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %} - -
- - - {{elements.fun_exchange_market_rate["amount"]}} - {{elements.fun_exchange_market_rate["unit"].split(" ")[1]}} - - - - + + {{fun_exchange_market_rate["amount"]}} + {{fun_exchange_market_rate["unit"].split(" ")[1]}} + + + + +
+

"{{fun_satoshi_quotes["quote"]}}"

+ ~ Satoshi {{fun_satoshi_quotes["date"]}} +
+
+
+ +
+ + + {{wallet["amount"]}} + ({{wallet["name"]}}) + + +
+ +
-
-

"{{elements.fun_satoshi_quotes["quote"]}}"

- ~ Satoshi {{elements.fun_satoshi_quotes["date"]}} -
- -
- -
- - - {{wallet["amount"]}} - ({{wallet["name"]}}) - - -
- -
- - -
Onchain
-
- -

- {{item[0].value}}: {{item[1].value}} -

-
-
- - - -
Mining
-
- -

- {{item[0].value}}: {{item[1].value}} -

-
-
- - - -
Lightning (Last 7 days)
-
- -

- {{item[0].value}}: {{item[1].value}} -

-
-
- - - -
Servers to check
-
- -
-
- - - - {{item[0].value}} - - - + + +
Onchain
+
+ +

+ {{item[0].value}}: {{item[1].value}} +

+
+
+ + + +
Mining
+
+ +

+ {{item[0].value}}: {{item[1].value}} +

+
+
+ + + +
Lightning (Last 7 days)
+
+ +

+ {{item[0].value}}: {{item[1].value}} +

+
+
+ + + +
Servers to check
+
+ +
+ +
+ + {{item[1].value}} + + + {{item[1].value}} + + + {{item[1].value}} + +
-
- - {{item[1].value}} - - - {{item[1].value}} - - - {{item[1].value}} - -
-
- - -
- -{% endraw %} {% endblock %} {% block scripts %} - -{% endblock %} + }) + + {% endblock %} + \ No newline at end of file From 2b6568296053da14ebb71280bd20cd43480e249e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 16:29:47 +0100 Subject: [PATCH 17/27] inbetween withdraw commit --- lnbits/extensions/withdraw/crud.py | 22 +++- lnbits/extensions/withdraw/lnurl.py | 139 +++++++++--------------- lnbits/extensions/withdraw/models.py | 25 ++--- lnbits/extensions/withdraw/views.py | 3 +- lnbits/extensions/withdraw/views_api.py | 41 +++---- pyproject.toml | 1 - 6 files changed, 98 insertions(+), 133 deletions(-) diff --git a/lnbits/extensions/withdraw/crud.py b/lnbits/extensions/withdraw/crud.py index 83404c62..8387d264 100644 --- a/lnbits/extensions/withdraw/crud.py +++ b/lnbits/extensions/withdraw/crud.py @@ -8,9 +8,10 @@ from .models import CreateWithdrawData, HashCheck, WithdrawLink async def create_withdraw_link( - data: CreateWithdrawData, wallet_id: str, usescsv: str + data: CreateWithdrawData, wallet_id: str ) -> WithdrawLink: link_id = urlsafe_short_hash() + available_links = ",".join([str(i) for i in range(data.uses)]) await db.execute( """ INSERT INTO withdraw.withdraw_link ( @@ -45,7 +46,7 @@ async def create_withdraw_link( urlsafe_short_hash(), urlsafe_short_hash(), int(datetime.now().timestamp()) + data.wait_time, - usescsv, + available_links, data.webhook_url, data.webhook_headers, data.webhook_body, @@ -94,6 +95,14 @@ async def get_withdraw_links(wallet_ids: Union[str, List[str]]) -> List[Withdraw return [WithdrawLink(**row) for row in rows] +async def increment_withdraw_link(link: WithdrawLink) -> None: + await update_withdraw_link( + link.id, + used=link.used + 1, + open_time=link.wait_time + int(datetime.now().timestamp()), + ) + + async def update_withdraw_link(link_id: str, **kwargs) -> Optional[WithdrawLink]: if "is_unique" in kwargs: kwargs["is_unique"] = int(kwargs["is_unique"]) @@ -129,10 +138,11 @@ async def create_hash_check(the_hash: str, lnurl_id: str) -> HashCheck: (the_hash, lnurl_id), ) hashCheck = await get_hash_check(the_hash, lnurl_id) + assert hashCheck return hashCheck -async def get_hash_check(the_hash: str, lnurl_id: str) -> Optional[HashCheck]: +async def get_hash_check(the_hash: str, lnurl_id: str) -> HashCheck: rowid = await db.fetchone( "SELECT * FROM withdraw.hash_check WHERE id = ?", (the_hash,) ) @@ -141,10 +151,10 @@ async def get_hash_check(the_hash: str, lnurl_id: str) -> Optional[HashCheck]: ) if not rowlnurl: await create_hash_check(the_hash, lnurl_id) - return {"lnurl": True, "hash": False} + return HashCheck(lnurl=True, hash=False) else: if not rowid: await create_hash_check(the_hash, lnurl_id) - return {"lnurl": True, "hash": False} + return HashCheck(lnurl=True, hash=False) else: - return {"lnurl": True, "hash": True} + return HashCheck(lnurl=True, hash=True) diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 86640443..e9c46f04 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -1,10 +1,10 @@ import json -import traceback from datetime import datetime from http import HTTPStatus import httpx -import shortuuid # type: ignore +import shortuuid + from fastapi import HTTPException from fastapi.param_functions import Query from loguru import logger @@ -15,9 +15,8 @@ from lnbits.core.crud import update_payment_extra from lnbits.core.services import pay_invoice from . import withdraw_ext -from .crud import get_withdraw_link_by_hash, update_withdraw_link - -# FOR LNURLs WHICH ARE NOT UNIQUE +from .crud import get_withdraw_link_by_hash, increment_withdraw_link +from .models import WithdrawLink @withdraw_ext.get( @@ -53,9 +52,6 @@ async def api_lnurl_response(request: Request, unique_hash): return json.dumps(withdrawResponse) -# CALLBACK - - @withdraw_ext.get( "/api/v1/lnurl/cb/{unique_hash}", name="withdraw.api_lnurl_callback", @@ -99,102 +95,75 @@ async def api_lnurl_callback( detail=f"wait link open_time {link.open_time - now} seconds.", ) - usescsv = "" - - for x in range(1, link.uses - link.used): - usecv = link.usescsv.split(",") - usescsv += "," + str(usecv[x]) - usecsvback = usescsv - - found = False - if id_unique_hash is not None: - useslist = link.usescsv.split(",") - for ind, x in enumerate(useslist): - tohash = link.id + link.unique_hash + str(x) - if id_unique_hash == shortuuid.uuid(name=tohash): - found = True - useslist.pop(ind) - usescsv = ",".join(useslist) - if not found: + if id_unique_hash: + if check_unique_link(link, id_unique_hash): + # remove it from usescsv list + pass + else: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="withdraw not found." ) - else: - usescsv = usescsv[1:] - - changesback = { - "open_time": link.wait_time, - "used": link.used, - "usescsv": usecsvback, - } try: - changes = { - "open_time": link.wait_time + now, - "used": link.used + 1, - "usescsv": usescsv, - } - await update_withdraw_link(link.id, **changes) - - payment_request = pr - payment_hash = await pay_invoice( wallet_id=link.wallet, - payment_request=payment_request, + payment_request=pr, max_sat=link.max_withdrawable, extra={"tag": "withdraw"}, ) - + await increment_withdraw_link(link) if link.webhook_url: - async with httpx.AsyncClient() as client: - try: - kwargs = { - "json": { - "payment_hash": payment_hash, - "payment_request": payment_request, - "lnurlw": link.id, - }, - "timeout": 40, - } - if link.webhook_body: - kwargs["json"]["body"] = json.loads(link.webhook_body) - if link.webhook_headers: - kwargs["headers"] = json.loads(link.webhook_headers) - - r: httpx.Response = await client.post(link.webhook_url, **kwargs) - await update_payment_extra( - payment_hash=payment_hash, - extra={ - "wh_success": r.is_success, - "wh_message": r.reason_phrase, - "wh_response": r.text, - }, - outgoing=True, - ) - except Exception as exc: - # webhook fails shouldn't cause the lnurlw to fail since invoice is already paid - logger.error( - "Caught exception when dispatching webhook url: " + str(exc) - ) - await update_payment_extra( - payment_hash=payment_hash, - extra={"wh_success": False, "wh_message": str(exc)}, - outgoing=True, - ) - + await dispatch_webhook(link, payment_hash, pr) return {"status": "OK"} - except Exception as e: - await update_withdraw_link(link.id, **changesback) - logger.error(traceback.format_exc()) raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail=f"withdraw not working. {str(e)}" ) +def check_unique_link(link: WithdrawLink, unique_hash: str) -> bool: + unique_links = link.usescsv.split(",") + return any(unique_hash == shortuuid.uuid(name=link.id + link.unique_hash + x.strip()) for x in unique_links) + + +async def dispatch_webhook( + link: WithdrawLink, payment_hash: str, payment_request: str +) -> None: + async with httpx.AsyncClient() as client: + try: + r: httpx.Response = await client.post( + link.webhook_url, + json={ + "payment_hash": payment_hash, + "payment_request": payment_request, + "lnurlw": link.id, + "body": json.loads(link.webhook_body) if link.webhook_body else "", + }, + headers=json.loads(link.webhook_headers) + if link.webhook_headers + else None, + timeout=40, + ) + await update_payment_extra( + payment_hash=payment_hash, + extra={ + "wh_success": r.is_success, + "wh_message": r.reason_phrase, + "wh_response": r.text, + }, + outgoing=True, + ) + except Exception as exc: + # webhook fails shouldn't cause the lnurlw to fail since invoice is already paid + logger.error("Caught exception when dispatching webhook url: " + str(exc)) + await update_payment_extra( + payment_hash=payment_hash, + extra={"wh_success": False, "wh_message": str(exc)}, + outgoing=True, + ) + + # FOR LNURLs WHICH ARE UNIQUE - - @withdraw_ext.get( "/api/v1/lnurl/{unique_hash}/{id_unique_hash}", response_class=HTMLResponse, diff --git a/lnbits/extensions/withdraw/models.py b/lnbits/extensions/withdraw/models.py index 51c6a1cf..ddb9d380 100644 --- a/lnbits/extensions/withdraw/models.py +++ b/lnbits/extensions/withdraw/models.py @@ -1,9 +1,8 @@ -from sqlite3 import Row - -import shortuuid # type: ignore -from fastapi.param_functions import Query +import shortuuid +from fastapi import Query from lnurl import Lnurl, LnurlWithdrawResponse -from lnurl import encode as lnurl_encode # type: ignore +from lnurl.models import ClearnetUrl, MilliSatoshi +from lnurl import encode as lnurl_encode from pydantic import BaseModel from starlette.requests import Request @@ -67,18 +66,14 @@ class WithdrawLink(BaseModel): name="withdraw.api_lnurl_callback", unique_hash=self.unique_hash ) return LnurlWithdrawResponse( - callback=url, + callback=ClearnetUrl(url, scheme="https"), k1=self.k1, - min_withdrawable=self.min_withdrawable * 1000, - max_withdrawable=self.max_withdrawable * 1000, - default_description=self.title, + minWithdrawable=MilliSatoshi(self.min_withdrawable * 1000), + maxWithdrawable=MilliSatoshi(self.max_withdrawable * 1000), + defaultDescription=self.title, ) class HashCheck(BaseModel): - id: str - lnurl_id: str - - @classmethod - def from_row(cls, row: Row) -> "Hash": - return cls(**dict(row)) + hash: bool + lnurl: bool diff --git a/lnbits/extensions/withdraw/views.py b/lnbits/extensions/withdraw/views.py index 6d211ed4..3338b5a5 100644 --- a/lnbits/extensions/withdraw/views.py +++ b/lnbits/extensions/withdraw/views.py @@ -2,8 +2,7 @@ from http import HTTPStatus from io import BytesIO import pyqrcode -from fastapi import Request -from fastapi.params import Depends +from fastapi import Request, Depends from fastapi.templating import Jinja2Templates from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse, StreamingResponse diff --git a/lnbits/extensions/withdraw/views_api.py b/lnbits/extensions/withdraw/views_api.py index e0d3e56f..a1052a01 100644 --- a/lnbits/extensions/withdraw/views_api.py +++ b/lnbits/extensions/withdraw/views_api.py @@ -1,8 +1,9 @@ from http import HTTPStatus -from fastapi.param_functions import Query -from fastapi.params import Depends -from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore +from typing import Optional + +from fastapi import Query, Depends +from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl from starlette.exceptions import HTTPException from starlette.requests import Request @@ -30,7 +31,8 @@ async def api_links( wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + user = await get_user(wallet.wallet.user) + wallet_ids = user.wallet_ids if user else [] try: return [ @@ -47,7 +49,7 @@ async def api_links( @withdraw_ext.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK) async def api_link_retrieve( - link_id, request: Request, wallet: WalletTypeInfo = Depends(get_key_type) + link_id: str, request: Request, wallet: WalletTypeInfo = Depends(get_key_type) ): link = await get_withdraw_link(link_id, 0) @@ -68,7 +70,7 @@ async def api_link_retrieve( async def api_link_create_or_update( req: Request, data: CreateWithdrawData, - link_id: str = None, + link_id: Optional[str] = Query(), wallet: WalletTypeInfo = Depends(require_admin_key), ): if data.uses > 250: @@ -85,14 +87,6 @@ async def api_link_create_or_update( status_code=HTTPStatus.BAD_REQUEST, ) - usescsv = "" - for i in range(data.uses): - if data.is_unique: - usescsv += "," + str(i + 1) - else: - usescsv += "," + str(1) - usescsv = usescsv[1:] - if link_id: link = await get_withdraw_link(link_id, 0) if not link: @@ -103,13 +97,10 @@ async def api_link_create_or_update( raise HTTPException( detail="Not your withdraw link.", status_code=HTTPStatus.FORBIDDEN ) - link = await update_withdraw_link( - link_id, **data.dict(), usescsv=usescsv, used=0 - ) + link = await update_withdraw_link(link_id, **data.dict()) else: - link = await create_withdraw_link( - wallet_id=wallet.wallet.id, data=data, usescsv=usescsv - ) + link = await create_withdraw_link(wallet_id=wallet.wallet.id, data=data) + assert link return {**link.dict(), **{"lnurl": link.lnurl(req)}} @@ -131,9 +122,11 @@ async def api_link_delete(link_id, wallet: WalletTypeInfo = Depends(require_admi return {"success": True} -@withdraw_ext.get("/api/v1/links/{the_hash}/{lnurl_id}", status_code=HTTPStatus.OK) -async def api_hash_retrieve( - the_hash, lnurl_id, wallet: WalletTypeInfo = Depends(get_key_type) -): +@withdraw_ext.get( + "/api/v1/links/{the_hash}/{lnurl_id}", + status_code=HTTPStatus.OK, + dependencies=[Depends(get_key_type)], +) +async def api_hash_retrieve(the_hash, lnurl_id): hashCheck = await get_hash_check(the_hash, lnurl_id) return hashCheck diff --git a/pyproject.toml b/pyproject.toml index 186e2123..f1e8648b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,7 +104,6 @@ exclude = """(?x)( | ^lnbits/extensions/streamalerts. | ^lnbits/extensions/tpos. | ^lnbits/extensions/watchonly. - | ^lnbits/extensions/withdraw. | ^lnbits/wallets/lnd_grpc_files. )""" From 32b785d790b3b775c1268123c00de233c1172c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 17:01:02 +0100 Subject: [PATCH 18/27] fixes --- lnbits/extensions/gerty/helpers.py | 1 + lnbits/extensions/gerty/views_api.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 036aa011..59b7159d 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -430,6 +430,7 @@ async def get_screen_data(screen_num: int, screens_list: list, gerty): if screen_slug == "dashboard": title = gerty.name areas = await get_dashboard(gerty) + if screen_slug == "lnbits_wallets_balance": wallets = await get_lnbits_wallet_balances(gerty) diff --git a/lnbits/extensions/gerty/views_api.py b/lnbits/extensions/gerty/views_api.py index f71bec42..4020c980 100644 --- a/lnbits/extensions/gerty/views_api.py +++ b/lnbits/extensions/gerty/views_api.py @@ -17,7 +17,13 @@ from .crud import ( get_mempool_info, update_gerty, ) -from .helpers import * +from .helpers import ( + get_screen_data, + get_satoshi, + gerty_should_sleep, + get_next_update_time, + get_screen_slug_by_index, +) from .models import Gerty @@ -84,7 +90,7 @@ async def api_gerty_delete( @gerty_ext.get("/api/v1/gerty/satoshiquote", status_code=HTTPStatus.OK) async def api_gerty_satoshi(): - return await get_satoshi + return await get_satoshi() @gerty_ext.get("/api/v1/gerty/pages/{gerty_id}/{p}") From 40bcee6d22cfd064c2bde317ff2769e97a08976a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 17:09:50 +0100 Subject: [PATCH 19/27] fix issue @ben ;) --- lnbits/extensions/gerty/helpers.py | 3 +- .../gerty/templates/gerty/gerty.html | 499 +++++++++--------- lnbits/extensions/gerty/views_api.py | 4 +- 3 files changed, 256 insertions(+), 250 deletions(-) diff --git a/lnbits/extensions/gerty/helpers.py b/lnbits/extensions/gerty/helpers.py index 59b7159d..3e48c576 100644 --- a/lnbits/extensions/gerty/helpers.py +++ b/lnbits/extensions/gerty/helpers.py @@ -70,7 +70,7 @@ def get_text_item_dict( else: data_text["x"] = x_pos if x_pos > 0 else 0 data_text["y"] = y_pos if x_pos > 0 else 0 - return text + return data_text def get_date_suffix(dayNumber): @@ -532,7 +532,6 @@ async def get_screen_data(screen_num: int, screens_list: list, gerty): "title": title, "areas": areas, } - return data diff --git a/lnbits/extensions/gerty/templates/gerty/gerty.html b/lnbits/extensions/gerty/templates/gerty/gerty.html index 141c3152..8a374e61 100644 --- a/lnbits/extensions/gerty/templates/gerty/gerty.html +++ b/lnbits/extensions/gerty/templates/gerty/gerty.html @@ -1,251 +1,258 @@ {% extends "public.html" %} {% block toolbar_title %} Gerty: {% raw %}{{ - gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %} - -
+ - - - {{fun_exchange_market_rate["amount"]}} - {{fun_exchange_market_rate["unit"].split(" ")[1]}} - - - - -
-

"{{fun_satoshi_quotes["quote"]}}"

- ~ Satoshi {{fun_satoshi_quotes["date"]}} -
-
-
- -
- - - {{wallet["amount"]}} - ({{wallet["name"]}}) - - -
- -
+ {{fun_exchange_market_rate["amount"]}} + {{fun_exchange_market_rate["unit"].split(" ")[1]}} + + + + - - -
Onchain
-
- -

- {{item[0].value}}: {{item[1].value}} -

-
-
- - - -
Mining
-
- -

- {{item[0].value}}: {{item[1].value}} -

-
-
- - - -
Lightning (Last 7 days)
-
- -

- {{item[0].value}}: {{item[1].value}} -

-
-
- - - -
Servers to check
-
- -
- -
- - {{item[1].value}} - - - {{item[1].value}} - - - {{item[1].value}} - -
+
+

"{{fun_satoshi_quotes["quote"]}}"

+ ~ Satoshi {{fun_satoshi_quotes["date"]}} +
+ +
+ +
+ + + {{wallet["amount"]}} + ({{wallet["name"]}}) + + +
+ +
+ + +
Onchain
+
+ +

+ {{item[0].value}}: {{item[1].value}} +

+
+
+ + + +
Mining
+
+ +

+ {{item[0].value}}: {{item[1].value}} +

+
+
+ + + +
Lightning (Last 7 days)
+
+ +

+ {{item[0].value}}: {{item[1].value}} +

+
+
+ + + +
Servers to check
+
+ +
+ - - -
- - {% endraw %} {% endblock %} {% block scripts %} - - {% endblock %} - \ No newline at end of file + }, + methods: { + getGertyInfo: async function () { + for (let i = 0; i < 8; i++) { + try { + const {data} = await LNbits.api.request( + 'GET', + `/gerty/api/v1/gerty/pages/${this.gerty_id}/${i}` + ) + this.gerty[i] = data + } catch (error) { + LNbits.utils.notifyApiError(error) + } + } + console.log(this.gerty) + for (let i = 0; i < this.gerty.length; i++) { + if (this.gerty[i].screen.group == 'lnbits_wallets_balance') { + for (let q = 0; q < this.gerty[i].screen.areas.length; q++) { + this.lnbits_wallets_balance[q] = { + name: this.gerty[i].screen.areas[q][0].value, + amount: this.gerty[i].screen.areas[q][1].value, + color1: this.walletColors[q].first, + color2: this.walletColors[q].second + } + this.gertyname = this.gerty[i].settings.name + } + } + if (this.gerty[i].screen.group == 'url_checker') { + this.url_checker = this.gerty[i].screen.areas + this.gertyname = this.gerty[i].settings.name + } + if (this.gerty[i].screen.group == 'dashboard_onchain') { + this.dashboard_onchain = this.gerty[i].screen.areas + this.gertyname = this.gerty[i].settings.name + } + if (this.gerty[i].screen.group == 'dashboard_mining') { + this.dashboard_mining = this.gerty[i].screen.areas + this.gertyname = this.gerty[i].settings.name + } + if (this.gerty[i].screen.group == 'lightning_dashboard') { + this.lightning_dashboard = this.gerty[i].screen.areas + this.gertyname = this.gerty[i].settings.name + } + if (this.gerty[i].screen.group == 'fun_satoshi_quotes') { + this.fun_satoshi_quotes['quote'] = this.gerty[ + i + ].screen.areas[0][0].value + this.fun_satoshi_quotes['date'] = this.gerty[ + i + ].screen.areas[0][1].value + this.gertyname = this.gerty[i].settings.name + } + if (this.gerty[i].screen.group == 'fun_exchange_market_rate') { + this.fun_exchange_market_rate['unit'] = this.gerty[ + i + ].screen.areas[0][0].value + this.fun_exchange_market_rate['amount'] = this.gerty[ + i + ].screen.areas[0][1].value + this.gertyname = this.gerty[i].settings.name + } + } + + setTimeout(this.getGertyInfo, 20000) + this.$forceUpdate() + return this.gerty + } + }, + created: async function () { + await this.getGertyInfo() + } + }) + +{% endblock %} diff --git a/lnbits/extensions/gerty/views_api.py b/lnbits/extensions/gerty/views_api.py index 4020c980..c408504b 100644 --- a/lnbits/extensions/gerty/views_api.py +++ b/lnbits/extensions/gerty/views_api.py @@ -18,10 +18,10 @@ from .crud import ( update_gerty, ) from .helpers import ( - get_screen_data, - get_satoshi, gerty_should_sleep, get_next_update_time, + get_satoshi, + get_screen_data, get_screen_slug_by_index, ) from .models import Gerty From 9bace16a45123a203090b648230e428a25453d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 18:27:39 +0100 Subject: [PATCH 20/27] refactoring some stuff --- lnbits/extensions/withdraw/crud.py | 9 ++++++++ lnbits/extensions/withdraw/lnurl.py | 30 +++++++++---------------- lnbits/extensions/withdraw/models.py | 2 +- lnbits/extensions/withdraw/views.py | 3 +-- lnbits/extensions/withdraw/views_api.py | 8 ++----- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/lnbits/extensions/withdraw/crud.py b/lnbits/extensions/withdraw/crud.py index 8387d264..9fa5bada 100644 --- a/lnbits/extensions/withdraw/crud.py +++ b/lnbits/extensions/withdraw/crud.py @@ -95,6 +95,15 @@ async def get_withdraw_links(wallet_ids: Union[str, List[str]]) -> List[Withdraw return [WithdrawLink(**row) for row in rows] +async def remove_unique_withdraw_link(link: WithdrawLink, unique_hash: str) -> None: + unique_links = link.usescsv.split(",") + unique_links.remove(unique_hash) + await update_withdraw_link( + link.id, + usescsv=",".join(unique_links), + ) + + async def increment_withdraw_link(link: WithdrawLink) -> None: await update_withdraw_link( link.id, diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index e9c46f04..85bb1f72 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -4,24 +4,20 @@ from http import HTTPStatus import httpx import shortuuid - -from fastapi import HTTPException -from fastapi.param_functions import Query +from fastapi import HTTPException, Response, Request, Query from loguru import logger -from starlette.requests import Request -from starlette.responses import HTMLResponse from lnbits.core.crud import update_payment_extra from lnbits.core.services import pay_invoice from . import withdraw_ext -from .crud import get_withdraw_link_by_hash, increment_withdraw_link +from .crud import get_withdraw_link_by_hash, remove_unique_withdraw_link, increment_withdraw_link from .models import WithdrawLink @withdraw_ext.get( "/api/v1/lnurl/{unique_hash}", - response_class=HTMLResponse, + response_class=Response, name="withdraw.api_lnurl_response", ) async def api_lnurl_response(request: Request, unique_hash): @@ -97,8 +93,7 @@ async def api_lnurl_callback( if id_unique_hash: if check_unique_link(link, id_unique_hash): - # remove it from usescsv list - pass + await remove_unique_withdraw_link(link, id_unique_hash) else: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="withdraw not found." @@ -122,8 +117,10 @@ async def api_lnurl_callback( def check_unique_link(link: WithdrawLink, unique_hash: str) -> bool: - unique_links = link.usescsv.split(",") - return any(unique_hash == shortuuid.uuid(name=link.id + link.unique_hash + x.strip()) for x in unique_links) + return any( + unique_hash == shortuuid.uuid(name=link.id + link.unique_hash + x.strip()) + for x in link.usescsv.split(",") + ) async def dispatch_webhook( @@ -166,7 +163,7 @@ async def dispatch_webhook( # FOR LNURLs WHICH ARE UNIQUE @withdraw_ext.get( "/api/v1/lnurl/{unique_hash}/{id_unique_hash}", - response_class=HTMLResponse, + response_class=Response, name="withdraw.api_lnurl_multi_response", ) async def api_lnurl_multi_response(request: Request, unique_hash, id_unique_hash): @@ -182,14 +179,7 @@ async def api_lnurl_multi_response(request: Request, unique_hash, id_unique_hash status_code=HTTPStatus.NOT_FOUND, detail="Withdraw is spent." ) - useslist = link.usescsv.split(",") - found = False - for x in useslist: - tohash = link.id + link.unique_hash + str(x) - if id_unique_hash == shortuuid.uuid(name=tohash): - found = True - - if not found: + if not check_unique_link(link, id_unique_hash): raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found." ) diff --git a/lnbits/extensions/withdraw/models.py b/lnbits/extensions/withdraw/models.py index ddb9d380..49421a79 100644 --- a/lnbits/extensions/withdraw/models.py +++ b/lnbits/extensions/withdraw/models.py @@ -1,8 +1,8 @@ import shortuuid from fastapi import Query from lnurl import Lnurl, LnurlWithdrawResponse -from lnurl.models import ClearnetUrl, MilliSatoshi from lnurl import encode as lnurl_encode +from lnurl.models import ClearnetUrl, MilliSatoshi from pydantic import BaseModel from starlette.requests import Request diff --git a/lnbits/extensions/withdraw/views.py b/lnbits/extensions/withdraw/views.py index 3338b5a5..e8e5719a 100644 --- a/lnbits/extensions/withdraw/views.py +++ b/lnbits/extensions/withdraw/views.py @@ -2,9 +2,8 @@ from http import HTTPStatus from io import BytesIO import pyqrcode -from fastapi import Request, Depends +from fastapi import Depends, HTTPException, Request from fastapi.templating import Jinja2Templates -from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse, StreamingResponse from lnbits.core.models import User diff --git a/lnbits/extensions/withdraw/views_api.py b/lnbits/extensions/withdraw/views_api.py index a1052a01..525796c9 100644 --- a/lnbits/extensions/withdraw/views_api.py +++ b/lnbits/extensions/withdraw/views_api.py @@ -1,11 +1,7 @@ from http import HTTPStatus -from typing import Optional - -from fastapi import Query, Depends +from fastapi import Depends, HTTPException, Query, Request from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl -from starlette.exceptions import HTTPException -from starlette.requests import Request from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key @@ -70,7 +66,7 @@ async def api_link_retrieve( async def api_link_create_or_update( req: Request, data: CreateWithdrawData, - link_id: Optional[str] = Query(), + link_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key), ): if data.uses > 250: From 38d3f5f6daf83eccc526925678b810c768f7fa7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 18:29:47 +0100 Subject: [PATCH 21/27] remove unneeded assert --- lnbits/extensions/withdraw/crud.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lnbits/extensions/withdraw/crud.py b/lnbits/extensions/withdraw/crud.py index 9fa5bada..51a7512f 100644 --- a/lnbits/extensions/withdraw/crud.py +++ b/lnbits/extensions/withdraw/crud.py @@ -147,7 +147,6 @@ async def create_hash_check(the_hash: str, lnurl_id: str) -> HashCheck: (the_hash, lnurl_id), ) hashCheck = await get_hash_check(the_hash, lnurl_id) - assert hashCheck return hashCheck From 99a8c7afb0059c81efbcf244a6062b647d36c4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 18:32:18 +0100 Subject: [PATCH 22/27] sorting --- lnbits/extensions/withdraw/lnurl.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 85bb1f72..5ef521fa 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -4,14 +4,18 @@ from http import HTTPStatus import httpx import shortuuid -from fastapi import HTTPException, Response, Request, Query +from fastapi import HTTPException, Query, Request, Response from loguru import logger from lnbits.core.crud import update_payment_extra from lnbits.core.services import pay_invoice from . import withdraw_ext -from .crud import get_withdraw_link_by_hash, remove_unique_withdraw_link, increment_withdraw_link +from .crud import ( + get_withdraw_link_by_hash, + increment_withdraw_link, + remove_unique_withdraw_link, +) from .models import WithdrawLink From 31fe5a51419fea879a4fa2737036db126f8e0f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 18:48:07 +0100 Subject: [PATCH 23/27] fix removing the right index from unique withdrawlinks --- lnbits/extensions/withdraw/crud.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/withdraw/crud.py b/lnbits/extensions/withdraw/crud.py index 51a7512f..1871fa9c 100644 --- a/lnbits/extensions/withdraw/crud.py +++ b/lnbits/extensions/withdraw/crud.py @@ -1,3 +1,5 @@ +import shortuuid + from datetime import datetime from typing import List, Optional, Union @@ -96,8 +98,7 @@ async def get_withdraw_links(wallet_ids: Union[str, List[str]]) -> List[Withdraw async def remove_unique_withdraw_link(link: WithdrawLink, unique_hash: str) -> None: - unique_links = link.usescsv.split(",") - unique_links.remove(unique_hash) + unique_links = [x.strip() for x in link.usescsv.split(",") if unique_hash != shortuuid.uuid(name=link.id + link.unique_hash + x.strip())] await update_withdraw_link( link.id, usescsv=",".join(unique_links), From 9fb63f268f9c256a0c2d34403f2bda8fcb6452e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 4 Jan 2023 18:51:36 +0100 Subject: [PATCH 24/27] formatting --- lnbits/extensions/withdraw/crud.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/withdraw/crud.py b/lnbits/extensions/withdraw/crud.py index 1871fa9c..68603f0a 100644 --- a/lnbits/extensions/withdraw/crud.py +++ b/lnbits/extensions/withdraw/crud.py @@ -1,8 +1,8 @@ -import shortuuid - from datetime import datetime from typing import List, Optional, Union +import shortuuid + from lnbits.helpers import urlsafe_short_hash from . import db @@ -98,7 +98,11 @@ async def get_withdraw_links(wallet_ids: Union[str, List[str]]) -> List[Withdraw async def remove_unique_withdraw_link(link: WithdrawLink, unique_hash: str) -> None: - unique_links = [x.strip() for x in link.usescsv.split(",") if unique_hash != shortuuid.uuid(name=link.id + link.unique_hash + x.strip())] + unique_links = [ + x.strip() + for x in link.usescsv.split(",") + if unique_hash != shortuuid.uuid(name=link.id + link.unique_hash + x.strip()) + ] await update_withdraw_link( link.id, usescsv=",".join(unique_links), From 9db9594a48be4226e362ae28e0563824b20cc7d3 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 18:11:53 +0000 Subject: [PATCH 25/27] swaps incremental id for small uuid for pos/atm --- lnbits/extensions/lnurldevice/crud.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/lnbits/extensions/lnurldevice/crud.py b/lnbits/extensions/lnurldevice/crud.py index 18451848..1bd8aa6d 100644 --- a/lnbits/extensions/lnurldevice/crud.py +++ b/lnbits/extensions/lnurldevice/crud.py @@ -1,5 +1,7 @@ from typing import List, Optional, Union +import shortuuid + from lnbits.helpers import urlsafe_short_hash from . import db @@ -12,7 +14,7 @@ async def create_lnurldevice( data: createLnurldevice, ) -> lnurldevices: if data.device == "pos" or data.device == "atm": - lnurldevice_id = str(await get_lnurldeviceposcount()) + lnurldevice_id = shortuuid.uuid()[:8] else: lnurldevice_id = urlsafe_short_hash() lnurldevice_key = urlsafe_short_hash() @@ -82,17 +84,6 @@ async def update_lnurldevice(lnurldevice_id: str, **kwargs) -> Optional[lnurldev return lnurldevices(**row) if row else None -async def get_lnurldeviceposcount() -> int: - row = await db.fetchall( - "SELECT * FROM lnurldevice.lnurldevices WHERE device = ? OR device = ?", - ( - "pos", - "atm", - ), - ) - return len(row) + 1 - - async def get_lnurldevice(lnurldevice_id: str) -> lnurldevices: row = await db.fetchone( "SELECT * FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,) From bb4ab7ab9225ae8fed8a1de8e9efebfb6701d000 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 18:16:04 +0000 Subject: [PATCH 26/27] can in fact be smaller, as for uniqueness, not security --- lnbits/extensions/lnurldevice/crud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/lnurldevice/crud.py b/lnbits/extensions/lnurldevice/crud.py index 1bd8aa6d..423c6a46 100644 --- a/lnbits/extensions/lnurldevice/crud.py +++ b/lnbits/extensions/lnurldevice/crud.py @@ -14,7 +14,7 @@ async def create_lnurldevice( data: createLnurldevice, ) -> lnurldevices: if data.device == "pos" or data.device == "atm": - lnurldevice_id = shortuuid.uuid()[:8] + lnurldevice_id = shortuuid.uuid()[:5] else: lnurldevice_id = urlsafe_short_hash() lnurldevice_key = urlsafe_short_hash() From 61f415ccee5a352daff4baabaf19bac78b9c7060 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 4 Jan 2023 19:01:52 +0000 Subject: [PATCH 27/27] software gerty url_checker fixed --- lnbits/extensions/gerty/templates/gerty/gerty.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/gerty/templates/gerty/gerty.html b/lnbits/extensions/gerty/templates/gerty/gerty.html index 8a374e61..06a29e22 100644 --- a/lnbits/extensions/gerty/templates/gerty/gerty.html +++ b/lnbits/extensions/gerty/templates/gerty/gerty.html @@ -52,7 +52,7 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
- - +
Servers to check
@@ -196,7 +195,6 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %} LNbits.utils.notifyApiError(error) } } - console.log(this.gerty) for (let i = 0; i < this.gerty.length; i++) { if (this.gerty[i].screen.group == 'lnbits_wallets_balance') { for (let q = 0; q < this.gerty[i].screen.areas.length; q++) {