diff --git a/disco/client.py b/disco/client.py index c480af9..cbb45e5 100644 --- a/disco/client.py +++ b/disco/client.py @@ -5,7 +5,7 @@ from disco.state import State, StateConfig from disco.api.client import APIClient from disco.gateway.client import GatewayClient from disco.gateway.packets import OPCode -from disco.types.user import Status, Game +from disco.types.user import Status, Activity from disco.util.config import Config from disco.util.emitter import Emitter from disco.util.logging import LoggingClass @@ -122,7 +122,7 @@ class Client(LoggingClass): since : float How long the client has been afk for (in seconds). """ - if game and not isinstance(game, Game): + if game and not isinstance(game, Activity): raise TypeError('Game must be a Game model') if status is Status.IDLE and not since: diff --git a/disco/types/channel.py b/disco/types/channel.py index 3d6837e..904cf32 100644 --- a/disco/types/channel.py +++ b/disco/types/channel.py @@ -6,7 +6,7 @@ from six.moves import map from disco.util.snowflake import to_snowflake from disco.util.functional import one_or_many, chunks from disco.types.user import User -from disco.types.base import SlottedModel, Field, AutoDictField, snowflake, enum, text, cached_property +from disco.types.base import SlottedModel, Field, AutoDictField, snowflake, enum, datetime, text, cached_property from disco.types.permissions import Permissions, Permissible, PermissionValue @@ -120,19 +120,23 @@ class Channel(SlottedModel, Permissible): Channel permissions overwrites. """ id = Field(snowflake) + type = Field(enum(ChannelType)) guild_id = Field(snowflake) + position = Field(int) + permission_overwrites = AutoDictField(PermissionOverwrite, 'id', alias='permission_overwrites') name = Field(text) topic = Field(text) + nsfw = Field(bool) last_message_id = Field(snowflake) - position = Field(int) bitrate = Field(int) user_limit = Field(int) + rate_limit_per_user = Field(int) recipients = AutoDictField(User, 'id') - nsfw = Field(bool) - type = Field(enum(ChannelType)) - overwrites = AutoDictField(PermissionOverwrite, 'id', alias='permission_overwrites') + icon = Field(text) + owner_id = Field(snowflake) + application_id = Field(snowflake) parent_id = Field(snowflake) - rate_limit_per_user = Field(int) + last_pin_timestamp = Field(datetime) def __init__(self, *args, **kwargs): super(Channel, self).__init__(*args, **kwargs) @@ -140,7 +144,7 @@ class Channel(SlottedModel, Permissible): def after_load(self): # TODO: hackfix - self.attach(six.itervalues(self.overwrites), {'channel_id': self.id, 'channel': self}) + self.attach(six.itervalues(self.permission_overwrites), {'channel_id': self.id, 'channel': self}) def __str__(self): return u'#{}'.format(self.name) if self.name else six.text_type(self.id) @@ -164,18 +168,18 @@ class Channel(SlottedModel, Permissible): base = self.guild.get_permissions(member) # First grab and apply the everyone overwrite - everyone = self.overwrites.get(self.guild_id) + everyone = self.permission_overwrites.get(self.guild_id) if everyone: base -= everyone.deny base += everyone.allow for role_id in member.roles: - overwrite = self.overwrites.get(role_id) + overwrite = self.permission_overwrites.get(role_id) if overwrite: base -= overwrite.deny base += overwrite.allow - ow_member = self.overwrites.get(member.user.id) + ow_member = self.permission_overwrites.get(member.user.id) if ow_member: base -= ow_member.deny base += ow_member.allow diff --git a/disco/types/guild.py b/disco/types/guild.py index db49430..481d1ce 100644 --- a/disco/types/guild.py +++ b/disco/types/guild.py @@ -8,13 +8,29 @@ from disco.types.base import ( SlottedModel, Field, ListField, AutoDictField, DictField, snowflake, text, enum, datetime, cached_property, ) -from disco.types.user import User +from disco.types.user import User, Presence from disco.types.voice import VoiceState from disco.types.channel import Channel, ChannelType from disco.types.message import Emoji from disco.types.permissions import PermissionValue, Permissions, Permissible +class DefaultMessageNotificationsLevel(object): + ALL_MESSAGES = 0 + ONLY_MENTIONS = 1 + + +class ExplicitContentFilterLevel(object): + NONE = 0 + WITHOUT_ROLES = 1 + ALL = 2 + + +class MFALevel(object): + NONE = 0 + ELEVATED = 1 + + class VerificationLevel(object): NONE = 0 LOW = 1 @@ -23,15 +39,17 @@ class VerificationLevel(object): EXTREME = 4 -class ExplicitContentFilterLevel(object): +class PremiumTier(object): NONE = 0 - WITHOUT_ROLES = 1 - ALL = 2 + TIER_1 = 1 + TIER_2 = 2 + TIER_3 = 3 -class DefaultMessageNotificationsLevel(object): - ALL_MESSAGES = 0 - ONLY_MENTIONS = 1 +class SystemChannelFlag(object): + NONE = 0 + SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0 + SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1 class GuildEmoji(Emoji): @@ -44,22 +62,25 @@ class GuildEmoji(Emoji): The ID of this emoji. name : str The name of this emoji. + roles : list(snowflake) + Roles this emoji is attached to. + user : User + The User that created this emoji. require_colons : bool Whether this emoji requires colons to use. managed : bool Whether this emoji is managed by an integration. - roles : list(snowflake) - Roles this emoji is attached to. animated : bool Whether this emoji is animated. """ id = Field(snowflake) - guild_id = Field(snowflake) name = Field(text) + roles = ListField(snowflake) + user = Field(User) require_colons = Field(bool) managed = Field(bool) - roles = ListField(snowflake) animated = Field(bool) + guild_id = Field(snowflake) def __str__(self): return u'<{}:{}:{}>'.format('a' if self.animated else '', self.name, self.id) @@ -89,26 +110,30 @@ class Role(SlottedModel): The role ID. name : string The role name. - hoist : bool - Whether this role is hoisted (displayed separately in the sidebar). - managed : bool - Whether this role is managed by an integration. color : int The RGB color of this role. - permissions : :class:`disco.types.permissions.PermissionsValue` - The permissions this role grants. + hoist : bool + Whether this role is hoisted (displayed separately in the sidebar). position : int The position of this role in the hierarchy. + permissions : :class:`disco.types.permissions.PermissionsValue` + The permissions this role grants. + managed : bool + Whether this role is managed by an integration. + mentionable : bool + Wherther this role is taggable in chat. + guild_id : snowflake + The id of the server the role is in. """ id = Field(snowflake) - guild_id = Field(snowflake) name = Field(text) - hoist = Field(bool) - managed = Field(bool) color = Field(int) - permissions = Field(PermissionValue) + hoist = Field(bool) position = Field(int) + permissions = Field(PermissionValue) + managed = Field(bool) mentionable = Field(bool) + guild_id = Field(snowflake) def __str__(self): return self.name @@ -141,29 +166,29 @@ class GuildMember(SlottedModel): ---------- user : :class:`disco.types.user.User` The user object of this member. - guild_id : snowflake - The guild this member is part of. nick : str The nickname of the member. - mute : bool - Whether this member is server voice-muted. - deaf : bool - Whether this member is server voice-deafened. - joined_at : datetime - When this user joined the guild. roles : list(snowflake) Roles this member is part of. + joined_at : datetime + When this user joined the guild. premium_since : datetime When this user set their nitro boost to this server. + deaf : bool + Whether this member is server voice-deafened. + mute : bool + Whether this member is server voice-muted. + guild_id : snowflake + The guild this member is part of. """ user = Field(User) - guild_id = Field(snowflake) nick = Field(text) - mute = Field(bool) - deaf = Field(bool) - joined_at = Field(datetime) roles = ListField(snowflake) + joined_at = Field(datetime) premium_since = Field(datetime) + deaf = Field(bool) + mute = Field(bool) + guild_id = Field(snowflake) def __str__(self): return self.user.__str__() @@ -271,6 +296,14 @@ class Guild(SlottedModel, Permissible): ---------- id : snowflake The id of this guild. + name : str + Guild's name. + icon : str + Guild's icon image hash + splash : str + Guild's splash image hash + owner : bool + Whether the user is the server owner. owner_id : snowflake The id of the owner. afk_channel_id : snowflake @@ -279,12 +312,8 @@ class Guild(SlottedModel, Permissible): The id of the embed channel. system_channel_id : snowflake The id of the system channel. - name : str - Guild's name. - icon : str - Guild's icon image hash - splash : str - Guild's splash image hash + widget_channel_id : snowflake + The id of the server widget channel banner : str Guild's banner image hash region : str @@ -293,12 +322,26 @@ class Guild(SlottedModel, Permissible): Delay after which users are automatically moved to the afk channel. embed_enabled : bool Whether the guild's embed is enabled. + widget_enabled : bool + Whether the guild's server widget is enabled. verification_level : int The verification level used by the guild. mfa_level : int The MFA level used by the guild. features : list(str) Extra features enabled for this guild. + system_channel_flags : int + The system messages that are disabled. + vanity_url_code : str + Guild's vanity url code + description : str + Guild's description + max_presences : int + Guild's maximum amount of presences + max_members : int + Guild's maximum amount of members + preferred_locale : str + Guild's primary language members : dict(snowflake, :class:`GuildMember`) All of the guild's members. channels : dict(snowflake, :class:`disco.types.channel.Channel`) @@ -311,38 +354,49 @@ class Guild(SlottedModel, Permissible): All of the guild's voice states. premium_tier : int Guild's premium tier. - premium_subscription_count: int + premium_subscription_count : int The amount of users using their nitro boost on this guild. """ id = Field(snowflake) - owner_id = Field(snowflake) - afk_channel_id = Field(snowflake) - embed_channel_id = Field(snowflake) - system_channel_id = Field(snowflake) name = Field(text) icon = Field(text) splash = Field(text) - banner = Field(text) + owner = Field(bool) + owner_id = Field(snowflake) + permissions = Field(int) region = Field(text) + afk_channel_id = Field(snowflake) afk_timeout = Field(int) embed_enabled = Field(bool) + embed_channel_id = Field(snowflake) verification_level = Field(enum(VerificationLevel)) - explicit_content_filter = Field(enum(ExplicitContentFilterLevel)) default_message_notifications = Field(enum(DefaultMessageNotificationsLevel)) - mfa_level = Field(int) - features = ListField(str) - members = AutoDictField(GuildMember, 'id') - channels = AutoDictField(Channel, 'id') + explicit_content_filter = Field(enum(ExplicitContentFilterLevel)) roles = AutoDictField(Role, 'id') emojis = AutoDictField(GuildEmoji, 'id') - voice_states = AutoDictField(VoiceState, 'session_id') + features = ListField(str) + mfa_level = Field(int) + application_id = Field(snowflake) + widget_enabled = Field(bool) + widget_channel_id = Field(snowflake) + system_channel_id = Field(snowflake) + joined_at = Field(datetime) + large = Field(bool) + unavailable = Field(bool) member_count = Field(int) - premium_tier = Field(int) - premium_subscription_count = Field(int, default=0) - vanity_url_code = Field(text) - max_presences = Field(int) + voice_states = AutoDictField(VoiceState, 'session_id') + members = AutoDictField(GuildMember, 'id') + channels = AutoDictField(Channel, 'id') + presences = AutoDictField(Presence) + max_presences = Field(int, default=5000) max_members = Field(int) + vanity_url_code = Field(text) description = Field(text) + banner = Field(text) + premium_tier = Field(int, default=0) + premium_subscription_count = Field(int, default=0) + system_channel_flags = Field(int) + preferred_locale = Field(str) def __init__(self, *args, **kwargs): super(Guild, self).__init__(*args, **kwargs) @@ -502,8 +556,7 @@ class Guild(SlottedModel, Permissible): parent_id=None, bitrate=None, user_limit=None, - position=None, - reason=None): + position=None): """ Creates a voice channel within the guild. """ diff --git a/disco/types/message.py b/disco/types/message.py index ae03e5d..cc6db75 100644 --- a/disco/types/message.py +++ b/disco/types/message.py @@ -11,6 +11,7 @@ from disco.types.base import ( from disco.util.paginator import Paginator from disco.util.snowflake import to_snowflake from disco.types.user import User +from disco.types.guild import GuildMember class MessageType(object): @@ -70,8 +71,23 @@ class Emoji(SlottedModel): class MessageReactionEmoji(Emoji): """ Represents a emoji which was used as a reaction on a message. + + Attributes + ---------- + count : int + The number of users who reacted with this emoji. + me : bool + Whether the current user reacted with this emoji. + emoji : `MessageReactionEmoji` + The emoji which was reacted. """ - pass + id = Field(snowflake) + name = Field(text) + roles = ListField(snowflake) + user = Field(User) + require_colons = Field(bool) + managed = Field(bool) + animated = Field(bool) class MessageReaction(SlottedModel): @@ -80,16 +96,16 @@ class MessageReaction(SlottedModel): Attributes ---------- - emoji : `MessageReactionEmoji` - The emoji which was reacted. count : int The number of users who reacted with this emoji. me : bool Whether the current user reacted with this emoji. + emoji : `MessageReactionEmoji` + The emoji which was reacted. """ - emoji = Field(MessageReactionEmoji) count = Field(int) me = Field(bool) + emoji = Field(MessageReactionEmoji) class MessageApplication(SlottedModel): @@ -159,15 +175,15 @@ class MessageEmbedImage(SlottedModel): The URL for the image. proxy_url : str A proxy URL for the image, set by Discord. - width : int - The width of the image, set by Discord. height : int The height of the image, set by Discord. + width : int + The width of the image, set by Discord. """ url = Field(text) proxy_url = Field(text) - width = Field(int) height = Field(int) + width = Field(int) class MessageEmbedThumbnail(SlottedModel): @@ -180,15 +196,15 @@ class MessageEmbedThumbnail(SlottedModel): The thumbnail URL. proxy_url : str A proxy URL for the thumbnail, set by Discord. - width : int - The width of the thumbnail, set by Discord. height : int The height of the thumbnail, set by Discord. + width : int + The width of the thumbnail, set by Discord. """ url = Field(text) proxy_url = Field(text) - width = Field(int) height = Field(int) + width = Field(int) class MessageEmbedVideo(SlottedModel): @@ -199,16 +215,21 @@ class MessageEmbedVideo(SlottedModel): ---------- url : str The URL for the video. - width : int - The width of the video, set by Discord. height : int The height of the video, set by Discord. + width : int + The width of the video, set by Discord. """ url = Field(text) height = Field(int) width = Field(int) +class MessageEmbedProvider(SlottedModel): + name = Field(text) + url = Field(text) + + class MessageEmbedAuthor(SlottedModel): """ An author for the `MessageEmbed`. @@ -274,6 +295,8 @@ class MessageEmbed(SlottedModel): The thumbnail of the embed. video : `MessageEmbedVideo` The video of the embed. + provider : "MessageEmbedProvider' + The provider of the embed. author : `MessageEmbedAuthor` The author of the embed. fields : list[`MessageEmbedField]` @@ -289,6 +312,7 @@ class MessageEmbed(SlottedModel): image = Field(MessageEmbedImage) thumbnail = Field(MessageEmbedThumbnail) video = Field(MessageEmbedVideo) + provider = Field(MessageEmbedProvider) author = Field(MessageEmbedAuthor) fields = ListField(MessageEmbedField) @@ -339,12 +363,12 @@ class MessageAttachment(SlottedModel): The id of this attachment. filename : str The filename of this attachment. + size : int + Size of the attachment. url : str The URL of this attachment. proxy_url : str The URL to proxy through when downloading the attachment. - size : int - Size of the attachment. height : int Height of the attachment. width : int @@ -352,9 +376,9 @@ class MessageAttachment(SlottedModel): """ id = Field(str) filename = Field(text) + size = Field(int) url = Field(text) proxy_url = Field(text) - size = Field(int) height = Field(int) width = Field(int) @@ -369,14 +393,14 @@ class Message(SlottedModel): The ID of this message. channel_id : snowflake The channel ID this message was sent in. - type : `MessageType` - Type of the message. + guild_id : snowflake + The server ID this message was sent in. author : :class:`disco.types.user.User` The author of this message. + member : GuildMember + Member properties for the message's author. content : str The unicode contents of this message. - nonce : str - The nonce of this message. timestamp : datetime When this message was created. edited_timestamp : datetime? @@ -385,18 +409,24 @@ class Message(SlottedModel): Whether this is a TTS (text-to-speech) message. mention_everyone : bool Whether this message has an @everyone which mentions everyone. - pinned : bool - Whether this message is pinned in the channel. mentions : dict[snowflake, `User`] Users mentioned within this message. mention_roles : list[snowflake] IDs for roles mentioned within this message. - embeds : list[`MessageEmbed`] - Embeds for this message. attachments : dict[`MessageAttachment`] Attachments for this message. + embeds : list[`MessageEmbed`] + Embeds for this message. reactions : list[`MessageReaction`] Reactions for this message. + nonce : str + The nonce of this message. + pinned : bool + Whether this message is pinned in the channel. + webhook_id : snowflake + The id if the message is a webhook. + type : `MessageType` + Type of the message. activity : `MessageActivity` The activity of a Rich Presence-related chat embed. application : `MessageApplication` @@ -404,21 +434,23 @@ class Message(SlottedModel): """ id = Field(snowflake) channel_id = Field(snowflake) - webhook_id = Field(snowflake) - type = Field(enum(MessageType)) + guild_id = Field(snowflake) author = Field(User) + member = Field(GuildMember) content = Field(text) - nonce = Field(snowflake) timestamp = Field(datetime) edited_timestamp = Field(datetime) tts = Field(bool) mention_everyone = Field(bool) - pinned = Field(bool) mentions = AutoDictField(User, 'id') mention_roles = ListField(snowflake) - embeds = ListField(MessageEmbed) attachments = AutoDictField(MessageAttachment, 'id') + embeds = ListField(MessageEmbed) reactions = ListField(MessageReaction) + nonce = Field(snowflake) + pinned = Field(bool) + webhook_id = Field(snowflake) + type = Field(enum(MessageType)) activity = Field(MessageActivity) application = Field(MessageApplication) diff --git a/disco/types/user.py b/disco/types/user.py index 30c432c..b331617 100644 --- a/disco/types/user.py +++ b/disco/types/user.py @@ -16,14 +16,36 @@ class DefaultAvatars(object): ALL = [BLURPLE, GREY, GREEN, ORANGE, RED] +class UserFlags(object): + NONE = 0 + DISCORD_EMPLOYEE = 1 << 0 + DISCORD_PARTNER = 1 << 1 + HS_EVENTS = 1 << 2 + BUG_HUNTER = 1 << 3 + HS_BRAVERY = 1 << 6 + HS_BRILLIANCE = 1 << 7 + HS_BALANCE = 1 << 8 + EARLY_SUPPORTER = 1 << 9 + TEAM_USER = 1 << 10 + + +class PremiumType(object): + CLASSIC = 1 + NITRO = 2 + + class User(SlottedModel, with_equality('id'), with_hash('id')): id = Field(snowflake) username = Field(text) - avatar = Field(text) discriminator = Field(text) + avatar = Field(text) bot = Field(bool, default=False) + mfa_enabled = Field(bool) + locale = Field(text) verified = Field(bool) email = Field(text) + flags = Field(int) + premium_type = Field(int) presence = Field(None) @@ -62,7 +84,7 @@ class User(SlottedModel, with_equality('id'), with_hash('id')): return u''.format(self.id, self) -class GameType(object): +class ActivityTypes(object): DEFAULT = 0 STREAMING = 1 LISTENING = 2 @@ -77,25 +99,31 @@ class Status(object): OFFLINE = 'OFFLINE' -class Party(SlottedModel): +class ClientStatus(object): + DESKTOP = 'DESKTOP' + MOBILE = 'MOBILE' + WEB = 'WEB' + + +class ActivityParty(SlottedModel): id = Field(text) size = ListField(int) -class Assets(SlottedModel): +class ActivityAssets(SlottedModel): large_image = Field(text) large_text = Field(text) small_image = Field(text) small_text = Field(text) -class Secrets(SlottedModel): +class ActivitySecrets(SlottedModel): join = Field(text) spectate = Field(text) match = Field(text) -class Timestamps(SlottedModel): +class ActivityTimestamps(SlottedModel): start = Field(int) end = Field(int) @@ -108,22 +136,35 @@ class Timestamps(SlottedModel): return datetime.utcfromtimestamp(self.end / 1000) -class Game(SlottedModel): - type = Field(enum(GameType)) +class ActivityFlags(object): + INSTANCE = 1 << 0 + JOIN = 1 << 1 + SPECTATE = 1 << 2 + JOIN_REQUEST = 1 << 3 + SYNC = 1 << 4 + PLAY = 1 << 5 + + +class Activity(SlottedModel): name = Field(text) + type = Field(enum(ActivityTypes)) url = Field(text) - timestamps = Field(Timestamps) + timestamps = Field(ActivityTimestamps) application_id = Field(text) details = Field(text) state = Field(text) - party = Field(Party) - assets = Field(Assets) - secrets = Field(Secrets) + party = Field(ActivityParty) + assets = Field(ActivityAssets) + secrets = Field(ActivitySecrets) instance = Field(bool) flags = Field(int) class Presence(SlottedModel): user = Field(User, alias='user', ignore_dump=['presence']) - game = Field(Game) + roles = ListField(snowflake) + game = Field(Activity) + guild_id = Field(snowflake) status = Field(enum(Status)) + activity = Field(Activity, 'application_id') + client_status = Field(enum(ClientStatus))