Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update to v1.0.0 #15

Merged
merged 4 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from fastapi import APIRouter
from lnbits.db import Database
from lnbits.tasks import create_permanent_unique_task
from loguru import logger

from .tasks import wait_for_paid_invoices
Expand Down Expand Up @@ -34,7 +33,7 @@ def example_stop():


def example_start():
# ignore will be removed in lnbits `0.12.6`
# https://github.com/lnbits/lnbits/pull/2417
task = create_permanent_unique_task("ext_testing", wait_for_paid_invoices) # type: ignore
from lnbits.tasks import create_permanent_unique_task

task = create_permanent_unique_task("ext_testing", wait_for_paid_invoices)
scheduled_tasks.append(task)
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Build your own!",
"short_description": "Extension building guide",
"tile": "https://raw.githubusercontent.com/lnbits/example/main/static/bitcoin-extension.png",
"min_lnbits_version": "0.12.6",
"min_lnbits_version": "1.0.0",
"donate": "[email protected]",
"contributors": [
{
Expand Down
2,421 changes: 1,271 additions & 1,150 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = ["Alan Bits <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.10 | ^3.9"
lnbits = "*"
lnbits = {version = "*", allow-prereleases = true}

[tool.poetry.group.dev.dependencies]
black = "^24.3.0"
Expand Down
85 changes: 85 additions & 0 deletions static/js/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const mapObject = obj => {
// obj.date = Quasar.date.formatDate(new Date(obj.time), 'YYYY-MM-DD HH:mm')
// here you can do something with the mapped data
return obj
}

window.app = Vue.createApp({
el: '#vue',
mixins: [windowMixin],
// Declare models/variables
data() {
return {
protocol: window.location.protocol,
location: '//' + window.location.hostname,
thingDialog: {
show: false,
data: {}
},
someBool: true,
splitterModel: 20,
exampleData: [],
tab: 'frameworks',
framworktab: 'fastapi',
usefultab: 'magicalg',
vettedData: ''
}
},
// Where functions live
methods: {
exampleFunction(data) {
LNbits.api
.request(
'GET', // Type of request
'/example/api/v1/test/00000000', // URL of the endpoint
this.g.user.wallets[0].inkey, // Often endpoints require a key
data
)
.then(response => {
this.exampleData = response.data.map(mapObject) // Often whats returned is mapped onto some model
})
// Error will be passed to the frontend
.catch(LNbits.utils.notifyApiError)
},
getVettedReadme() {
// This is a function that gets the vetted readme from the LNbits repo and converts it from makrdown to html.
LNbits.api
.request('GET', '/example/api/v1/vetted', this.g.user.wallets[0].inkey)
.then(response => {
this.vettedData = LNbits.utils.convertMarkdown(response.data)
})
.catch(LNbits.utils.notifyApiError)
},
async initWs() {
if (location.protocol !== 'http:') {
localUrl =
'wss://' +
document.domain +
':' +
location.port +
'/api/v1/ws/32872r23g29'
} else {
localUrl =
'ws://' +
document.domain +
':' +
location.port +
'/api/v1/ws/32872r23g29'
}
this.ws = new WebSocket(localUrl)
this.ws.addEventListener('message', async ({data}) => {
const res = data.toString()
document.getElementById('text-to-change').innerHTML = res
})
},
sendThingDialog() {
console.log(this.thingDialog)
}
},
// To run on startup
created() {
this.exampleFunction('lorum')
this.initWs()
this.getVettedReadme()
}
})
8 changes: 4 additions & 4 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@

async def wait_for_paid_invoices():
invoice_queue = asyncio.Queue()
register_invoice_listener(invoice_queue, "example")
register_invoice_listener(invoice_queue, "ext_example")

while True:
payment = await invoice_queue.get()
await on_invoice_paid(payment)


async def on_invoice_paid(payment: Payment) -> None:
if (
payment.extra.get("tag") == "example"
): # Will grab any payment with the tag "example"
# Will grab any payment with the tag "example"
if payment.extra.get("tag") == "example":
logger.info("example extension received payment")
logger.debug(payment)
107 changes: 4 additions & 103 deletions templates/example/index.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
%} {% block page %}

%} {% block scripts %} {{ window_vars(user) }}
<script src="{{ static_url_for('example/static', path='js/index.js') }}"></script>
<!-- Do not remove. Test install extension version: 2 -->
{% endblock %} {% block page %}
<q-dialog v-model="thingDialog.show" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form @submit="sendThingDialog" class="q-gutter-md">
Expand Down Expand Up @@ -371,105 +373,4 @@
</q-card>
</q-card-section>
</q-card>
{% endblock %} {% block scripts %} {{ window_vars(user) }}

<script>
var someMapObject = obj => {
obj._data = _.clone(obj)
obj.date = Quasar.utils.date.formatDate(
new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm'
)
// here you can do something with the mapped data
return obj
}
new Vue({
el: '#vue',
mixins: [windowMixin],
data: function () {
return {
///// Declare models/variables /////
protocol: window.location.protocol,
location: '//' + window.location.hostname,
thingDialog: {
show: false,
data: {}
},
someBool: true,
splitterModel: 20,
exampleData: [],
tab: 'frameworks',
framworktab: 'fastapi',
usefultab: 'magicalg',
vettedData: ''
}
},
///// Where functions live /////
methods: {
exampleFunction: function (data) {
var theData = data
LNbits.api
.request(
'GET', // Type of request
'/example/api/v1/test/' + theData, // URL of the endpoint
this.g.user.wallets[0].inkey // Often endpoints require a key
)
.then(response => {
this.exampleData = response.data.map(someMapObject) // Often whats returned is mapped onto some model
})
.catch(error => {
LNbits.utils.notifyApiError(error) // Error will be passed to the frontend
})
},
getVettedReadme: function () {
// This is a function that gets the vetted readme from the LNbits repo and converts it from makrdown to html.
LNbits.api
.request(
'GET',
'/example/api/v1/vetted',
this.g.user.wallets[0].inkey
)
.then(response => {
this.vettedData = LNbits.utils.convertMarkdown(response.data)
})
.catch(error => {
LNbits.utils.notifyApiError(error)
})
},
initWs: async function () {
if (location.protocol !== 'http:') {
localUrl =
'wss://' +
document.domain +
':' +
location.port +
'/api/v1/ws/32872r23g29'
} else {
localUrl =
'ws://' +
document.domain +
':' +
location.port +
'/api/v1/ws/32872r23g29'
}
this.ws = new WebSocket(localUrl)
this.ws.addEventListener('message', async ({data}) => {
const res = data.toString()
document.getElementById('text-to-change').innerHTML = res
})
},
sendThingDialog() {
console.log(this.thingDialog)
}
},
///// To run on startup /////
created: function () {
self = this // Often used to run a real object, rather than the event (all a bit confusing really)
self.exampleFunction('lorum')
self.initWs()
self.getVettedReadme()
}
})
</script>
<!-- Do not remove. Test install extension version: 2 -->
{% endblock %}
2 changes: 1 addition & 1 deletion views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ async def index(
user: User = Depends(check_user_exists),
):
return template_renderer(["example/templates"]).TemplateResponse(
request, "example/index.html", {"user": user.dict()}
request, "example/index.html", {"user": user.json()}
)
41 changes: 22 additions & 19 deletions views_api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from http import HTTPStatus

import httpx
from fastapi import APIRouter, Depends
from fastapi.exceptions import HTTPException
from lnbits.decorators import WalletTypeInfo, get_key_type
from fastapi import APIRouter, Depends, HTTPException
from lnbits.decorators import require_invoice_key

from .models import Example

Expand All @@ -16,20 +15,24 @@


@example_ext_api.get("/test/{example_data}", description="Example API endpoint")
async def api_example(example_data: str) -> Example:
# Do some python things and return the data
return Example(id="2", wallet=example_data)


@example_ext_api.get("/vetted", description="Get the vetted extension readme")
async def api_get_vetted(wallet: WalletTypeInfo = Depends(get_key_type)):
try:
async with httpx.AsyncClient() as client:
resp = await client.get(
"https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/README.md"
)
return resp.text
except Exception as e:
async def api_example(example_data: str) -> list[Example]:
if example_data != "00000000":
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)
) from e
status_code=HTTPStatus.BAD_REQUEST,
detail="Invalid example data",
)
# Do some python things and return the data
return [Example(id="1", wallet=example_data), Example(id="2", wallet=example_data)]


@example_ext_api.get(
"/vetted",
description="Get the vetted extension readme",
dependencies=[Depends(require_invoice_key)],
)
async def api_get_vetted():
async with httpx.AsyncClient() as client:
resp = await client.get(
"https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/README.md"
)
return resp.text