Exemple #1
0
    async def _do_execute(self, cmd: Command):
        if len(cmd.args) != 1 or cmd.args[0].lower() not in ['on', 'off']:
            await self.client.send_message(
                cmd.channel,
                "Couldn't parse cmd. Call `{0} on` or `{0} off`.".format(
                    self.mention))
            return

        user_prefs = UserPrefs(daily_alert=None,
                               race_alert=(cmd.args[0] == 'on'))

        user = await userlib.get_user(discord_id=int(cmd.author.id),
                                      register=True)
        user.set(user_prefs=user_prefs, commit=True)

        if user_prefs.race_alert:
            await self.client.send_message(
                cmd.channel,
                "{0}: You will now receive PM alerts when a new raceroom is made."
                .format(cmd.author.mention))
        else:
            await self.client.send_message(
                cmd.channel,
                "{0}: You will no longer receive PM alerts for races.".format(
                    cmd.author.mention))
Exemple #2
0
async def make_room(race_info):
    # Find the races category
    race_channel_category = server.find_category(
        channel_name=Config.RACE_CHANNEL_CATEGORY_NAME)

    # Make a channel for the room
    race_channel = await server.guild.create_text_channel(
        get_raceroom_name(race_info), category=race_channel_category)

    if race_channel is None:
        console.warning('Failed to make a race channel.')
        return None

    # Make the actual RaceRoom and initialize it
    new_room = RaceRoom(race_discord_channel=race_channel, race_info=race_info)
    await new_room.initialize()

    Necrobot().register_bot_channel(race_channel, new_room)

    # Send PM alerts
    alert_pref = UserPrefs(daily_alert=None, race_alert=True)

    alert_string = 'A new race has been started:\nFormat: {1}\nChannel: {0}'.format(
        race_channel.mention, race_info.format_str)
    for member_id in await userdb.get_all_discord_ids_matching_prefs(alert_pref
                                                                     ):
        member = server.find_member(discord_id=member_id)
        if member is not None:
            try:
                await member.send(alert_string)
            except discord.errors.Forbidden:
                continue

    return race_channel
Exemple #3
0
async def make_room(race_info):
    # Make a channel for the room
    race_channel = await server.client.create_channel(
        server.server,
        get_raceroom_name(race_info),
        type=discord.ChannelType.text)

    if race_channel is not None:
        # Make the actual RaceRoom and initialize it
        new_room = RaceRoom(race_discord_channel=race_channel, race_info=race_info)
        await new_room.initialize()

        Necrobot().register_bot_channel(race_channel, new_room)

        # Send PM alerts
        alert_pref = UserPrefs(daily_alert=None, race_alert=True)

        alert_string = 'A new race has been started:\nFormat: {1}\nChannel: {0}'.format(
            race_channel.mention, race_info.format_str)
        for member_id in await userdb.get_all_discord_ids_matching_prefs(alert_pref):
            member = server.find_member(discord_id=member_id)
            if member is not None:
                await server.client.send_message(member, alert_string)

    return race_channel
Exemple #4
0
    def __init__(self, commit_fn):
        """Initialization. There should be no reason to directly create NecroUser objects; use userlib 
        instead.
        
        Parameters
        ----------
        commit_fn: function(NecroUser) -> None
            This should write the NecroUser to the database.
        """
        self._user_id = None            # type: int
        self._discord_id = None         # type: int
        self._discord_name = None       # type: str
        self._discord_member = None     # type: discord.Member
        self._twitch_name = None        # type: str
        self._rtmp_name = None          # type: str
        self._timezone = None           # type: pytz.timezone
        self._user_info = None          # type: str
        self._user_prefs = UserPrefs(daily_alert=False, race_alert=False)   # type: UserPrefs

        self._commit = commit_fn        # type: Callable[None, None]
Exemple #5
0
def _get_user_from_db_row(user_row):
    user = NecroUser(commit_fn=userdb.write_user)
    console.debug('Getting user from data: {}'.format(user_row))
    user.set(discord_id=user_row[0],
             discord_name=user_row[1],
             twitch_name=user_row[2],
             rtmp_name=user_row[3],
             timezone=user_row[4],
             user_info=user_row[5],
             user_prefs=UserPrefs(daily_alert=bool(user_row[6]),
                                  race_alert=bool(user_row[7])),
             commit=False)
    user._user_id = int(user_row[8])
    _cache_user(user)
    return user
Exemple #6
0
    async def on_new_daily(self) -> None:
        """Run when a new daily happens"""
        # Make the leaderboard message
        text = await self.leaderboard_text(self.today_number,
                                           display_seed=False)
        msg = await self.client.send_message(self._leaderboard_channel, text)
        await self.register_message(self.today_number, msg.id)

        # Update yesterday's leaderboard with the seed
        await self.update_leaderboard(self.today_number - 1, display_seed=True)

        # PM users with the daily_alert preference
        auto_pref = UserPrefs(daily_alert=True, race_alert=None)
        for member_id in await userdb.get_all_discord_ids_matching_prefs(
                auto_pref):
            member = server.find_member(discord_id=member_id)
            if member is not None:
                await self.register(self.today_number, member.id)
                await self.client.send_message(
                    member, "({0}) Today's {2} speedrun seed: {1}".format(
                        self.today_date.strftime("%d %b"), await
                        self.get_seed(self.today_number),
                        dailytype.character(self.daily_type,
                                            self.today_number)))
Exemple #7
0
class NecroUser(object):
    def __init__(self, commit_fn):
        """Initialization. There should be no reason to directly create NecroUser objects; use userlib 
        instead.
        
        Parameters
        ----------
        commit_fn: function(NecroUser) -> None
            This should write the NecroUser to the database.
        """
        self._user_id = None  # type: int
        self._discord_id = None  # type: int
        self._discord_name = None  # type: str
        self._discord_member = None  # type: discord.Member
        self._twitch_name = None  # type: str
        self._rtmp_name = None  # type: str
        self._timezone = None  # type: pytz.timezone
        self._user_info = None  # type: str
        self._user_prefs = UserPrefs(daily_alert=False,
                                     race_alert=False)  # type: UserPrefs

        self._commit = commit_fn  # type: Callable[None, None]

    def __eq__(self, other):
        return self.user_id == other.user_id

    def __repr__(self):
        if self.rtmp_name is not None:
            name_str = 'RTMP: ' + self.rtmp_name
        elif self.discord_name is not None:
            name_str = 'Discord: ' + self.discord_name
        elif self.twitch_name is not None:
            name_str = 'Twitch: ' + self.twitch_name
        else:
            name_str = '<unnamed>'
        return 'User {uid} ({name})'.format(uid=self._user_id, name=name_str)

    def __str__(self):
        return self.display_name

    async def commit(self) -> None:
        await self._commit(self)

    @property
    def user_id(self) -> int:
        return self._user_id

    @property
    def name_regex(self):
        """A compiled Regular Expression Object matching the racer's various names"""
        re_str = r''
        if self.rtmp_name is not None:
            re_str += re.escape(self.rtmp_name) + r'|'
        if self.discord_name is not None:
            re_str += re.escape(self.discord_name) + r'|'
        if self.twitch_name is not None:
            re_str += re.escape(self.twitch_name) + r'|'

        if re_str == r'':
            return None

        re_str = re_str[:-1]

        return re.compile(r'(?i)^\s*(' + re_str + r')\s*$')

    @property
    def discord_id(self) -> int:
        return self.discord_member.id if self.discord_member is not None else self._discord_id

    @property
    def discord_member(self) -> discord.Member or None:
        if self._discord_member is None and \
                (self._discord_id is not None or self._discord_name is not None):
            self._discord_member = server.find_member(
                discord_name=self._discord_name, discord_id=self._discord_id)
        return self._discord_member

    @property
    def discord_name(self) -> str:
        return self.discord_member.display_name if self.discord_member is not None else self._discord_name

    @property
    def display_name(self) -> str:
        if self.discord_name is not None:
            return self.discord_name
        elif self.rtmp_name is not None:
            return self.rtmp_name
        elif self.twitch_name is not None:
            return self.twitch_name
        else:
            return '<NecroUser with ID {}>'.format(self.user_id)

    @property
    def gsheet_name(self):
        return self.twitch_name

    @property
    def member(self) -> discord.Member or None:
        return self.discord_member

    @property
    def rtmp_name(self) -> str:
        return self._rtmp_name

    @property
    def timezone(self) -> pytz.timezone:
        return self._timezone

    @property
    def timezone_str(self) -> str or None:
        return str(self._timezone) if self._timezone is not None else None

    @property
    def twitch_name(self) -> str:
        return self._twitch_name

    @property
    def user_info(self) -> str:
        return self._user_info

    @property
    def user_prefs(self) -> UserPrefs:
        return self._user_prefs

    @property
    def infoname(self) -> str:
        if self.user_info is not None:
            return '{0} ({1})'.format(self.discord_name, self.user_info)
        else:
            return self.discord_name

    @property
    def infotext(self) -> str:
        if self.twitch_name == self.rtmp_name:
            return '  Twitch/RTMP: {0}\n' \
                   '     Timezone: {1}'.format(
                    self.rtmp_name,
                    self.timezone)
        else:
            return '    Twitch: {0}\n' \
                   '      RTMP: {1}\n' \
                   '  Timezone: {2}'.format(
                    self.twitch_name,
                    self.rtmp_name,
                    self.timezone)

    @property
    def infobox(self) -> str:
        return '```\n' \
               '{0}\n' \
               '{1}```'\
                .format(
                    strutil.tickless(self.infoname),
                    strutil.tickless(self.infotext)
                )

    def set(self,
            discord_member: discord.Member = None,
            discord_id: int = None,
            discord_name: str = None,
            twitch_name: str = None,
            rtmp_name: str = None,
            timezone: str = None,
            user_info: str = None,
            user_prefs: UserPrefs = None,
            commit: bool = True) -> None:
        """Set all non-None values and optionally commit the change to the database.
        
        Parameters
        ----------
        discord_member: discord.Member
            The discord.Member corresponding to this necrobot user.
        discord_id: int
            The user's discord ID. Not necessary if discord_member is not None.
        discord_name: str
            The user's discord name. Not necessary if discord_member is not None.
        twitch_name: str
            This user's twitch name. Case-insensitive.
        rtmp_name: str
            This user's RTMP name. Case-insensitive.
        timezone: str
            The user's timezone as a string, e.g., 'Asia/Tokyo'.
        user_info: str
            The user's custom info (shown on .userinfo).
        user_prefs: UserPrefs  
            The user's preferences.
        commit: bool
            If False, will not commit changes to the database.
        """

        changed_any = False
        if discord_member is not None and discord_member != self.discord_member:
            self._discord_id = int(discord_member.id)
            self._discord_name = discord_member.display_name
            self._discord_member = discord_member
            changed_any = True
        elif discord_id is not None and discord_id != self.discord_id:
            self._discord_id = discord_id
            member = server.find_member(discord_id=discord_id)
            if member is not None:
                self._discord_member = member
                self._discord_name = member.display_name
            elif discord_name is not None:
                self._discord_name = discord_name
            changed_any = True
        elif discord_name is not None and discord_name != self.discord_name:
            self._discord_name = discord_name
            member = server.find_member(discord_name=discord_name)
            if member is not None:
                self._discord_member = member
                self._discord_id = int(member.id)
            changed_any = True

        if twitch_name is not None and twitch_name != self._twitch_name:
            self._twitch_name = twitch_name
            changed_any = True
        if rtmp_name is not None and rtmp_name != self._rtmp_name:
            self._rtmp_name = rtmp_name
            changed_any = True
        if timezone is not None:
            if timezone not in pytz.common_timezones:
                console.warning(
                    'Tried to set timezone to {0}.'.format(timezone))
            elif str(self.timezone) != timezone:
                self._timezone = pytz.timezone(timezone)
                changed_any = True
        if user_info is not None and user_info != self._user_info:
            self._user_info = user_info
            changed_any = True
        if user_prefs is not None and user_prefs != self._user_prefs:
            self._user_prefs.merge_prefs(user_prefs)
            changed_any = True

        if changed_any and commit:
            asyncio.ensure_future(self.commit())

    async def get_big_infotext(self, stats: LeagueStats) -> str:
        return textwrap.dedent("""
            {discord_name} ({userinfo})
                   RTMP: {rtmp_name}
                 Twitch: {twitch_name}
               Timezone: {timezone}
                 Record: {wins}-{losses}
               Best win: {best_win}
               Avg. win: {avg_win}
            """.format(discord_name=self.discord_name,
                       userinfo=self.user_info,
                       rtmp_name=self.rtmp_name,
                       twitch_name=self.twitch_name,
                       timezone=self.timezone,
                       wins=stats.wins,
                       losses=stats.losses,
                       best_win=stats.best_win_str,
                       avg_win=stats.avg_win_str))