Browse Source

Add permissions support, etc fixes/tweaks

pull/3/head
Andrei 9 years ago
parent
commit
4c41010fc1
  1. 9
      disco/api/http.py
  2. 2
      disco/bot/bot.py
  3. 34
      disco/bot/parser.py
  4. 5
      disco/types/channel.py
  5. 3
      disco/types/guild.py
  6. 5
      disco/types/message.py
  7. 71
      disco/types/permissions.py
  8. 6
      disco/types/user.py
  9. 1
      disco/util/websocket.py

9
disco/api/http.py

@ -88,9 +88,14 @@ class Routes(object):
class APIException(Exception): class APIException(Exception):
def __init__(self, msg, status_code=0, content=None): def __init__(self, msg, status_code=0, content=None):
super(APIException, self).__init__(msg)
self.status_code = status_code self.status_code = status_code
self.content = content self.content = content
self.msg = msg
if self.status_code:
self.msg += ' code: {}'.format(status_code)
super(APIException, self).__init__(self.msg)
class HTTPClient(LoggingClass): class HTTPClient(LoggingClass):
@ -132,6 +137,8 @@ class HTTPClient(LoggingClass):
# If we got a success status code, just return the data # If we got a success status code, just return the data
if r.status_code < 400: if r.status_code < 400:
return r return r
elif 400 < r.status_code < 500:
raise APIException('Request failed', r.status_code, r.content)
else: else:
if r.status_code == 429: if r.status_code == 429:
self.log.warning('Request responded w/ 429, retrying (but this should not happen, check your clock sync') self.log.warning('Request responded w/ 429, retrying (but this should not happen, check your clock sync')

2
disco/bot/bot.py

@ -126,7 +126,7 @@ class Bot(object):
if cls.__name__ in self.plugins: if cls.__name__ in self.plugins:
raise Exception('Cannot add already added plugin: {}'.format(cls.__name__)) raise Exception('Cannot add already added plugin: {}'.format(cls.__name__))
config = self.config.plugin_config_provider(cls.__name__) if self.config.plugin_config_provider else {} config = self.config.plugin_config_provider(cls.__name__) if self.config.plugin_config_provider else None
self.plugins[cls.__name__] = cls(self, config) self.plugins[cls.__name__] = cls(self, config)
self.plugins[cls.__name__].load() self.plugins[cls.__name__].load()

34
disco/bot/parser.py

@ -1,4 +1,6 @@
import re import re
import copy
PARTS_RE = re.compile('(\<|\[)((?:\w+|\:|\||\.\.\.| (?:[0-9]+))+)(?:\>|\])') PARTS_RE = re.compile('(\<|\[)((?:\w+|\:|\||\.\.\.| (?:[0-9]+))+)(?:\>|\])')
@ -26,15 +28,6 @@ class Argument(object):
def true_count(self): def true_count(self):
return self.count or 1 return self.count or 1
def convert(self, obj):
for typ in self.types:
typ = TYPE_MAP.get(typ)
try:
return typ(obj)
except Exception as e:
continue
raise e
def parse(self, raw): def parse(self, raw):
prefix, part = raw prefix, part = raw
@ -58,8 +51,23 @@ class Argument(object):
class ArgumentSet(object): class ArgumentSet(object):
def __init__(self, args=None): def __init__(self, args=None, custom_types=None):
self.args = args or [] self.args = args or []
self.types = copy.copy(TYPE_MAP)
self.types.update(custom_types)
def convert(self, types, value):
for typ_name in types:
typ = self.types.get(typ_name)
if not typ:
raise Exception('Unknown type {}'.format(typ_name))
try:
return typ(value)
except Exception as e:
continue
raise e
def append(self, arg): def append(self, arg):
if self.args and not self.args[-1].required and arg.required: if self.args and not self.args[-1].required and arg.required:
@ -85,7 +93,7 @@ class ArgumentSet(object):
if arg.types: if arg.types:
for idx, r in enumerate(raw): for idx, r in enumerate(raw):
try: try:
raw[idx] = arg.convert(r) raw[idx] = self.convert(arg.types, r)
except: except:
raise ArgumentError('cannot convert `{}` to `{}`'.format( raise ArgumentError('cannot convert `{}` to `{}`'.format(
r, ', '.join(arg.types) r, ', '.join(arg.types)
@ -110,8 +118,8 @@ class ArgumentSet(object):
return sum([i.true_count for i in self.args if i.required]) return sum([i.true_count for i in self.args if i.required])
def parse_arguments(line): def parse_arguments(line, custom_types=None):
args = ArgumentSet() args = ArgumentSet(custom_types=custom_types)
data = PARTS_RE.findall(line) data = PARTS_RE.findall(line)
if len(data): if len(data):

5
disco/types/channel.py

@ -6,6 +6,7 @@ from disco.util.cache import cached_property
from disco.util.types import ListToDictType from disco.util.types import ListToDictType
from disco.types.base import BaseType from disco.types.base import BaseType
from disco.types.user import User from disco.types.user import User
from disco.types.permissions import *
from disco.voice.client import VoiceClient from disco.voice.client import VoiceClient
@ -26,8 +27,8 @@ class PermissionOverwrite(BaseType):
id = skema.SnowflakeType() id = skema.SnowflakeType()
type = skema.StringType(choices=PermissionOverwriteType.ALL_VALUES) type = skema.StringType(choices=PermissionOverwriteType.ALL_VALUES)
allow = skema.IntType() allow = PermissionType()
deny = skema.IntType() deny = PermissionType()
class Channel(BaseType): class Channel(BaseType):

3
disco/types/guild.py

@ -7,6 +7,7 @@ from disco.types.base import BaseType
from disco.util.types import PreHookType, ListToDictType from disco.util.types import PreHookType, ListToDictType
from disco.types.user import User from disco.types.user import User
from disco.types.voice import VoiceState from disco.types.voice import VoiceState
from disco.types.permissions import PermissionType
from disco.types.channel import Channel from disco.types.channel import Channel
@ -24,7 +25,7 @@ class Role(BaseType):
hoist = skema.BooleanType() hoist = skema.BooleanType()
managed = skema.BooleanType() managed = skema.BooleanType()
color = skema.IntType() color = skema.IntType()
permissions = skema.IntType() permissions = PermissionType()
position = skema.IntType() position = skema.IntType()

5
disco/types/message.py

@ -47,6 +47,9 @@ class Message(BaseType):
embeds = skema.ListType(skema.ModelType(MessageEmbed)) embeds = skema.ListType(skema.ModelType(MessageEmbed))
attachments = ListToDictType('id', skema.ModelType(MessageAttachment)) attachments = ListToDictType('id', skema.ModelType(MessageAttachment))
def __str__(self):
return '<Message {} ({})>'.format(self.id, self.channel_id)
@cached_property @cached_property
def guild(self): def guild(self):
return self.channel.guild return self.channel.guild
@ -61,7 +64,7 @@ class Message(BaseType):
def edit(self, content): def edit(self, content):
return self.client.api.channels_messages_modify(self.channel_id, self.id, content) return self.client.api.channels_messages_modify(self.channel_id, self.id, content)
def delete(self, content): def delete(self):
return self.client.api.channels_messages_delete(self.channel_id, self.id) return self.client.api.channels_messages_delete(self.channel_id, self.id)
def is_mentioned(self, entity): def is_mentioned(self, entity):

71
disco/types/permissions.py

@ -0,0 +1,71 @@
from skema import NumberType
from holster.enum import Enum
Permissions = Enum(
NONE=0,
CREATE_INSTANT_INVITE=1 << 0,
KICK_MEMBERS=1 << 1,
BAN_MEMBERS=1 << 2,
ADMINISTRATOR=1 << 3,
MANAGE_CHANNELS=1 << 4,
MANAGE_GUILD=1 << 5,
READ_MESSAGES=1 << 10,
SEND_MESSAGES=1 << 11,
SEND_TSS_MESSAGES=1 << 12,
MANAGE_MESSAGES=1 << 13,
EMBED_LINKS=1 << 14,
ATTACH_FILES=1 << 15,
READ_MESSAGE_HISTORY=1 << 16,
MENTION_EVERYONE=1 << 17,
USE_EXTERNAL_EMOJIS=1 << 18,
CONNECT=1 << 20,
SPEAK=1 << 21,
MUTE_MEMBERS=1 << 22,
DEAFEN_MEMBERS=1 << 23,
MOVE_MEMBERS=1 << 24,
USE_VAD=1 << 25,
CHANGE_NICKNAME=1 << 26,
MANAGE_NICKNAMES=1 << 27,
MANAGE_ROLES=1 << 28,
MANAGE_WEBHOOKS=1 << 29,
MANAGE_EMOJIS=1 << 30,
)
class PermissionValue(object):
def __init__(self, value):
self.value = value
def __getattribute__(self, name):
if name in Permissions.attrs:
return (self.value & Permissions[name].value) == Permissions[name].value
else:
return object.__getattribute__(self, name)
def __setattr__(self, name, value):
if name not in Permissions.attrs:
return super(PermissionValue, self).__setattr__(name, value)
if value:
self.value |= Permissions[name].value
else:
self.value &= ~Permissions[name].value
def to_dict(self):
return {
k: getattr(self, k) for k in Permissions.attrs
}
@classmethod
def text(cls):
return cls(523264)
@classmethod
def voice(cls):
return cls(66060288)
class PermissionType(NumberType):
def __init__(self, *args, **kwargs):
super(PermissionType, self).__init__(number_class=PermissionValue, number_type='PermissionValue', *args, **kwargs)

6
disco/types/user.py

@ -13,5 +13,11 @@ class User(BaseType):
verified = skema.BooleanType(required=False) verified = skema.BooleanType(required=False)
email = skema.EmailType(required=False) email = skema.EmailType(required=False)
def to_string(self):
return '{}#{}'.format(self.username, self.discriminator)
def __str__(self):
return '<User {} ({})>'.format(self.id, self.to_string())
def on_create(self): def on_create(self):
self.client.state.users[self.id] = self self.client.state.users[self.id] = self

1
disco/util/websocket.py

@ -66,7 +66,6 @@ class WebsocketProcessProxy(object):
self.emitter = Emitter(gevent.spawn) self.emitter = Emitter(gevent.spawn)
gevent.signal(signal.SIGINT, self.handle_signal) gevent.signal(signal.SIGINT, self.handle_signal)
gevent.signal(signal.SIGQUIT, self.handle_signal)
gevent.signal(signal.SIGTERM, self.handle_signal) gevent.signal(signal.SIGTERM, self.handle_signal)
def handle_signal(self, *args): def handle_signal(self, *args):

Loading…
Cancel
Save