about summary refs log tree commit diff stats
path: root/discord
diff options
context:
space:
mode:
Diffstat (limited to 'discord')
-rw-r--r--discord/client.py14
-rw-r--r--discord/flags.py35
-rw-r--r--discord/intents.py56
-rw-r--r--discord/premium_type.py8
-rw-r--r--discord/user.py130
-rw-r--r--discord/utils/exceptions.py3
-rw-r--r--discord/utils/rest.py60
7 files changed, 262 insertions, 44 deletions
diff --git a/discord/client.py b/discord/client.py
index d272130..c725e3c 100644
--- a/discord/client.py
+++ b/discord/client.py
@@ -8,7 +8,8 @@ import zlib
 import websockets
 
 from .utils import EventEmitter
-from .intents import Intents, gen_number
+from .utils.rest import get
+from .intents import Intents, get_number
 from .user import User
 
 class GatewayEvents(IntEnum):
@@ -26,10 +27,17 @@ class GatewayEvents(IntEnum):
     HEARTBEAT_ACK      = 11
     GUILD_SYNC         = 12
 class Client:
+    _token: str
+
+    @property
+    async def user(self):
+        data = await get(self._token, '/users/@me')
+        return User(data)
+
     def __init__(self, intents: list[Intents]):
         self.gateway = None
         self.loop = asyncio.get_event_loop()
-        self.code: int = gen_number(intents)
+        self.code: int = get_number(intents)
         self.event_emitter = EventEmitter()
         self.buffer = bytearray()
         self.inflator = zlib.decompressobj()
@@ -37,7 +45,7 @@ class Client:
         self.token: str = None
         self.ready: bool = False
 
-    async def connect(self, token: str, intent_code: int):
+    async def connect(self):
         async with websockets.connect("wss://gateway.discord.gg/?v=10&encoding=json") as gateway:
             self.gateway = gateway
             threading.Thread(target=self.loop.run_forever).start()
diff --git a/discord/flags.py b/discord/flags.py
new file mode 100644
index 0000000..65a9253
--- /dev/null
+++ b/discord/flags.py
@@ -0,0 +1,35 @@
+from enum import Enum, unique
+
+
+@unique
+class Flags(Enum):
+    STAFF = 1
+    PARTNER = 2
+    HYPESQUAD = 4
+    BUG_HUNTER_LEVEL_1 = 8
+    HYPESQUAD_ONLINE_HOUSE_1 = 64
+    HYPESQUAD_ONLINE_HOUSE_2 = 128
+    HYPESQUAD_ONLINE_HOUSE_3 = 256
+    TEAM_PSUEDO_USER = 1024
+    BUG_HUNTER_LEVEL_2 = 16384
+    VERIFIED_BOT = 65536
+    VERIFIED_DEVELOPER = 131072
+    CERTIFIED_MODERATOR = 262144
+    BOT_HTTP_INTERACTIONS = 524288
+
+
+def get_number(flags: list[Flags]):
+    number = 1
+    for i in flags:
+        number += i.value
+    return number
+
+def get_flags(number: int):
+    flags = []
+    while number != 0:
+        for i in Flags:
+            if number >= i.value:
+                flags.append(i)
+                number -= i.value
+    return flags
+
diff --git a/discord/intents.py b/discord/intents.py
index 2e993ea..f538fb6 100644
--- a/discord/intents.py
+++ b/discord/intents.py
@@ -15,28 +15,28 @@ class Intents(Enum):
 
     See more at: https://discord.com/developers/docs/topics/gateway#gateway-intents
     """
-    GUILDS = 0
-    GUILD_MEMBERS = 1
-    GUILD_BANS = 2
-    GUILD_EMOJIS_AND_STICKERS = 3
-    GUILD_INTEGRATIONS = 4
-    GUILD_WEBHOOKS = 5
-    GUILD_INVITES = 6
-    GUILD_VOICE_STATES = 7
-    GUILD_PRESENCES = 8
-    GUILD_MESSAGES = 9
-    GUILD_MESSAGE_REACTIONS = 10
-    GUILD_MESSAGE_TYPING = 11
-    DIRECT_MESSAGES = 12
-    DIRECT_MESSAGE_REACTIONS = 13
-    DIRECT_MESSAGE_TYPING = 14
-    MESSAGE_CONTENT = 15
-    GUILD_SCHEDULED_EVENTS = 16
-    AUTO_MODERATION_CONFIGURATION = 20
-    AUTO_MODERATION_EXECUTION = 21
-
-
-def gen_number(intents: list[Intents]):
+    GUILDS = 1
+    GUILD_MEMBERS = 2
+    GUILD_BANS = 4
+    GUILD_EMOJIS_AND_STICKERS = 8
+    GUILD_INTEGRATIONS = 16
+    GUILD_WEBHOOKS = 32
+    GUILD_INVITES = 64
+    GUILD_VOICE_STATES = 128
+    GUILD_PRESENCES = 256
+    GUILD_MESSAGES = 512
+    GUILD_MESSAGE_REACTIONS = 1024
+    GUILD_MESSAGE_TYPING = 2048
+    DIRECT_MESSAGES = 4096
+    DIRECT_MESSAGE_REACTIONS = 8192
+    DIRECT_MESSAGE_TYPING = 16384
+    MESSAGE_CONTENT = 32768
+    GUILD_SCHEDULED_EVENTS = 65536
+    AUTO_MODERATION_CONFIGURATION = 1048576
+    AUTO_MODERATION_EXECUTION = 2097152
+
+
+def get_number(intents: list[Intents]):
     """
     Generates the number used to tell the gateway which intents are active.
 
@@ -48,5 +48,15 @@ def gen_number(intents: list[Intents]):
     """
     number = 1
     for i in intents:
-        number << i.value
+        number += i.value
     return number
+
+
+def get_intents(number: int):
+    intents = []
+    while number != 0:
+        for i in Intents:
+            if number >= i.value:
+                intents.append(i)
+                number -= i.value
+    return intents
diff --git a/discord/premium_type.py b/discord/premium_type.py
new file mode 100644
index 0000000..3549f92
--- /dev/null
+++ b/discord/premium_type.py
@@ -0,0 +1,8 @@
+from enum import Enum, unique
+
+
+@unique
+class PremiumType(Enum):
+    NONE = 0,
+    NITRO_CLASSIC = 1,
+    NITRO = 2
\ No newline at end of file
diff --git a/discord/user.py b/discord/user.py
index 16ddf1b..ff86c26 100644
--- a/discord/user.py
+++ b/discord/user.py
@@ -1,22 +1,116 @@
+from discord.flags import get_flags, Flags
+from discord.premium_type import PremiumType
+
+
 class User:
-    __slots__ = (
-        "id",
-        "username",
-        "discriminator",
-        "avatar",
-        "bot",
-        "system",
-        "mfa_enabled",
-        "banner",
-        "accent_color",
-        "locale",
-        "verified",
-        "email",
-        "flags",
-        "premium_type",
-        "public_flags"
-    )
+    _id: int
+    _username: str
+    _discriminator: str
+    _avatar: str
+    _bot: bool
+    _system: bool
+    _mfa_enabled: bool
+    _banner: str
+    _accent_color: int
+    _locale: str
+    _verified: bool
+    _email: str
+    _pronouns: str
+    _bio: str
+    _flags: list[Flags]
+    _premium_type: PremiumType
+    _public_flags: list[Flags]
+
+    @property
+    def id(self):
+        """The user's ID."""
+        return self._id
+
+    @property
+    def username(self):
+        """The user's username. This is not unique."""
+        return self._username
+
+    @property
+    def discriminator(self):
+        """The user's 4-digit tag."""
+        return self._discriminator
+
+    @property
+    def avatar(self):
+        """The user's avatar hash."""
+        return self._avatar
+
+    @property
+    def bot(self):
+        """Whether the user is a bot."""
+        return self._bot
+
+    @property
+    def pronouns(self):
+        """The user's pronouns (not yet implemented into Discord frontend)."""
+        return self._pronouns
+
+    @property
+    def bio(self):
+        """The contents of the user's About Me section."""
+        return self._bio
+
+    @property
+    def system(self):
+        """Whether the user is an Official Discord System user (for urgent messages)."""
+        return self._system
+
+    @property
+    def mfa_enabled(self):
+        """Whether the user has 2FA set up."""
+        return self._mfa_enabled
+
+    @property
+    def banner(self):
+        """The user's banner hash."""
+        return self._banner
+
+    @property
+    def accent_color(self):
+        """The user's banner color."""
+        return self._accent_color
+
+    @property
+    def locale(self):
+        """The user's chosen language."""
+        return self._locale
+
+    @property
+    def verified(self):
+        """Whether the email on the user's account is verified."""
+        return self._verified
+
+    @property
+    def email(self):
+        """The user's email."""
+        return self._email
+
+    @property
+    def flags(self):
+        """The flags on the user's account."""
+        return self._flags
+
+    @property
+    def premium_type(self):
+        """The type of Nitro subscription on a user's account."""
+        return self._premium_type
+
+    @property
+    def public_flags(self):
+        """The public flags on a user's account."""
+        return self._public_flags
 
     def __init__(self, data: dict):
         for k in data:
-            setattr(self, k, data[k])
+            if k == "flags" or k == "public_flags":
+                setattr(self, f"_{k}", get_flags(data[k]))
+            elif k == "premium_type":
+                setattr(self, f"_{k}", PremiumType(data[k]))
+            else:
+                setattr(self, f"_{k}", data[k])
diff --git a/discord/utils/exceptions.py b/discord/utils/exceptions.py
new file mode 100644
index 0000000..a7f035c
--- /dev/null
+++ b/discord/utils/exceptions.py
@@ -0,0 +1,3 @@
+class APIException(Exception):
+    """Raised when the Discord API returns an error."""
+
diff --git a/discord/utils/rest.py b/discord/utils/rest.py
new file mode 100644
index 0000000..f7f6ab8
--- /dev/null
+++ b/discord/utils/rest.py
@@ -0,0 +1,60 @@
+import aiohttp
+import asyncio
+
+from discord.utils.exceptions import APIException
+
+
+async def get(token, url):
+    async with aiohttp.ClientSession(headers={
+        "Authorization": f"Bot {token}",
+        "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)"
+    }) as session:
+        async with session.get(url='https://discord.com/api/v10' + url) as r:
+            data = await r.json()
+            match r.status:
+                case 200:
+                    return data
+                case other:
+                    raise APIException(data['message'])
+
+
+async def post(token, url, data):
+    async with aiohttp.ClientSession(headers={
+        "Authorization": f"Bot {token}",
+        "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)"
+    }) as session:
+        async with session.post(url='https://discord.com/api/v10' + url, data=data) as r:
+            data = await r.json()
+            match r.status:
+                case 200 | 204:
+                    return data
+                case other:
+                    raise APIException(data['message'])
+
+
+async def patch(token, url, data):
+    async with aiohttp.ClientSession(headers={
+        "Authorization": f"Bot {token}",
+        "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)"
+    }) as session:
+        async with session.patch(url='https://discord.com/api/v10' + url, data=data) as r:
+            data = await r.json()
+            match r.status:
+                case 200 | 204:
+                    return data
+                case other:
+                    raise APIException(data['message'])
+
+
+async def delete(token, url):
+    async with aiohttp.ClientSession(headers={
+        "Authorization": f"Bot {token}",
+        "User-Agent": f"DiscordBot (https://github.com/mounderfod/discobra 0.0.1)"
+    }) as session:
+        async with session.delete(url='https://discord.com/api/v10' + url) as r:
+            data = await r.json()
+            match r.status:
+                case 200:
+                    return data
+                case other:
+                    raise APIException(data['message'])