From 0c089109b925eefcc3f9e4c1985b34c5102d5ac8 Mon Sep 17 00:00:00 2001 From: Bitcoin Gamer 21 <98273902+bitcoingamer21@users.noreply.github.com> Date: Fri, 6 May 2022 20:26:42 +0200 Subject: [PATCH] Edited discord bot extension to use FastAPI (#570) Squashed 9 commits: * Added Discordbot Extension * Removed backup files * Fixing renaming wallet * added further description * further description index.html * import staticfiles * remove duplicate file * deleted changes in core --- lnbits/extensions/discordbot/Pipfile | 11 + lnbits/extensions/discordbot/README.md | 34 ++ lnbits/extensions/discordbot/__init__.py | 25 + lnbits/extensions/discordbot/config.json | 6 + lnbits/extensions/discordbot/crud.py | 123 +++++ lnbits/extensions/discordbot/migrations.py | 30 ++ lnbits/extensions/discordbot/models.py | 36 ++ lnbits/extensions/discordbot/static/stack.png | Bin 0 -> 73993 bytes .../templates/discordbot/_api_docs.html | 260 ++++++++++ .../templates/discordbot/index.html | 464 ++++++++++++++++++ lnbits/extensions/discordbot/views.py | 15 + lnbits/extensions/discordbot/views_api.py | 127 +++++ 12 files changed, 1131 insertions(+) create mode 100644 lnbits/extensions/discordbot/Pipfile create mode 100644 lnbits/extensions/discordbot/README.md create mode 100644 lnbits/extensions/discordbot/__init__.py create mode 100644 lnbits/extensions/discordbot/config.json create mode 100644 lnbits/extensions/discordbot/crud.py create mode 100644 lnbits/extensions/discordbot/migrations.py create mode 100644 lnbits/extensions/discordbot/models.py create mode 100644 lnbits/extensions/discordbot/static/stack.png create mode 100644 lnbits/extensions/discordbot/templates/discordbot/_api_docs.html create mode 100644 lnbits/extensions/discordbot/templates/discordbot/index.html create mode 100644 lnbits/extensions/discordbot/views.py create mode 100644 lnbits/extensions/discordbot/views_api.py diff --git a/lnbits/extensions/discordbot/Pipfile b/lnbits/extensions/discordbot/Pipfile new file mode 100644 index 000000000..d58206622 --- /dev/null +++ b/lnbits/extensions/discordbot/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +[requires] +python_version = "3.9" diff --git a/lnbits/extensions/discordbot/README.md b/lnbits/extensions/discordbot/README.md new file mode 100644 index 000000000..a14083175 --- /dev/null +++ b/lnbits/extensions/discordbot/README.md @@ -0,0 +1,34 @@ +# Discord Bot + +## Provide LNbits wallets for all your Discord users + +_This extension is a modifed version of LNbits [User Manager](../usermanager/README.md)_ + +The intended usage of this extension is to connect it to a specifically designed [Discord Bot](https://github.com/chrislennon/lnbits-discord-bot) leveraging LNbits as a community based lightning node. + +## Setup +This bot can target [lnbits.com](https://lnbits.com) or a self hosted instance. + +To setup and run the bot instructions are located [here](https://github.com/chrislennon/lnbits-discord-bot#installation) + +## Usage +This bot will allow users to interact with it in the following ways [full command list](https://github.com/chrislennon/lnbits-discord-bot#commands): + +`/create` Will create a wallet for the Discord user + - (currently limiting 1 Discord user == 1 LNbits user == 1 user wallet) + +![create](https://imgur.com/CWdDusE.png) + +`/balance` Will show the balance of the users wallet. + +![balance](https://imgur.com/tKeReCp.png) + +`/tip @user [amount]` Will sent money from one user to another + - If the recieving user does not have a wallet, one will be created for them + - The receiving user will receive a direct message from the bot with a link to their wallet + +![tip](https://imgur.com/K3tnChK.png) + +`/payme [amount] [description]` Will open an invoice that can be paid by any user + +![payme](https://imgur.com/dFvAqL3.png) diff --git a/lnbits/extensions/discordbot/__init__.py b/lnbits/extensions/discordbot/__init__.py new file mode 100644 index 000000000..ff60dd628 --- /dev/null +++ b/lnbits/extensions/discordbot/__init__.py @@ -0,0 +1,25 @@ +from fastapi import APIRouter +from fastapi.staticfiles import StaticFiles + +from lnbits.db import Database +from lnbits.helpers import template_renderer + +db = Database("ext_discordbot") + +discordbot_static_files = [ + { + "path": "/discordbot/static", + "app": StaticFiles(directory="lnbits/extensions/discordbot/static"), + "name": "discordbot_static", + } +] + +discordbot_ext: APIRouter = APIRouter(prefix="/discordbot", tags=["discordbot"]) + + +def discordbot_renderer(): + return template_renderer(["lnbits/extensions/discordbot/templates"]) + + +from .views import * # noqa +from .views_api import * # noqa diff --git a/lnbits/extensions/discordbot/config.json b/lnbits/extensions/discordbot/config.json new file mode 100644 index 000000000..eb6741225 --- /dev/null +++ b/lnbits/extensions/discordbot/config.json @@ -0,0 +1,6 @@ +{ + "name": "Discord Bot", + "short_description": "Generate users and wallets", + "icon": "person_add", + "contributors": ["bitcoingamer21"] +} diff --git a/lnbits/extensions/discordbot/crud.py b/lnbits/extensions/discordbot/crud.py new file mode 100644 index 000000000..5661fcb4d --- /dev/null +++ b/lnbits/extensions/discordbot/crud.py @@ -0,0 +1,123 @@ +from typing import List, Optional + +from lnbits.core.crud import ( + create_account, + create_wallet, + delete_wallet, + get_payments, + get_user, +) +from lnbits.core.models import Payment + +from . import db +from .models import CreateUserData, Users, Wallets + +### Users + + +async def create_discordbot_user(data: CreateUserData) -> Users: + account = await create_account() + user = await get_user(account.id) + assert user, "Newly created user couldn't be retrieved" + + wallet = await create_wallet(user_id=user.id, wallet_name=data.wallet_name) + + await db.execute( + """ + INSERT INTO discordbot.users (id, name, admin, discord_id) + VALUES (?, ?, ?, ?) + """, + (user.id, data.user_name, data.admin_id, data.discord_id), + ) + + await db.execute( + """ + INSERT INTO discordbot.wallets (id, admin, name, "user", adminkey, inkey) + VALUES (?, ?, ?, ?, ?, ?) + """, + ( + wallet.id, + data.admin_id, + data.wallet_name, + user.id, + wallet.adminkey, + wallet.inkey, + ), + ) + + user_created = await get_discordbot_user(user.id) + assert user_created, "Newly created user couldn't be retrieved" + return user_created + + +async def get_discordbot_user(user_id: str) -> Optional[Users]: + row = await db.fetchone("SELECT * FROM discordbot.users WHERE id = ?", (user_id,)) + return Users(**row) if row else None + + +async def get_discordbot_users(user_id: str) -> List[Users]: + rows = await db.fetchall( + "SELECT * FROM discordbot.users WHERE admin = ?", (user_id,) + ) + + return [Users(**row) for row in rows] + + +async def delete_discordbot_user(user_id: str) -> None: + wallets = await get_discordbot_wallets(user_id) + for wallet in wallets: + await delete_wallet(user_id=user_id, wallet_id=wallet.id) + + await db.execute("DELETE FROM discordbot.users WHERE id = ?", (user_id,)) + await db.execute("""DELETE FROM discordbot.wallets WHERE "user" = ?""", (user_id,)) + + +### Wallets + + +async def create_discordbot_wallet( + user_id: str, wallet_name: str, admin_id: str +) -> Wallets: + wallet = await create_wallet(user_id=user_id, wallet_name=wallet_name) + await db.execute( + """ + INSERT INTO discordbot.wallets (id, admin, name, "user", adminkey, inkey) + VALUES (?, ?, ?, ?, ?, ?) + """, + (wallet.id, admin_id, wallet_name, user_id, wallet.adminkey, wallet.inkey), + ) + wallet_created = await get_discordbot_wallet(wallet.id) + assert wallet_created, "Newly created wallet couldn't be retrieved" + return wallet_created + + +async def get_discordbot_wallet(wallet_id: str) -> Optional[Wallets]: + row = await db.fetchone( + "SELECT * FROM discordbot.wallets WHERE id = ?", (wallet_id,) + ) + return Wallets(**row) if row else None + + +async def get_discordbot_wallets(admin_id: str) -> Optional[Wallets]: + rows = await db.fetchall( + "SELECT * FROM discordbot.wallets WHERE admin = ?", (admin_id,) + ) + return [Wallets(**row) for row in rows] + + +async def get_discordbot_users_wallets(user_id: str) -> Optional[Wallets]: + rows = await db.fetchall( + """SELECT * FROM discordbot.wallets WHERE "user" = ?""", (user_id,) + ) + return [Wallets(**row) for row in rows] + + +async def get_discordbot_wallet_transactions(wallet_id: str) -> Optional[Payment]: + return await get_payments( + wallet_id=wallet_id, complete=True, pending=False, outgoing=True, incoming=True + ) + + +async def delete_discordbot_wallet(wallet_id: str, user_id: str) -> None: + await delete_wallet(user_id=user_id, wallet_id=wallet_id) + await db.execute("DELETE FROM discordbot.wallets WHERE id = ?", (wallet_id,)) diff --git a/lnbits/extensions/discordbot/migrations.py b/lnbits/extensions/discordbot/migrations.py new file mode 100644 index 000000000..ababfd7a5 --- /dev/null +++ b/lnbits/extensions/discordbot/migrations.py @@ -0,0 +1,30 @@ +async def m001_initial(db): + """ + Initial users table. + """ + await db.execute( + """ + CREATE TABLE discordbot.users ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + admin TEXT NOT NULL, + discord_id TEXT + ); + """ + ) + + """ + Initial wallets table. + """ + await db.execute( + """ + CREATE TABLE discordbot.wallets ( + id TEXT PRIMARY KEY, + admin TEXT NOT NULL, + name TEXT NOT NULL, + "user" TEXT NOT NULL, + adminkey TEXT NOT NULL, + inkey TEXT NOT NULL + ); + """ + ) diff --git a/lnbits/extensions/discordbot/models.py b/lnbits/extensions/discordbot/models.py new file mode 100644 index 000000000..4be367f80 --- /dev/null +++ b/lnbits/extensions/discordbot/models.py @@ -0,0 +1,36 @@ +from sqlite3 import Row + +from fastapi.param_functions import Query +from pydantic import BaseModel +from typing import Optional + + +class CreateUserData(BaseModel): + user_name: str = Query(...) + wallet_name: str = Query(...) + admin_id: str = Query(...) + discord_id: str = Query("") + +class CreateUserWallet(BaseModel): + user_id: str = Query(...) + wallet_name: str = Query(...) + admin_id: str = Query(...) + + +class Users(BaseModel): + id: str + name: str + admin: str + discord_id: str + +class Wallets(BaseModel): + id: str + admin: str + name: str + user: str + adminkey: str + inkey: str + + @classmethod + def from_row(cls, row: Row) -> "Wallets": + return cls(**dict(row)) diff --git a/lnbits/extensions/discordbot/static/stack.png b/lnbits/extensions/discordbot/static/stack.png new file mode 100644 index 0000000000000000000000000000000000000000..3b987db118ad79196f3592038cc77b1c4fa4ad92 GIT binary patch literal 73993 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 KQgPoZ?EeAyL$~4p literal 0 HcmV?d00001 diff --git a/lnbits/extensions/discordbot/templates/discordbot/_api_docs.html b/lnbits/extensions/discordbot/templates/discordbot/_api_docs.html new file mode 100644 index 000000000..40fcfb126 --- /dev/null +++ b/lnbits/extensions/discordbot/templates/discordbot/_api_docs.html @@ -0,0 +1,260 @@ + + + +
+ Discord Bot: Connect Discord users to LNbits. +
+
+ + + + + + + + GET + /discordbot/api/v1/users +
Body (application/json)
+
+ Returns 201 CREATED (application/json) +
+ JSON list of users +
Curl example
+ curl -X GET {{ request.base_url }}discordbot/api/v1/users -H + "X-Api-Key: {{ user.wallets[0].inkey }}" + +
+
+
+ + + + GET + /discordbot/api/v1/users/<user_id> +
Body (application/json)
+
+ Returns 201 CREATED (application/json) +
+ JSON list of users +
Curl example
+ curl -X GET {{ request.base_url + }}discordbot/api/v1/users/<user_id> -H "X-Api-Key: {{ + user.wallets[0].inkey }}" + +
+
+
+ + + + GET + /discordbot/api/v1/wallets/<user_id> +
Headers
+ {"X-Api-Key": <string>} +
Body (application/json)
+
+ Returns 201 CREATED (application/json) +
+ JSON wallet data +
Curl example
+ curl -X GET {{ request.base_url + }}discordbot/api/v1/wallets/<user_id> -H "X-Api-Key: {{ + user.wallets[0].inkey }}" + +
+
+
+ + + + GET + /discordbot/api/v1/wallets<wallet_id> +
Headers
+ {"X-Api-Key": <string>} +
Body (application/json)
+
+ Returns 201 CREATED (application/json) +
+ JSON a wallets transactions +
Curl example
+ curl -X GET {{ request.base_url + }}discordbot/api/v1/wallets<wallet_id> -H "X-Api-Key: {{ + user.wallets[0].inkey }}" + +
+
+
+ + + + POST + /discordbot/api/v1/users +
Headers
+ {"X-Api-Key": <string>, "Content-type": + "application/json"} +
+ Body (application/json) - "admin_id" is a YOUR user ID +
+ {"admin_id": <string>, "user_name": <string>, + "wallet_name": <string>,"discord_id": <string>} +
+ Returns 201 CREATED (application/json) +
+ {"id": <string>, "name": <string>, "admin": + <string>, "discord_id": <string>} +
Curl example
+ curl -X POST {{ request.base_url }}discordbot/api/v1/users -d + '{"admin_id": "{{ user.id }}", "wallet_name": <string>, + "user_name": <string>, "discord_id": <string>}' -H "X-Api-Key: {{ + user.wallets[0].inkey }}" -H "Content-type: application/json" + +
+
+
+ + + + POST + /discordbot/api/v1/wallets +
Headers
+ {"X-Api-Key": <string>, "Content-type": + "application/json"} +
+ Body (application/json) - "admin_id" is a YOUR user ID +
+ {"user_id": <string>, "wallet_name": <string>, + "admin_id": <string>} +
+ Returns 201 CREATED (application/json) +
+ {"id": <string>, "admin": <string>, "name": + <string>, "user": <string>, "adminkey": <string>, + "inkey": <string>} +
Curl example
+ curl -X POST {{ request.base_url }}discordbot/api/v1/wallets -d + '{"user_id": <string>, "wallet_name": <string>, + "admin_id": "{{ user.id }}"}' -H "X-Api-Key: {{ user.wallets[0].inkey + }}" -H "Content-type: application/json" + +
+
+
+ + + + DELETE + /discordbot/api/v1/users/<user_id> +
Headers
+ {"X-Api-Key": <string>} +
Curl example
+ curl -X DELETE {{ request.base_url + }}discordbot/api/v1/users/<user_id> -H "X-Api-Key: {{ + user.wallets[0].inkey }}" + +
+
+
+ + + + DELETE + /discordbot/api/v1/wallets/<wallet_id> +
Headers
+ {"X-Api-Key": <string>} +
Curl example
+ curl -X DELETE {{ request.base_url + }}discordbot/api/v1/wallets/<wallet_id> -H "X-Api-Key: {{ + user.wallets[0].inkey }}" + +
+
+
+ + + + POST + /discordbot/api/v1/extensions +
Headers
+ {"X-Api-Key": <string>} +
Curl example
+ curl -X POST {{ request.base_url }}discordbot/api/v1/extensions -d + '{"userid": <string>, "extension": <string>, "active": + <integer>}' -H "X-Api-Key: {{ user.wallets[0].inkey }}" -H + "Content-type: application/json" + +
+
+
+
diff --git a/lnbits/extensions/discordbot/templates/discordbot/index.html b/lnbits/extensions/discordbot/templates/discordbot/index.html new file mode 100644 index 000000000..782f8bb61 --- /dev/null +++ b/lnbits/extensions/discordbot/templates/discordbot/index.html @@ -0,0 +1,464 @@ +{% extends "base.html" %} {% from "macros.jinja" import window_vars with context +%} {% block page %} +
+
+ + +
+ This extension is designed to be used through its API by a Discord Bot, + currently you have to install the bot + yourself
+ + Soon™ there will be a much easier one-click install discord bot... +
+
+ + + +
+
+
Users
+
+
+ Export to CSV +
+
+ + {% raw %} + + + {% endraw %} + +
+
+ + + +
+
+
Wallets
+
+
+ Export to CSV +
+
+ + {% raw %} + + + {% endraw %} + +
+
+
+ +
+ + +
LNbits Discord Bot Extension + +
+
+ + + {% include "discordbot/_api_docs.html" %} + +
+
+ + + + + + + + + Create User + Cancel + + + + + + + + + + + Create Wallet + Cancel + + + +
+{% endblock %} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} diff --git a/lnbits/extensions/discordbot/views.py b/lnbits/extensions/discordbot/views.py new file mode 100644 index 000000000..a5395e21f --- /dev/null +++ b/lnbits/extensions/discordbot/views.py @@ -0,0 +1,15 @@ +from fastapi import Request +from fastapi.params import Depends +from starlette.responses import HTMLResponse + +from lnbits.core.models import User +from lnbits.decorators import check_user_exists + +from . import discordbot_ext, discordbot_renderer + + +@discordbot_ext.get("/", response_class=HTMLResponse) +async def index(request: Request, user: User = Depends(check_user_exists)): + return discordbot_renderer().TemplateResponse( + "discordbot/index.html", {"request": request, "user": user.dict()} + ) diff --git a/lnbits/extensions/discordbot/views_api.py b/lnbits/extensions/discordbot/views_api.py new file mode 100644 index 000000000..64d1df1a7 --- /dev/null +++ b/lnbits/extensions/discordbot/views_api.py @@ -0,0 +1,127 @@ +from http import HTTPStatus + +from fastapi import Query +from fastapi.params import Depends +from starlette.exceptions import HTTPException + +from lnbits.core import update_user_extension +from lnbits.core.crud import get_user +from lnbits.decorators import WalletTypeInfo, get_key_type + +from . import discordbot_ext +from .crud import ( + create_discordbot_user, + create_discordbot_wallet, + delete_discordbot_user, + delete_discordbot_wallet, + get_discordbot_user, + get_discordbot_users, + get_discordbot_users_wallets, + get_discordbot_wallet, + get_discordbot_wallet_transactions, + get_discordbot_wallets, +) +from .models import CreateUserData, CreateUserWallet + +# Users + + +@discordbot_ext.get("/api/v1/users", status_code=HTTPStatus.OK) +async def api_discordbot_users(wallet: WalletTypeInfo = Depends(get_key_type)): + user_id = wallet.wallet.user + return [user.dict() for user in await get_discordbot_users(user_id)] + + +@discordbot_ext.get("/api/v1/users/{user_id}", status_code=HTTPStatus.OK) +async def api_discordbot_user(user_id, wallet: WalletTypeInfo = Depends(get_key_type)): + user = await get_discordbot_user(user_id) + return user.dict() + + +@discordbot_ext.post("/api/v1/users", status_code=HTTPStatus.CREATED) +async def api_discordbot_users_create( + data: CreateUserData, wallet: WalletTypeInfo = Depends(get_key_type) +): + user = await create_discordbot_user(data) + full = user.dict() + full["wallets"] = [ + wallet.dict() for wallet in await get_discordbot_users_wallets(user.id) + ] + return full + + +@discordbot_ext.delete("/api/v1/users/{user_id}") +async def api_discordbot_users_delete( + user_id, wallet: WalletTypeInfo = Depends(get_key_type) +): + user = await get_discordbot_user(user_id) + if not user: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." + ) + await delete_discordbot_user(user_id) + raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + + +# Activate Extension + + +@discordbot_ext.post("/api/v1/extensions") +async def api_discordbot_activate_extension( + extension: str = Query(...), userid: str = Query(...), active: bool = Query(...) +): + user = await get_user(userid) + if not user: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." + ) + update_user_extension(user_id=userid, extension=extension, active=active) + return {"extension": "updated"} + + +# Wallets + + +@discordbot_ext.post("/api/v1/wallets") +async def api_discordbot_wallets_create( + data: CreateUserWallet, wallet: WalletTypeInfo = Depends(get_key_type) +): + user = await create_discordbot_wallet( + user_id=data.user_id, wallet_name=data.wallet_name, admin_id=data.admin_id + ) + return user.dict() + + +@discordbot_ext.get("/api/v1/wallets") +async def api_discordbot_wallets(wallet: WalletTypeInfo = Depends(get_key_type)): + admin_id = wallet.wallet.user + return [wallet.dict() for wallet in await get_discordbot_wallets(admin_id)] + + +@discordbot_ext.get("/api/v1/transactions/{wallet_id}") +async def api_discordbot_wallet_transactions( + wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) +): + return await get_discordbot_wallet_transactions(wallet_id) + + +@discordbot_ext.get("/api/v1/wallets/{user_id}") +async def api_discordbot_users_wallets( + user_id, wallet: WalletTypeInfo = Depends(get_key_type) +): + return [ + s_wallet.dict() for s_wallet in await get_discordbot_users_wallets(user_id) + ] + + +@discordbot_ext.delete("/api/v1/wallets/{wallet_id}") +async def api_discordbot_wallets_delete( + wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) +): + get_wallet = await get_discordbot_wallet(wallet_id) + if not get_wallet: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." + ) + await delete_discordbot_wallet(wallet_id, get_wallet.user) + raise HTTPException(status_code=HTTPStatus.NO_CONTENT)

+ Connect your LNbits instance to a Discord Bot leveraging LNbits as a community based lightning node.
+ + Created by, Chris Lennon
+ + Based on User Manager, by Ben Arc +