""" Set defaults for config options """ import os from hierkeyval import get_default CONFIG_STORE = get_default('toothless-config') # The token to authenticate to Discord with TOKEN = os.environ['BOTTOKEN'] # All prefix commands must start with this sigil # It must be 0 or 1 characters CONFIG_STORE.set_global('COMMAND_PREFIX', '/') # Whether to complain if an incorrect command is used CONFIG_STORE.set_global('COMPLAIN_IF_COMMAND_NOT_RECOGNIZED', True) # Must specify routes in config prefix_patterns = [] # Specify names of modules to import on load to activate event handlers event_handler_modules = [] # If True, will never crash on exception in a route handler. # Warning: This may cause corruption of data or invalid state, depending on # the plugin in question GRACEFULLY_CATCH_EXCEPTIONS = False from config import *
from datetime import datetime, timezone, timedelta import asyncio from toothless import on_connect, path from hierkeyval import get_default # server: { sprints: {...id : endtime...}, users: {...id: sprint }, count: 0} TEMPORARY_STORAGE = get_default('sprints') # Until a permanent solution found # On (re)connect, re-queue all sprints @on_connect async def initialize(client): loop = asyncio.get_event_loop() for server in client.servers: try: sprints = TEMPORARY_STORAGE.get_val_ident('s', server, 'sprints') for sprintid, sprint in sprints.items(): loop.create_task( count_sprint(client, sprint['msg'], sprint, sprintid)) except KeyError: continue def inc_counter(msg): counter = TEMPORARY_STORAGE.get_default('s', msg.server, 'sprint counter', 0) TEMPORARY_STORAGE.set_val('s', msg, 'sprint counter', counter + 1) return counter # returns a tz-aware utc tz datetime obj
from toothless.eventhandlers import on_match from toothless import path from toothless import utils from hierkeyval import get_default from datetime import datetime import logging STORE = get_default('pingme') def get_pingchannel(client, server): id = STORE.get_default('s', server, 'pingchannel', None) if id is None: return None return client.get_channel(id) def set_pingchannel(msg): STORE.set_val('s', msg, 'pingchannel', msg.channel.id) def unset_pingchannel(msg): STORE.set_val('s', msg, 'pingchannel', None) # Get all those who are eligible for being pinged. # returns a set of user ids def get_pingees(msg): serverpings = STORE.get_default('s', msg.server, 'serverpingees', set()) channels = STORE.get_default('s', msg.server, 'channelpingees', {}) if msg.channel.id in channels:
from hierkeyval import get_default from .commandrouter import path from .tokens import TokenMismatch, BoolProto from toothless import utils from toothless.utils import is_admin, has_perm, get_or_extract_id, check_admin_or_mod CONFIG_STORE = get_default('toothless-config') PERM_STORE = get_default('toothless-perms') """ Some utilities for configuring Toothless per-server. """ class ConfigOptions: # Parser can be any callable that takes 1 param and returns a parsed result, # or raises TokenMismatch if invalid input def __init__(self, name, desc, parser): self.name = name self.desc = desc self.parser = parser def get_desc(self): return self.desc.format(CONFIG_STORE.get_global(self.name)) def parse_and_set(self, server, input): newconfig = self.parser(input) CONFIG_STORE.set_val('s', server, self.name, newconfig, hasident=True) async def set_config(client, message, config=None, input=None): if not check_admin_or_mod(message):
# just hard break out.append(string[:maxlen]) string = string[maxlen:] out.append(string) return out # Checks if user has a given role by comparing role ids def user_has_role(user, roleid): for r in user.roles: if r.id == roleid: return True return False PERM_STORE = get_default('toothless-perms') """ Checks that a user has at least one of the perms :param permnames: A permission name, or a list of permission names. If it's a list, it will be OR'd. :param msg: The Discord.py message :returns: True if the user has at least one of the permissions provided """ def has_perm(permnames, msg): if isinstance(permnames, str): permnames = [permnames] try: for permname in permnames:
""" A series of commands that allow for role management. """ import asyncio import discord from hierkeyval import get_default from toothless import path from toothless import utils from toothless.utils import check_admin_or_mod, get_or_extract_id, get_role_by_id STORE = get_default('role-management') """ Bind a keyword to a role, for purposes of bot role management. :param role: Either a role ping or id number :param keyword: The words. """ async def bind_role(client, message, role=None, keyword=None): if not check_admin_or_mod(message): return "You don't have permission to do that." bindings = STORE.get_default('s', message.server, 'bindings', {}) keyword = keyword.strip() if len(keyword) == 0: return "Keywords need to not be empty." if keyword in bindings: return f"The keyword '{keyword}' is already bound to <@&{bindings[keyword]}>." # Bind role! roleid = get_or_extract_id(role) bindings[keyword] = roleid
import asyncio import datetime import discord import heapq from hierkeyval import get_default import logging import pytz from toothless import on_start, on_connect, path from toothless.tokens import DateProto, RawDateProto from toothless.utils import get_full_username from .reminder_class import Reminder from dateparser import parse HKV = get_default('reminders') QUEUE_LOOP = None @on_start def initialize(): # if not initialized, set dicts HKV.get_default('g', None, 'timezones', {}) HKV.get_default('g', None, 'reminders', []) HKV.get_default('g', None, 'queued', []) # reminders that will fire soon HKV.get_default('g', None, 'backedoff', []) # failed send, must resend logging.info('timers:reminders - initialized') @on_connect async def connected(client): global QUEUE_LOOP