WIP: Guilds and Wallets
This commit is contained in:
parent
65b0e30c75
commit
bf6ca24eed
40
api/extensions/guild.py
Normal file
40
api/extensions/guild.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import logging
|
||||||
|
from logging import Logger
|
||||||
|
|
||||||
|
from fastapi import HTTPException, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from api.app import app
|
||||||
|
from classes import PycordGuild
|
||||||
|
from classes.errors import WalletNotFoundError, GuildNotFoundError
|
||||||
|
from classes.wallet import Wallet
|
||||||
|
|
||||||
|
logger: Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/v1/guilds/{guild_id}", response_class=JSONResponse)
|
||||||
|
async def get_guild_wallet(guild_id: int):
|
||||||
|
try:
|
||||||
|
guild: PycordGuild = await PycordGuild.from_id(guild_id, allow_creation=False)
|
||||||
|
except GuildNotFoundError as exc:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND, detail="Guild not found"
|
||||||
|
) from exc
|
||||||
|
except NotImplementedError as exc:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Not implemented"
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
return guild.to_dict(json_compatible=True)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/v1/guilds/{guild_id}/wallets/{user_id}", response_class=JSONResponse)
|
||||||
|
async def get_guild_wallet(guild_id: int, user_id: int):
|
||||||
|
try:
|
||||||
|
wallet: Wallet = await Wallet.from_id(user_id, guild_id, allow_creation=False)
|
||||||
|
except WalletNotFoundError as exc:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND, detail="Wallet not found"
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
return wallet.to_dict(json_compatible=True)
|
23
api/extensions/user.py
Normal file
23
api/extensions/user.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import logging
|
||||||
|
from logging import Logger
|
||||||
|
|
||||||
|
from fastapi import HTTPException, status
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from api.app import app
|
||||||
|
from classes import PycordUser
|
||||||
|
from classes.errors import UserNotFoundError
|
||||||
|
|
||||||
|
logger: Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/v1/users/{user_id}", response_class=JSONResponse)
|
||||||
|
async def get_user(user_id: int):
|
||||||
|
try:
|
||||||
|
user: PycordUser = await PycordUser.from_id(user_id, allow_creation=False)
|
||||||
|
except UserNotFoundError as exc:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND, detail="User not found"
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
return user.to_dict(json_compatible=True)
|
@ -1,9 +1,13 @@
|
|||||||
|
import logging
|
||||||
|
from logging import Logger
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
|
|
||||||
from api.app import app
|
from api.app import app
|
||||||
|
|
||||||
|
logger: Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/favicon.ico", response_class=FileResponse, include_in_schema=False)
|
@app.get("/favicon.ico", response_class=FileResponse, include_in_schema=False)
|
||||||
async def favicon():
|
async def favicon():
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from .pycord_guild import PycordGuild
|
from .pycord_guild import PycordGuild
|
||||||
from .pycord_guild_colors import PycordGuildColors
|
from .pycord_guild_colors import PycordGuildColors
|
||||||
from .pycord_user import PycordUser
|
from .pycord_user import PycordUser
|
||||||
from .wallet import Wallet
|
|
||||||
|
# from .wallet import Wallet
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from .pycord_guild import GuildNotFoundError
|
||||||
from .pycord_user import UserNotFoundError
|
from .pycord_user import UserNotFoundError
|
||||||
from .wallet import (
|
from .wallet import (
|
||||||
WalletBalanceLimitExceeded,
|
WalletBalanceLimitExceeded,
|
||||||
|
7
classes/errors/pycord_guild.py
Normal file
7
classes/errors/pycord_guild.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
class GuildNotFoundError(Exception):
|
||||||
|
"""PycordGuild could not find guild with such an ID in the database"""
|
||||||
|
|
||||||
|
def __init__(self, guild_id: int) -> None:
|
||||||
|
self.guild_id = guild_id
|
||||||
|
|
||||||
|
super().__init__(f"Guild with id {self.guild_id} was not found")
|
@ -1,6 +1,8 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
|
from libbot.cache.classes import Cache
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -10,3 +12,36 @@ class PycordGuild:
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def from_id(
|
||||||
|
cls, guild_id: int, allow_creation: bool = True, cache: Optional[Cache] = None
|
||||||
|
) -> "PycordGuild":
|
||||||
|
"""Find guild in database and create new record if guild does not exist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
guild_id (int): User's Discord ID
|
||||||
|
allow_creation (:obj:`bool`, optional): Create new guild record if none found in the database
|
||||||
|
cache (:obj:`Cache`, optional): Cache engine to get the cache from
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PycordGuild: User object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GuildNotFoundError: User was not found and creation was not allowed
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def to_dict(self, json_compatible: bool = False) -> Dict[str, Any]:
|
||||||
|
"""Convert PycordGuild object to a JSON representation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
json_compatible (bool): Whether the JSON-incompatible objects like ObjectId need to be converted
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Any]: JSON representation of PycordGuild
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"_id": self._id if not json_compatible else str(self._id),
|
||||||
|
"id": self.id,
|
||||||
|
}
|
||||||
|
@ -7,8 +7,8 @@ from bson import ObjectId
|
|||||||
from libbot.cache.classes import Cache
|
from libbot.cache.classes import Cache
|
||||||
from pymongo.results import InsertOneResult
|
from pymongo.results import InsertOneResult
|
||||||
|
|
||||||
from classes import Wallet
|
|
||||||
from classes.errors.pycord_user import UserNotFoundError
|
from classes.errors.pycord_user import UserNotFoundError
|
||||||
|
from classes.wallet import Wallet
|
||||||
from modules.database import col_users
|
from modules.database import col_users
|
||||||
|
|
||||||
logger: Logger = logging.getLogger(__name__)
|
logger: Logger = logging.getLogger(__name__)
|
||||||
@ -63,9 +63,17 @@ class PycordUser:
|
|||||||
|
|
||||||
return cls(**db_entry)
|
return cls(**db_entry)
|
||||||
|
|
||||||
def _to_dict(self) -> Dict[str, Any]:
|
def to_dict(self, json_compatible: bool = False) -> Dict[str, Any]:
|
||||||
|
"""Convert PycordUser object to a JSON representation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
json_compatible (bool): Whether the JSON-incompatible objects like ObjectId need to be converted
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Any]: JSON representation of PycordUser
|
||||||
|
"""
|
||||||
return {
|
return {
|
||||||
"_id": self._id,
|
"_id": self._id if not json_compatible else str(self._id),
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +125,7 @@ class PycordUser:
|
|||||||
if cache is None:
|
if cache is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
user_dict: Dict[str, Any] = self._to_dict()
|
user_dict: Dict[str, Any] = self.to_dict()
|
||||||
|
|
||||||
if user_dict is not None:
|
if user_dict is not None:
|
||||||
cache.set_json(self._get_cache_key(), user_dict)
|
cache.set_json(self._get_cache_key(), user_dict)
|
||||||
|
@ -7,12 +7,12 @@ from typing import Any, Dict, Optional
|
|||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
from pymongo.results import InsertOneResult
|
from pymongo.results import InsertOneResult
|
||||||
|
|
||||||
from classes.errors import (
|
from classes.errors.wallet import (
|
||||||
WalletBalanceLimitExceeded,
|
WalletBalanceLimitExceeded,
|
||||||
WalletNotFoundError,
|
WalletNotFoundError,
|
||||||
WalletOverdraftLimitExceeded,
|
WalletOverdraftLimitExceeded,
|
||||||
|
WalletInsufficientFunds,
|
||||||
)
|
)
|
||||||
from classes.errors.wallet import WalletInsufficientFunds
|
|
||||||
from modules.database import col_wallets
|
from modules.database import col_wallets
|
||||||
|
|
||||||
logger: Logger = logging.getLogger(__name__)
|
logger: Logger = logging.getLogger(__name__)
|
||||||
@ -46,9 +46,17 @@ class Wallet:
|
|||||||
|
|
||||||
return cls(**db_entry)
|
return cls(**db_entry)
|
||||||
|
|
||||||
def _to_dict(self) -> Dict[str, Any]:
|
def to_dict(self, json_compatible: bool = False) -> Dict[str, Any]:
|
||||||
|
"""Convert Wallet object to a JSON representation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
json_compatible (bool): Whether the JSON-incompatible objects like ObjectId need to be converted
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Any]: JSON representation of Wallet
|
||||||
|
"""
|
||||||
return {
|
return {
|
||||||
"_id": self._id,
|
"_id": self._id if not json_compatible else str(self._id),
|
||||||
"owner_id": self.owner_id,
|
"owner_id": self.owner_id,
|
||||||
"guild_id": self.guild_id,
|
"guild_id": self.guild_id,
|
||||||
"balance": self.balance,
|
"balance": self.balance,
|
||||||
|
27
cli.py
Normal file
27
cli.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import logging
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from logging import Logger
|
||||||
|
|
||||||
|
from modules.migrator import migrate_database
|
||||||
|
|
||||||
|
logger: Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
parser = ArgumentParser(
|
||||||
|
prog="Javelina",
|
||||||
|
description="Discord bot for community management.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument("--migrate", action="store_true")
|
||||||
|
parser.add_argument("--only-api", action="store_true")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if args.migrate:
|
||||||
|
logger.info("Performing migrations...")
|
||||||
|
migrate_database()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
5
cogs/wallet.py
Normal file
5
cogs/wallet.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from classes.pycord_bot import PycordBot
|
||||||
|
|
||||||
|
|
||||||
|
def setup(client: PycordBot) -> None:
|
||||||
|
pass
|
18
main.py
18
main.py
@ -1,23 +1,31 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
|
from logging import Logger
|
||||||
from os import getpid
|
from os import getpid
|
||||||
|
|
||||||
from libbot.utils import config_get
|
from libbot.utils import config_get
|
||||||
|
|
||||||
|
# Import required for uvicorn
|
||||||
|
from api.app import app # noqa
|
||||||
from classes.pycord_bot import PycordBot
|
from classes.pycord_bot import PycordBot
|
||||||
from modules.extensions_loader import dynamic_import_from_src
|
from modules.extensions_loader import dynamic_import_from_src
|
||||||
from modules.scheduler import scheduler
|
from modules.scheduler import scheduler
|
||||||
|
|
||||||
# Import required for uvicorn
|
|
||||||
from api.app import app
|
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.DEBUG if config_get("debug") else logging.INFO,
|
level=logging.DEBUG if config_get("debug") else logging.INFO,
|
||||||
format="%(name)s.%(funcName)s | %(levelname)s | %(message)s",
|
format="%(name)s.%(funcName)s | %(levelname)s | %(message)s",
|
||||||
datefmt="[%X]",
|
datefmt="[%X]",
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger: Logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Try to import the module that improves performance
|
||||||
|
# and ignore errors when module is not installed
|
||||||
|
with contextlib.suppress(ImportError):
|
||||||
|
import uvloop
|
||||||
|
|
||||||
|
uvloop.install()
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
@ -26,7 +34,7 @@ async def main():
|
|||||||
bot.load_extension("cogs")
|
bot.load_extension("cogs")
|
||||||
|
|
||||||
# Import API modules
|
# Import API modules
|
||||||
dynamic_import_from_src("api.extensions", star_import=True)
|
dynamic_import_from_src("api/extensions", star_import=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await bot.start(config_get("bot_token", "bot"))
|
await bot.start(config_get("bot_token", "bot"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user