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
This commit is contained in:
parent
8dbe1b3678
commit
0c089109b9
12 changed files with 1131 additions and 0 deletions
11
lnbits/extensions/discordbot/Pipfile
Normal file
11
lnbits/extensions/discordbot/Pipfile
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[[source]]
|
||||||
|
url = "https://pypi.python.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.9"
|
||||||
34
lnbits/extensions/discordbot/README.md
Normal file
34
lnbits/extensions/discordbot/README.md
Normal file
|
|
@ -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)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`/balance` Will show the balance of the users wallet.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`/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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`/payme [amount] [description]` Will open an invoice that can be paid by any user
|
||||||
|
|
||||||
|

|
||||||
25
lnbits/extensions/discordbot/__init__.py
Normal file
25
lnbits/extensions/discordbot/__init__.py
Normal file
|
|
@ -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
|
||||||
6
lnbits/extensions/discordbot/config.json
Normal file
6
lnbits/extensions/discordbot/config.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "Discord Bot",
|
||||||
|
"short_description": "Generate users and wallets",
|
||||||
|
"icon": "person_add",
|
||||||
|
"contributors": ["bitcoingamer21"]
|
||||||
|
}
|
||||||
123
lnbits/extensions/discordbot/crud.py
Normal file
123
lnbits/extensions/discordbot/crud.py
Normal file
|
|
@ -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,))
|
||||||
30
lnbits/extensions/discordbot/migrations.py
Normal file
30
lnbits/extensions/discordbot/migrations.py
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
36
lnbits/extensions/discordbot/models.py
Normal file
36
lnbits/extensions/discordbot/models.py
Normal file
|
|
@ -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))
|
||||||
BIN
lnbits/extensions/discordbot/static/stack.png
Normal file
BIN
lnbits/extensions/discordbot/static/stack.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
260
lnbits/extensions/discordbot/templates/discordbot/_api_docs.html
Normal file
260
lnbits/extensions/discordbot/templates/discordbot/_api_docs.html
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
<q-expansion-item
|
||||||
|
group="extras"
|
||||||
|
icon="swap_vertical_circle"
|
||||||
|
label="Info"
|
||||||
|
:content-inset-level="0.5"
|
||||||
|
>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<h5 class="text-subtitle1 q-my-none">
|
||||||
|
Discord Bot: Connect Discord users to LNbits.
|
||||||
|
</h5>
|
||||||
|
<p>
|
||||||
|
Connect your LNbits instance to a <a href="https://github.com/chrislennon/lnbits-discord-bot">Discord Bot</a> leveraging LNbits as a community based lightning node.<br />
|
||||||
|
<small>
|
||||||
|
Created by, <a href="https://github.com/chrislennon">Chris Lennon</a></small
|
||||||
|
> <br />
|
||||||
|
<small>
|
||||||
|
Based on User Manager, by <a href="https://github.com/benarc">Ben Arc</a></small
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item
|
||||||
|
group="extras"
|
||||||
|
icon="swap_vertical_circle"
|
||||||
|
label="API info"
|
||||||
|
:content-inset-level="0.5"
|
||||||
|
>
|
||||||
|
<q-expansion-item group="api" dense expand-separator label="GET users">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-light-blue">GET</span>
|
||||||
|
/discordbot/api/v1/users</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Returns 201 CREATED (application/json)
|
||||||
|
</h5>
|
||||||
|
<code>JSON list of users</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>curl -X GET {{ request.base_url }}discordbot/api/v1/users -H
|
||||||
|
"X-Api-Key: {{ user.wallets[0].inkey }}"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item group="api" dense expand-separator label="GET user">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-light-blue">GET</span>
|
||||||
|
/discordbot/api/v1/users/<user_id></code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Returns 201 CREATED (application/json)
|
||||||
|
</h5>
|
||||||
|
<code>JSON list of users</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>curl -X GET {{ request.base_url
|
||||||
|
}}discordbot/api/v1/users/<user_id> -H "X-Api-Key: {{
|
||||||
|
user.wallets[0].inkey }}"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item group="api" dense expand-separator label="GET wallets">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-light-blue">GET</span>
|
||||||
|
/discordbot/api/v1/wallets/<user_id></code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
|
<code>{"X-Api-Key": <string>}</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Returns 201 CREATED (application/json)
|
||||||
|
</h5>
|
||||||
|
<code>JSON wallet data</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>curl -X GET {{ request.base_url
|
||||||
|
}}discordbot/api/v1/wallets/<user_id> -H "X-Api-Key: {{
|
||||||
|
user.wallets[0].inkey }}"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item group="api" dense expand-separator label="GET transactions">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-light-blue">GET</span>
|
||||||
|
/discordbot/api/v1/wallets<wallet_id></code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
|
<code>{"X-Api-Key": <string>}</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Returns 201 CREATED (application/json)
|
||||||
|
</h5>
|
||||||
|
<code>JSON a wallets transactions</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>curl -X GET {{ request.base_url
|
||||||
|
}}discordbot/api/v1/wallets<wallet_id> -H "X-Api-Key: {{
|
||||||
|
user.wallets[0].inkey }}"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item
|
||||||
|
group="api"
|
||||||
|
dense
|
||||||
|
expand-separator
|
||||||
|
label="POST user + initial wallet"
|
||||||
|
>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-light-green">POST</span>
|
||||||
|
/discordbot/api/v1/users</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
|
<code
|
||||||
|
>{"X-Api-Key": <string>, "Content-type":
|
||||||
|
"application/json"}</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Body (application/json) - "admin_id" is a YOUR user ID
|
||||||
|
</h5>
|
||||||
|
<code
|
||||||
|
>{"admin_id": <string>, "user_name": <string>,
|
||||||
|
"wallet_name": <string>,"discord_id": <string>}</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Returns 201 CREATED (application/json)
|
||||||
|
</h5>
|
||||||
|
<code
|
||||||
|
>{"id": <string>, "name": <string>, "admin":
|
||||||
|
<string>, "discord_id": <string>}</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>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"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item group="api" dense expand-separator label="POST wallet">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-light-green">POST</span>
|
||||||
|
/discordbot/api/v1/wallets</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
|
<code
|
||||||
|
>{"X-Api-Key": <string>, "Content-type":
|
||||||
|
"application/json"}</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Body (application/json) - "admin_id" is a YOUR user ID
|
||||||
|
</h5>
|
||||||
|
<code
|
||||||
|
>{"user_id": <string>, "wallet_name": <string>,
|
||||||
|
"admin_id": <string>}</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
|
Returns 201 CREATED (application/json)
|
||||||
|
</h5>
|
||||||
|
<code
|
||||||
|
>{"id": <string>, "admin": <string>, "name":
|
||||||
|
<string>, "user": <string>, "adminkey": <string>,
|
||||||
|
"inkey": <string>}</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>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"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item
|
||||||
|
group="api"
|
||||||
|
dense
|
||||||
|
expand-separator
|
||||||
|
label="DELETE user and their wallets"
|
||||||
|
>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-red">DELETE</span>
|
||||||
|
/discordbot/api/v1/users/<user_id></code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
|
<code>{"X-Api-Key": <string>}</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>curl -X DELETE {{ request.base_url
|
||||||
|
}}discordbot/api/v1/users/<user_id> -H "X-Api-Key: {{
|
||||||
|
user.wallets[0].inkey }}"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item group="api" dense expand-separator label="DELETE wallet">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-red">DELETE</span>
|
||||||
|
/discordbot/api/v1/wallets/<wallet_id></code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
|
<code>{"X-Api-Key": <string>}</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>curl -X DELETE {{ request.base_url
|
||||||
|
}}discordbot/api/v1/wallets/<wallet_id> -H "X-Api-Key: {{
|
||||||
|
user.wallets[0].inkey }}"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
<q-expansion-item
|
||||||
|
group="api"
|
||||||
|
dense
|
||||||
|
expand-separator
|
||||||
|
label="POST activate extension"
|
||||||
|
>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<code
|
||||||
|
><span class="text-green">POST</span>
|
||||||
|
/discordbot/api/v1/extensions</code
|
||||||
|
>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
|
<code>{"X-Api-Key": <string>}</code>
|
||||||
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
|
<code
|
||||||
|
>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"
|
||||||
|
</code>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-expansion-item>
|
||||||
|
</q-expansion-item>
|
||||||
464
lnbits/extensions/discordbot/templates/discordbot/index.html
Normal file
464
lnbits/extensions/discordbot/templates/discordbot/index.html
Normal file
|
|
@ -0,0 +1,464 @@
|
||||||
|
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
|
||||||
|
%} {% block page %}
|
||||||
|
<div class="row q-col-gutter-md">
|
||||||
|
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<center><img src="/discordbot/static/stack.png" height="200" /></center>
|
||||||
|
This extension is designed to be used through its API by a Discord Bot,
|
||||||
|
currently you have to install the bot
|
||||||
|
<a
|
||||||
|
href="https://github.com/chrislennon/lnbits-discord-bot/#installation"
|
||||||
|
>yourself</a
|
||||||
|
><br />
|
||||||
|
|
||||||
|
Soon™ there will be a much easier one-click install discord bot...
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<h5 class="text-subtitle1 q-my-none">Users</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<q-btn flat color="grey" @click="exportUsersCSV"
|
||||||
|
>Export to CSV</q-btn
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<q-table
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
:data="users"
|
||||||
|
row-key="id"
|
||||||
|
:columns="usersTable.columns"
|
||||||
|
:pagination.sync="usersTable.pagination"
|
||||||
|
>
|
||||||
|
{% raw %}
|
||||||
|
<template v-slot:header="props">
|
||||||
|
<q-tr :props="props">
|
||||||
|
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
|
{{ col.label }}
|
||||||
|
</q-th>
|
||||||
|
<q-th auto-width></q-th>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
<template v-slot:body="props">
|
||||||
|
<q-tr :props="props">
|
||||||
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
|
{{ col.value }}
|
||||||
|
</q-td>
|
||||||
|
<q-td auto-width>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
size="xs"
|
||||||
|
@click="deleteUser(props.row.id)"
|
||||||
|
icon="cancel"
|
||||||
|
color="pink"
|
||||||
|
></q-btn>
|
||||||
|
</q-td>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
{% endraw %}
|
||||||
|
</q-table>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
|
<div class="col">
|
||||||
|
<h5 class="text-subtitle1 q-my-none">Wallets</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<q-btn flat color="grey" @click="exportWalletsCSV"
|
||||||
|
>Export to CSV</q-btn
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<q-table
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
:data="wallets"
|
||||||
|
row-key="id"
|
||||||
|
:columns="walletsTable.columns"
|
||||||
|
:pagination.sync="walletsTable.pagination"
|
||||||
|
>
|
||||||
|
{% raw %}
|
||||||
|
<template v-slot:header="props">
|
||||||
|
<q-tr :props="props">
|
||||||
|
<q-th auto-width></q-th>
|
||||||
|
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
|
{{ col.label }}
|
||||||
|
</q-th>
|
||||||
|
<q-th auto-width></q-th>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
<template v-slot:body="props">
|
||||||
|
<q-tr :props="props">
|
||||||
|
<q-td auto-width>
|
||||||
|
<q-btn
|
||||||
|
unelevated
|
||||||
|
dense
|
||||||
|
size="xs"
|
||||||
|
icon="account_balance_wallet"
|
||||||
|
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||||
|
type="a"
|
||||||
|
:href="props.row.walllink"
|
||||||
|
target="_blank"
|
||||||
|
></q-btn>
|
||||||
|
<q-tooltip> Link to wallet </q-tooltip>
|
||||||
|
</q-td>
|
||||||
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
|
{{ col.value }}
|
||||||
|
</q-td>
|
||||||
|
<q-td auto-width>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
size="xs"
|
||||||
|
@click="deleteWallet(props.row.id)"
|
||||||
|
icon="cancel"
|
||||||
|
color="pink"
|
||||||
|
></q-btn>
|
||||||
|
</q-td>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
{% endraw %}
|
||||||
|
</q-table>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-4 col-lg-5 q-gutter-y-md">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<h6 class="text-subtitle1 q-my-none">LNbits Discord Bot Extension
|
||||||
|
<!--{{SITE_TITLE}} Discord Bot Extension-->
|
||||||
|
</h6>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-pa-none">
|
||||||
|
<q-separator></q-separator>
|
||||||
|
<q-list> {% include "discordbot/_api_docs.html" %} </q-list>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-dialog v-model="userDialog.show" position="top">
|
||||||
|
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
||||||
|
<q-form @submit="sendUserFormData" class="q-gutter-md">
|
||||||
|
<q-input
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
v-model.trim="userDialog.data.usrname"
|
||||||
|
label="Username"
|
||||||
|
></q-input>
|
||||||
|
<q-input
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
v-model.trim="userDialog.data.walname"
|
||||||
|
label="Initial wallet name"
|
||||||
|
></q-input>
|
||||||
|
<q-input
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
v-model.trim="userDialog.data.discord_id"
|
||||||
|
label="Discord ID"
|
||||||
|
></q-input>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
unelevated
|
||||||
|
color="primary"
|
||||||
|
:disable="userDialog.data.walname == null"
|
||||||
|
type="submit"
|
||||||
|
>Create User</q-btn
|
||||||
|
>
|
||||||
|
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||||
|
</q-form>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
|
<q-dialog v-model="walletDialog.show" position="top">
|
||||||
|
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
||||||
|
<q-form @submit="sendWalletFormData" class="q-gutter-md">
|
||||||
|
<q-select
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
emit-value
|
||||||
|
v-model="walletDialog.data.user"
|
||||||
|
:options="userOptions"
|
||||||
|
label="User *"
|
||||||
|
>
|
||||||
|
</q-select>
|
||||||
|
<q-input
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
v-model.trim="walletDialog.data.walname"
|
||||||
|
label="Wallet name"
|
||||||
|
></q-input>
|
||||||
|
<q-btn
|
||||||
|
unelevated
|
||||||
|
color="primary"
|
||||||
|
:disable="walletDialog.data.walname == null"
|
||||||
|
type="submit"
|
||||||
|
>Create Wallet</q-btn
|
||||||
|
>
|
||||||
|
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||||
|
</q-form>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</div>
|
||||||
|
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||||
|
<script>
|
||||||
|
var mapUserManager = function (obj) {
|
||||||
|
obj.date = Quasar.utils.date.formatDate(
|
||||||
|
new Date(obj.time * 1000),
|
||||||
|
'YYYY-MM-DD HH:mm'
|
||||||
|
)
|
||||||
|
obj.fsat = new Intl.NumberFormat(LOCALE).format(obj.amount)
|
||||||
|
obj.walllink = ['../wallet?usr=', obj.user, '&wal=', obj.id].join('')
|
||||||
|
obj._data = _.clone(obj)
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
el: '#vue',
|
||||||
|
mixins: [windowMixin],
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
wallets: [],
|
||||||
|
users: [],
|
||||||
|
|
||||||
|
usersTable: {
|
||||||
|
columns: [
|
||||||
|
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
||||||
|
{name: 'name', align: 'left', label: 'Username', field: 'name'},
|
||||||
|
{name: 'discord_id', align: 'left', label: 'discord_id', field: 'discord_id'}
|
||||||
|
],
|
||||||
|
pagination: {
|
||||||
|
rowsPerPage: 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
walletsTable: {
|
||||||
|
columns: [
|
||||||
|
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
||||||
|
{name: 'name', align: 'left', label: 'Name', field: 'name'},
|
||||||
|
{name: 'user', align: 'left', label: 'User', field: 'user'},
|
||||||
|
{
|
||||||
|
name: 'adminkey',
|
||||||
|
align: 'left',
|
||||||
|
label: 'Admin Key',
|
||||||
|
field: 'adminkey'
|
||||||
|
},
|
||||||
|
{name: 'inkey', align: 'left', label: 'Invoice Key', field: 'inkey'}
|
||||||
|
],
|
||||||
|
pagination: {
|
||||||
|
rowsPerPage: 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
walletDialog: {
|
||||||
|
show: false,
|
||||||
|
data: {}
|
||||||
|
},
|
||||||
|
userDialog: {
|
||||||
|
show: false,
|
||||||
|
data: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
userOptions: function () {
|
||||||
|
return this.users.map(function (obj) {
|
||||||
|
console.log(obj.id)
|
||||||
|
return {
|
||||||
|
value: String(obj.id),
|
||||||
|
label: String(obj.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
///////////////Users////////////////////////////
|
||||||
|
|
||||||
|
getUsers: function () {
|
||||||
|
var self = this
|
||||||
|
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/discordbot/api/v1/users',
|
||||||
|
this.g.user.wallets[0].inkey
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
self.users = response.data.map(function (obj) {
|
||||||
|
return mapUserManager(obj)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
openUserUpdateDialog: function (linkId) {
|
||||||
|
var link = _.findWhere(this.users, {id: linkId})
|
||||||
|
|
||||||
|
this.userDialog.data = _.clone(link._data)
|
||||||
|
this.userDialog.show = true
|
||||||
|
},
|
||||||
|
sendUserFormData: function () {
|
||||||
|
if (this.userDialog.data.id) {
|
||||||
|
} else {
|
||||||
|
var data = {
|
||||||
|
admin_id: this.g.user.id,
|
||||||
|
user_name: this.userDialog.data.usrname,
|
||||||
|
wallet_name: this.userDialog.data.walname,
|
||||||
|
discord_id: this.userDialog.data.discord_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
this.createUser(data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createUser: function (data) {
|
||||||
|
var self = this
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'POST',
|
||||||
|
'/discordbot/api/v1/users',
|
||||||
|
this.g.user.wallets[0].inkey,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
self.users.push(mapUserManager(response.data))
|
||||||
|
self.userDialog.show = false
|
||||||
|
self.userDialog.data = {}
|
||||||
|
data = {}
|
||||||
|
self.getWallets()
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteUser: function (userId) {
|
||||||
|
var self = this
|
||||||
|
|
||||||
|
console.log(userId)
|
||||||
|
LNbits.utils
|
||||||
|
.confirmDialog('Are you sure you want to delete this User link?')
|
||||||
|
.onOk(function () {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'DELETE',
|
||||||
|
'/discordbot/api/v1/users/' + userId,
|
||||||
|
self.g.user.wallets[0].inkey
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
self.users = _.reject(self.users, function (obj) {
|
||||||
|
return obj.id == userId
|
||||||
|
})
|
||||||
|
self.getWallets()
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
exportUsersCSV: function () {
|
||||||
|
LNbits.utils.exportCSV(this.usersTable.columns, this.users)
|
||||||
|
},
|
||||||
|
|
||||||
|
///////////////Wallets////////////////////////////
|
||||||
|
|
||||||
|
getWallets: function () {
|
||||||
|
var self = this
|
||||||
|
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/discordbot/api/v1/wallets',
|
||||||
|
this.g.user.wallets[0].inkey
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
self.wallets = response.data.map(function (obj) {
|
||||||
|
return mapUserManager(obj)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openWalletUpdateDialog: function (linkId) {
|
||||||
|
var link = _.findWhere(this.users, {id: linkId})
|
||||||
|
|
||||||
|
this.walletDialog.data = _.clone(link._data)
|
||||||
|
this.walletDialog.show = true
|
||||||
|
},
|
||||||
|
sendWalletFormData: function () {
|
||||||
|
if (this.walletDialog.data.id) {
|
||||||
|
} else {
|
||||||
|
var data = {
|
||||||
|
user_id: this.walletDialog.data.user,
|
||||||
|
admin_id: this.g.user.id,
|
||||||
|
wallet_name: this.walletDialog.data.walname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
this.createWallet(data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createWallet: function (data) {
|
||||||
|
var self = this
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'POST',
|
||||||
|
'/discordbot/api/v1/wallets',
|
||||||
|
this.g.user.wallets[0].inkey,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
self.wallets.push(mapUserManager(response.data))
|
||||||
|
self.walletDialog.show = false
|
||||||
|
self.walletDialog.data = {}
|
||||||
|
data = {}
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteWallet: function (userId) {
|
||||||
|
var self = this
|
||||||
|
|
||||||
|
LNbits.utils
|
||||||
|
.confirmDialog('Are you sure you want to delete this wallet link?')
|
||||||
|
.onOk(function () {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'DELETE',
|
||||||
|
'/discordbot/api/v1/wallets/' + userId,
|
||||||
|
self.g.user.wallets[0].inkey
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
self.wallets = _.reject(self.wallets, function (obj) {
|
||||||
|
return obj.id == userId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
exportWalletsCSV: function () {
|
||||||
|
LNbits.utils.exportCSV(this.walletsTable.columns, this.wallets)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created: function () {
|
||||||
|
if (this.g.user.wallets.length) {
|
||||||
|
this.getUsers()
|
||||||
|
this.getWallets()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
15
lnbits/extensions/discordbot/views.py
Normal file
15
lnbits/extensions/discordbot/views.py
Normal file
|
|
@ -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()}
|
||||||
|
)
|
||||||
127
lnbits/extensions/discordbot/views_api.py
Normal file
127
lnbits/extensions/discordbot/views_api.py
Normal file
|
|
@ -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)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue