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 00000000..d5820662 --- /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 00000000..a1408317 --- /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 00000000..ff60dd62 --- /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 00000000..eb674122 --- /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 00000000..5661fcb4 --- /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 00000000..ababfd7a --- /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 00000000..4be367f8 --- /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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 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 00000000..40fcfb12 --- /dev/null +++ b/lnbits/extensions/discordbot/templates/discordbot/_api_docs.html @@ -0,0 +1,260 @@ + + + +
+ Discord Bot: Connect Discord users to LNbits. +
+

+ 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 +

+
+
+
+ + + + + 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 00000000..782f8bb6 --- /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 00000000..a5395e21 --- /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 00000000..64d1df1a --- /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)