Esempio n. 1
0
 async def on_message(self, message: discord.Message):
     # Update active
     if not ChannelUtil.is_private(message.channel) and len(
             message.content) > 0 and message.content[0] not in [
                 '`', '\'', '.', '?', '!', "\"", "+", ";", ":", ","
             ]:
         await self.update_activity_stats(message)
 async def cog_before_invoke(self, ctx: Context):
     ctx.error = False
     # Remove duplicate mentions
     ctx.message.mentions = set(ctx.message.mentions)
     # Only allow giveaway commands in public channels
     msg = ctx.message
     if ChannelUtil.is_private(msg.channel) and ctx.command.name not in [
             'ticketstatus_cmd', 'ticket_cmd'
     ]:
         ctx.error = True
         await Messages.send_error_dm(
             msg.author,
             "You need to use giveaway commands in a public channel")
         return
     else:
         # Determine if user is admin
         ctx.god = msg.author.id in config.Config.instance().get_admin_ids()
         if not ctx.god:
             ctx.admin = False
             for g in self.bot.guilds:
                 member = g.get_member(msg.author.id)
                 if member is not None:
                     for role in member.roles:
                         if role.id in config.Config.instance(
                         ).get_admin_roles():
                             ctx.admin = True
                             break
                 if ctx.admin:
                     break
         else:
             ctx.admin = True
     if ctx.command.name not in 'giveaway_stats_cmd':
         # See if user exists in DB
         user = await User.get_user(msg.author)
         if user is None:
             ctx.error = True
             await Messages.send_error_dm(
                 msg.author,
                 f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started."
             )
             return
         elif user.frozen:
             ctx.error = True
             await Messages.send_error_dm(
                 msg.author,
                 f"Your account is frozen. Contact an admin if you need further assistance."
             )
             return
         # Update name, if applicable
         await user.update_name(msg.author.name)
         ctx.user = user
Esempio n. 3
0
    async def statsban_cmd(self, ctx: Context):
        if ctx.error:
            return

        msg = ctx.message

        if ChannelUtil.is_private(msg.channel):
            await Messages.add_x_reaction(msg)
            await Messages.send_error_dm(msg.author, "You can only stats ban in a public channel")
            return

        ban_ids = []
        # Get mentioned users
        for m in msg.mentions:
            ban_ids.append(m.id)
    
        # Get users they are banning by ID alone
        for sec in msg.content.split():
            try:
                numeric = int(sec.strip())
                user = await self.bot.fetch_user(numeric)
                if user is not None:
                    ban_ids.append(user.id)
            except Exception:
                pass

        # remove duplicates and admins
        ban_ids = set(ban_ids)
        ban_ids = [x for x in ban_ids if x not in config.Config.instance().get_admin_ids()]
        for f in ban_ids:
            memba = msg.guild.get_member(f)
            if memba is not None:
                for r in memba.roles:
                    if r.id in [config.Config.instance().get_admin_roles()]:
                        ban_ids.remove(r.id)

        if len(ban_ids) < 1:
            await Messages.add_x_reaction(msg)
            await msg.author.send("Your message has no users to ban")
            return

        # We need to make sure that the stats objects are created for these users before banning them
        to_ban = await User.filter(id__in=ban_ids).all()
        async with in_transaction() as conn:
            for u in to_ban:
                stats = await u.get_stats(msg.guild.id)
                stats.banned = True
                await stats.save(update_fields=['banned'], using_db=conn)

        await msg.author.send(f"{len(ban_ids)} users have been banned")
        await msg.add_reaction("\U0001F528")
Esempio n. 4
0
    async def cog_before_invoke(self, ctx: Context):
        ctx.error = False
        # Only allow tip commands in public channels
        msg = ctx.message
        if ChannelUtil.is_private(
                msg.channel) and ctx.command.name != 'blocks_cmd':
            await Messages.send_error_dm(
                msg.author,
                "You can only view statistics in a server, not via DM.")
            ctx.error = True
            return
        else:
            # Determine if user is admin
            ctx.god = msg.author.id in config.Config.instance().get_admin_ids()
            if not ctx.god:
                ctx.admin = False
                for g in self.bot.guilds:
                    member = g.get_member(msg.author.id)
                    if member is not None:
                        for role in member.roles:
                            if role.id in config.Config.instance(
                            ).get_admin_roles():
                                ctx.admin = True
                                break
                    if ctx.admin:
                        break
            else:
                ctx.admin = True

        # Can't spam stats commands
        if msg.channel.id in config.Config.instance().get_no_spam_channels():
            ctx.error = True
            await Messages.send_error_dm(
                msg.author, "I can't post stats in that channel.")
            return

        if ctx.command.name in ['tipstats_cmd']:
            # Make sure user exists in DB
            user = await User.get_user(msg.author)
            if user is None:
                ctx.error = True
                await Messages.send_error_dm(
                    msg.author,
                    f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started."
                )
                return
            # Update name, if applicable
            await user.update_name(msg.author.name)
            ctx.user = user
Esempio n. 5
0
 async def cog_before_invoke(self, ctx: Context):
     ctx.error = False
     msg = ctx.message
     if ChannelUtil.is_private(msg.channel):
         ctx.error = True
         return
     # See if user exists in DB
     user = await User.get_user(msg.author)
     if user is None:
         ctx.error = True
         await Messages.send_error_dm(
             msg.author,
             f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started."
         )
         return
Esempio n. 6
0
    async def tipban_cmd(self, ctx: Context):
        if ctx.error:
            return

        msg = ctx.message

        if ChannelUtil.is_private(msg.channel):
            await Messages.add_x_reaction(msg)
            await Messages.send_error_dm(msg.author, "You can't ban via DM, need to do it in a server channel")
            return

        ban_ids = []
        # Get mentioned users
        for m in msg.mentions:
            ban_ids.append(m.id)
    
        # Get users they are banning by ID alone
        for sec in msg.content.split():
            try:
                numeric = int(sec.strip())
                user = await self.bot.fetch_user(numeric)
                if user is not None:
                    ban_ids.append(user.id)
            except Exception:
                pass

        # remove duplicates and admins
        ban_ids = set(ban_ids)
        ban_ids = [x for x in ban_ids if x not in config.Config.instance().get_admin_ids()]
        for f in ban_ids:
            memba = msg.guild.get_member(f)
            if memba is not None:
                for r in memba.roles:
                    if r.id in [config.Config.instance().get_admin_roles()]:
                        ban_ids.remove(r.id)

        if len(ban_ids) < 1:
            await Messages.add_x_reaction(msg)
            await msg.author.send("Your message has no users to ban")
            return

        await User.filter(id__in=ban_ids).update(tip_banned=True)

        await msg.author.send(f"{len(ban_ids)} users have been banned")
        await msg.add_reaction("\U0001F528")
Esempio n. 7
0
    async def muted_cmd(self, ctx: Context):
        if ctx.error:
            return

        msg = ctx.message
        user = ctx.user

        if not ChannelUtil.is_private(msg.channel):
            await Messages.add_x_reaction(msg)
            await Messages.send_error_dm(msg.author, "You can only view users you have muted in DM")
            return

        muted_list = await Muted.filter(user=ctx.user).prefetch_related('target_user').all()

        if len(muted_list) < 1:
            await msg.author.send("You haven't muted anybody.")
            return

        # Build user list
        entries = []
        for u in muted_list:
            entries.append(Entry(f"{u.target_user.name}", f"Unmute with `{config.Config.instance().command_prefix}unmute {u.target_user.id}`"))

        # Build pages
        pages = []
        # Overview
        author=f"Muted Users"
        description = f"Use `{config.Config.instance().command_prefix}unmute <user_id>` to unmute a user"
        i = 0
        entry_subset = []
        for e in entries:
            entry_subset.append(e)
            if i == 14:
                pages.append(Page(entries=entry_subset, author=author, description=description))
                i = 0
                entry_subset = []
            else:
                i += 1
        if len(entry_subset) > 0:
            pages.append(Page(entries=entry_subset, author=author, description=description))

        # Start pagination
        pages = Paginator(self.bot, message=msg, page_list=pages,as_dm=True)
        await pages.paginate(start_page=1)
Esempio n. 8
0
 async def cog_before_invoke(self, ctx: Context):
     ctx.error = False
     # Only allow mute commands in private channels
     msg = ctx.message
     if not ChannelUtil.is_private(msg.channel):
         ctx.error = True
         await Messages.send_error_dm(msg.author, "You can only do this in DM")
         return
     # See if user exists in DB
     user = await User.get_user(msg.author)
     if user is None:
         ctx.error = True
         await Messages.send_error_dm(msg.author, f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started.")
         return
     elif user.frozen:
         ctx.error = True
         await Messages.send_error_dm(msg.author, f"Your account is frozen. Contact an admin if you need further assistance.")
         return
     ctx.user = user
Esempio n. 9
0
    async def statsbanned_cmd(self, ctx: Context):
        if ctx.error:
            return

        msg = ctx.message

        if ChannelUtil.is_private(msg.channel):
            await Messages.add_x_reaction(msg)
            await Messages.send_error_dm(msg.author, "You can only view stats banned in a public channel")
            return

        banned_list = await Stats.filter(banned=True, server_id=msg.guild.id).prefetch_related('user').all()

        if len(banned_list) < 1:
            await msg.author.send("There aren't any banned users")
            return

        # Build user list
        entries = []
        for u in banned_list:
            entries.append(Entry(f"{u.user.id}:{u.user.name}", f"Unban with `{config.Config.instance().command_prefix}statsunban {u.user.id}`"))

        # Build pages
        pages = []
        # Overview
        author=f"Stats Banned Users"
        description = f"Use `{config.Config.instance().command_prefix}statsunban <user_id>` to unban a user"
        i = 0
        entry_subset = []
        for e in entries:
            entry_subset.append(e)
            if i == 14:
                pages.append(Page(entries=entry_subset, author=author, description=description))
                i = 0
                entry_subset = []
            else:
                i += 1
        if len(entry_subset) > 0:
            pages.append(Page(entries=entry_subset, author=author, description=description))

        # Start pagination
        pages = Paginator(self.bot, message=msg, page_list=pages,as_dm=True)
        await pages.paginate(start_page=1)
Esempio n. 10
0
    async def blocks_cmd(self, ctx: Context):
        if ctx.error:
            await Messages.add_x_reaction(ctx.message)
            return

        msg = ctx.message
        is_private = ChannelUtil.is_private(msg.channel)

        if not ctx.god and await RedisDB.instance().exists(
                f"blocksspam{msg.channel.id if not is_private else msg.author.id}"
        ):
            await Messages.add_timer_reaction(msg)
            await Messages.send_error_dm(
                msg.author,
                "Why don't you wait awhile before checking the block count again?"
            )
            return

        count, unchecked = await RPCClient.instance().block_count()
        if count is None or unchecked is None:
            await Messages.send_error_dm(
                msg.author, "I couldn't retrieve the current block count")
            return

        embed = discord.Embed(
            colour=0xFBDD11 if Env.banano() else discord.Colour.dark_blue())
        embed.set_author(
            name=f"Here's how many blocks I have",
            icon_url=
            "https://github.com/bbedward/graham_discord_bot/raw/master/assets/banano_logo.png"
            if Env.banano() else
            "https://github.com/bbedward/graham_discord_bot/raw/master/assets/nano_logo.png"
        )
        embed.description = f"```Count: {count:,}\nUnchecked: {unchecked:,}```"

        await RedisDB.instance().set(
            f"blocksspam{msg.channel.id if not is_private else msg.author.id}",
            "as",
            expires=120)
        if is_private:
            await msg.author.send(embed=embed)
        else:
            await msg.channel.send(f"<@{msg.author.id}>", embed=embed)
Esempio n. 11
0
    async def statsunban_cmd(self, ctx: Context):
        if ctx.error:
            return

        msg = ctx.message

        if ChannelUtil.is_private(msg.channel):
            await Messages.add_x_reaction(msg)
            await Messages.send_error_dm(msg.author, "You can only stats unban in a public channel")
            return

        ban_ids = []
        # Get mentioned users
        for m in msg.mentions:
            ban_ids.append(m.id)
    
        # Get users they are banning by ID alone
        for sec in msg.content.split():
            try:
                numeric = int(sec.strip())
                user = await self.bot.fetch_user(numeric)
                if user is not None:
                    ban_ids.append(user.id)
            except Exception:
                pass

        # remove duplicates and admins
        ban_ids = set(ban_ids)

        if len(ban_ids) < 1:
            await Messages.add_x_reaction(msg)
            await msg.author.send("Your message has no users to unban")
            return

        # TODO - tortoise doesnt give us any feedback on update counts atm
        # https://github.com/tortoise/tortoise-orm/issues/126
        await Stats.filter(user_id__in=ban_ids, server_id=msg.guild.id, banned=True).update(banned=False)

        await msg.author.send(f"{len(ban_ids)} users have been unbanned")
        await msg.add_reaction("\U0001F5FD")
Esempio n. 12
0
    async def cog_before_invoke(self, ctx: Context):
        ctx.error = False
        msg = ctx.message
        if ChannelUtil.is_private(ctx.message.channel):
            ctx.error = True
            return
        else:
            # Check admins
            ctx.god = msg.author.id in config.Config.instance().get_admin_ids()
            ctx.admin = False
            author: discord.Member = msg.author
            for role in author.roles:
                if role.id in config.Config.instance().get_admin_roles():
                    ctx.admin = True
                    break

        # Check paused
        if await RedisDB.instance().is_paused():
            ctx.error = True
            await Messages.send_error_dm(
                msg.author,
                f"Transaction activity is currently suspended. I'll be back online soon!"
            )
            return

        # Check anti-spam
        if not ctx.god and await RedisDB.instance().exists(
                f"rainspam{msg.author.id}"):
            ctx.error = True
            await Messages.add_timer_reaction(msg)
            await Messages.send_basic_dm(
                msg.author, "You can only rain once every 5 minutes")
            return

        # Parse some info
        try:
            ctx.send_amount = RegexUtil.find_send_amounts(msg.content)
            if Validators.too_many_decimals(ctx.send_amount):
                await Messages.add_x_reaction(msg)
                await Messages.send_error_dm(
                    msg.author,
                    f"You are only allowed to use {Env.precision_digits()} digits after the decimal."
                )
                ctx.error = True
                return
            elif ctx.send_amount < config.Config.instance().get_rain_minimum():
                ctx.error = True
                await Messages.add_x_reaction(msg)
                await Messages.send_usage_dm(msg.author, RAIN_INFO)
                return
            # See if user exists in DB
            user = await User.get_user(msg.author)
            if user is None:
                await Messages.add_x_reaction(msg)
                await Messages.send_error_dm(
                    msg.author,
                    f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started."
                )
                ctx.error = True
                return
            elif user.frozen:
                ctx.error = True
                await Messages.add_x_reaction(msg)
                await Messages.send_error_dm(
                    msg.author,
                    f"Your account is frozen. Contact an admin if you need further assistance."
                )
                return
            # Update name, if applicable
            await user.update_name(msg.author.name)
            ctx.user = user
        except AmountMissingException:
            await Messages.add_x_reaction(msg)
            await Messages.send_usage_dm(msg.author, RAIN_INFO)
            ctx.error = True
            return
        except AmountAmbiguousException:
            await Messages.add_x_reaction(msg)
            await Messages.send_error_dm(
                msg.author, "You can only specify 1 amount to send")
            ctx.error = True
            return
Esempio n. 13
0
    async def update_activity_stats(msg: discord.Message):
        """Update activity statistics for a user"""
        if ChannelUtil.is_private(msg.channel):
            return
        member = msg.author

        # Ignore if user doesnt have rain role
        has_rain_role = False
        rain_roles = config.Config.instance().get_rain_roles()
        if len(rain_roles) > 0:
            for role in member.roles:
                if role.id in rain_roles:
                    has_rain_role = True
                    break
            if not has_rain_role:
                return

        content_adjusted = Utils.emoji_strip(msg.content)
        if len(content_adjusted) == 0:
            return

        # Get user OBJ from redis if it exists, else create one
        user_key = f"activity:{msg.guild.id}:{msg.author.id}"
        active_stats = await RedisDB.instance().get(user_key)
        if active_stats is None:
            # Create stats and save
            active_stats = {
                'user_id':
                msg.author.id,
                'last_msg':
                datetime.datetime.utcnow().strftime('%m/%d/%Y %H:%M:%S'),
                'msg_count':
                1
            }
            await RedisDB.instance().set(user_key,
                                         json.dumps(active_stats),
                                         expires=1800)
            return
        else:
            active_stats = json.loads(active_stats)

        # Ignore em if they've messaged too recently
        last_msg_dt = datetime.datetime.strptime(active_stats['last_msg'],
                                                 '%m/%d/%Y %H:%M:%S')
        delta_s = (datetime.datetime.utcnow() - last_msg_dt).total_seconds()
        if 90 > delta_s:
            return
        elif delta_s > 1200:
            # Deduct a point
            if active_stats['msg_count'] > 1:
                active_stats['msg_count'] -= 1
            active_stats['last_msg'] = datetime.datetime.utcnow().strftime(
                '%m/%d/%Y %H:%M:%S')
            await RedisDB.instance().set(user_key,
                                         json.dumps(active_stats),
                                         expires=1800)
        else:
            # add a point
            if active_stats['msg_count'] <= Constants.RAIN_MSG_REQUIREMENT * 2:
                active_stats['msg_count'] += 1
                active_stats['last_msg'] = datetime.datetime.utcnow().strftime(
                    '%m/%d/%Y %H:%M:%S')
                await RedisDB.instance().set(user_key,
                                             json.dumps(active_stats),
                                             expires=1800)
            else:
                # Reset key expiry
                active_stats['last_msg'] = datetime.datetime.utcnow().strftime(
                    '%m/%d/%Y %H:%M:%S')
                await RedisDB.instance().set(user_key,
                                             json.dumps(active_stats),
                                             expires=1800)
Esempio n. 14
0
    async def ticketstatus_cmd(self, ctx: Context):
        if ctx.error:
            return

        msg = ctx.message
        user = ctx.user
        author = msg.author
        content = msg.content

        # If private, see what servers they are part of
        guilds = None
        if ChannelUtil.is_private(msg.channel):
            guilds = []
            for g in self.bot.guilds:
                if g.get_member(msg.author.id) is not None:
                    guilds.append(g)
            if len(guilds) == 0:
                return

        # See if they've been spamming
        redis_key = f"ticketspam:{msg.author.id}"
        if not ctx.god:
            spam = await RedisDB.instance().get(redis_key)
            if spam is not None:
                spam = int(spam)
                if spam >= 3:
                    await Messages.send_error_dm(msg.author, "You're temporarily banned from entering giveaways")
                    await Messages.delete_message(msg)
                    return
            else:
                spam = 0
        else:
            spam = 0

        # Get active giveaway(s) - public channel
        if guilds == None:
            gw = await Giveaway.get_active_giveaway(server_id=msg.guild.id)

            if gw is None:
                await Messages.send_error_dm(msg.author, "There aren't any active giveaways.")
                await Messages.delete_message(msg)
                # Block ticket spam
                await RedisDB.instance().set(f"ticketspam:{msg.author.id}", str(spam + 1), expires=3600)
                return

            # Get their active giveaway transaction
            active_tx = await Transaction.filter(giveaway__id=gw.id, sending_user__id=user.id).first()
            response = None
            if active_tx is None:
                if int(gw.entry_fee) > 0:
                    fee_converted = Env.raw_to_amount(int(gw.entry_fee))
                    response = f"There is a fee of **{fee_converted} {Env.currency_symbol()}**!\n"
                    response+= f"Use `{config.Config.instance().command_prefix}ticket {fee_converted}` to pay the fee and enter"
                else:
                    response = f"This giveaway is free to enter\n"
                    response+= f"Use `{config.Config.instance().command_prefix}ticket` to enter."
            else:
                needed = int(gw.entry_fee) - int(active_tx.amount)
                if needed <= 0:
                    response = f"You're already entered into this giveaway"
                else:
                    fee_converted = Env.raw_to_amount(int(gw.entry_fee))
                    paid_converted = Env.raw_to_amount(int(active_tx.amount))
                    response = f"There is a fee of **{fee_converted} {Env.currency_symbol()}**! You've donated **{paid_converted} {Env.currency_symbol()}** but that's not enough to enter!\n"
                    response+= f"Use `{config.Config.instance().command_prefix}ticket {NumberUtil.format_float(fee_converted - paid_converted)}` to pay the fee and enter"

            # Build response
            embed = discord.Embed(colour=0xFBDD11 if Env.banano() else discord.Colour.dark_blue())
            embed.set_author(name=f"Giveaway #{gw.id} is active!", icon_url="https://github.com/bbedward/graham_discord_bot/raw/master/assets/banano_logo.png" if Env.banano() else "https://github.com/bbedward/graham_discord_bot/raw/master/assets/nano_logo.png")
            embed.description = response

            await msg.author.send(embed=embed)
            await Messages.delete_message(msg)
            return
        # Get active giveaways (private channel)
        gws = await Giveaway.get_active_giveaways(server_ids=[g.id for g in guilds])
        if gws is None or len(gws) == 0:
            await Messages.send_error_dm(msg.author, "There aren't any active giveaways.")
            await Messages.delete_message(msg)
            # Block ticket spam
            await RedisDB.instance().set(f"ticketspam:{msg.author.id}", str(spam + 1), expires=3600)
            return

        # Get their active giveaway transaction
        response = None
        for gw in gws:
            active_tx = await Transaction.filter(giveaway__id=gw.id, sending_user__id=user.id).first()
            response = f"**Giveaway #{gw.id}**\n" if response is None else f"**Giveaway #{gw.id}**:\n"
            if active_tx is None:
                if int(gw.entry_fee) > 0:
                    fee_converted = Env.raw_to_amount(int(gw.entry_fee))
                    response+= f"There is a fee of **{fee_converted} {Env.currency_symbol()}**!\n"
                    response+= f"Use `{config.Config.instance().command_prefix}ticket {fee_converted} id={gw.id}` to pay the fee and enter\n"
                else:
                    response+= f"This giveaway is free to enter\n"
                    response+= f"Use `{config.Config.instance().command_prefix}ticket id={gw.id}` to enter.\n"
            else:
                needed = int(gw.entry_fee) - int(active_tx.amount)
                if needed <= 0:
                    response+= f"You're already entered into this giveaway"
                else:
                    fee_converted = Env.raw_to_amount(int(gw.entry_fee))
                    paid_converted = Env.raw_to_amount(int(active_tx.amount))
                    response+= f"There is a fee of **{fee_converted} {Env.currency_symbol()}**! You've donated **{paid_converted} {Env.currency_symbol()}** but that's not enough to enter!\n"
                    response+= f"Use `{config.Config.instance().command_prefix}ticket {NumberUtil.format_float(fee_converted - paid_converted)} id={gw.id}` to pay the fee and enter\n"

        # Build response
        embed = discord.Embed(colour=0xFBDD11 if Env.banano() else discord.Colour.dark_blue())
        embed.set_author(name=f"Here are the active giveaways!", icon_url="https://github.com/bbedward/graham_discord_bot/raw/master/assets/banano_logo.png" if Env.banano() else "https://github.com/bbedward/graham_discord_bot/raw/master/assets/nano_logo.png")
        embed.description = response

        await msg.author.send(embed=embed)
        await Messages.delete_message(msg)
Esempio n. 15
0
    async def ticket_cmd(self, ctx: Context):
        if ctx.error:
            return

        msg = ctx.message
        user = ctx.user
        author = msg.author
        content = msg.content

        is_private = ChannelUtil.is_private(msg.channel)
        id=None

        if is_private:
            if 'id=' not in msg.content:
                await Messages.send_usage_dm(msg.author, TICKET_INFO)
                await Messages.add_x_reaction(msg)
                return            

            # Parse message
            split_content = msg.content.split(' ')
            cleaned_content = msg.content
            for split in split_content:
                if split.startswith('id='):
                    cleaned_content.replace(split, "")
                    split = split.replace('id=','').strip()
                    if not split:
                        continue
                    try:
                        id = int(split)
                    except ValueError as e:
                        await Messages.add_x_reaction(msg)
                        await Messages.send_usage_dm(msg.author, TICKET_INFO)
                        return

        # See if they've been spamming
        redis_key = f"ticketspam:{msg.author.id}"
        if not ctx.god:
            spam = await RedisDB.instance().get(redis_key)
            if spam is not None:
                spam = int(spam)
                if spam >= 3:
                    await Messages.send_error_dm(msg.author, "You're temporarily banned from entering giveaways")
                    await Messages.delete_message_if_ok(msg)
                    return
            else:
                spam = 0
        else:
            spam = 0

        # Get active giveaway
        if id is None:
            gw = await Giveaway.get_active_giveaway(server_id=msg.guild.id)
        else:
            gw = await Giveaway.get_active_giveaway_by_id(id=id)

        if gw is None:
            await Messages.send_error_dm(msg.author, "There aren't any active giveaways to enter.")
            await Messages.delete_message_if_ok(msg)
            # Block ticket spam
            await RedisDB.instance().set(f"ticketspam:{msg.author.id}", str(spam + 1), expires=3600)
            return

        # Check roles
        if is_private:
            guild = self.bot.get_guild(gw.server_id)
            if guild is None:
                await Messages.send_error_dm(msg.author, "Something went wrong, ask my master for help")
                return
            member = guild.get_member(msg.author.id)
            if member is None:
                await "You're not a member of that server"
                return
            msg.author = member
    
        if not await self.role_check(msg):
            return

        # There is an active giveaway, enter em if not already entered.
        active_tx = await Transaction.filter(giveaway__id=gw.id, sending_user__id=user.id).first()
        if active_tx is not None and int(gw.entry_fee) == 0:
            await Messages.send_error_dm(msg.author, "You've already entered this giveaway.")
            await Messages.delete_message_if_ok(msg)
            return
        elif active_tx is None:
            paid_already = 0
        else:
            paid_already = int(active_tx.amount)
    
        if paid_already >= int(gw.entry_fee) and int(gw.entry_fee) > 0:
            await Messages.send_error_dm(msg.author, "You've already entered this giveaway.")
            await Messages.delete_message_if_ok(msg)
            return

        # Enter em
        fee_raw = int(gw.entry_fee) - paid_already
        fee = Env.raw_to_amount(fee_raw)
        # Check balance if fee is > 0
        if fee > 0:
            try:
                amount = RegexUtil.find_float(msg.content)
                if amount < fee:
                    await Messages.send_error_dm(msg.author, f"This giveaway has a fee of {fee} {Env.currency_symbol()}. The amount you specified isn't enough to cover the entry fee")
                    await Messages.delete_message_if_ok(msg)
                    return
            except AmountMissingException:
                await Messages.send_error_dm(msg.author, f"This giveaway has a fee, you need to specify the amount to enter. `{config.Config.instance().command_prefix}ticket {fee}`")
                await Messages.delete_message_if_ok(msg)
                return
            available_balance = Env.raw_to_amount(await user.get_available_balance())
            if fee > available_balance:
                await Messages.add_x_reaction(ctx.message)
                await Messages.send_error_dm(msg.author, f"Your balance isn't high enough to complete this tip. You have **{available_balance} {Env.currency_symbol()}**, but this entry would cost you **{fee} {Env.currency_symbol()}**")
                await Messages.delete_message_if_ok(msg)
                await RedisDB.instance().set(f"ticketspam:{msg.author.id}", str(spam + 1), expires=3600)
                return
        await Transaction.create_transaction_giveaway(
            user,
            fee,
            gw
        )
        await Messages.send_success_dm(msg.author, f"You've successfully been entered into giveaway #{gw.id}")
        await Messages.delete_message_if_ok(msg)
        return
Esempio n. 16
0
 async def cog_before_invoke(self, ctx: Context):
     ctx.error = False
     # Remove duplicate mentions
     ctx.message.mentions = set(ctx.message.mentions)
     # Only allow tip commands in public channels
     msg = ctx.message
     if ChannelUtil.is_private(msg.channel):
         ctx.error = True
         return
     else:
         # Check admins
         ctx.god = msg.author.id in config.Config.instance().get_admin_ids()
         ctx.admin = False
         author: discord.Member = msg.author
         for role in author.roles:
             if role.id in config.Config.instance().get_admin_roles():
                 ctx.admin = True
                 break
     # Check paused
     if await RedisDB.instance().is_paused():
         ctx.error = True
         await Messages.send_error_dm(
             msg.author,
             f"Transaction activity is currently suspended. I'll be back online soon!"
         )
         return
     # See if user exists in DB
     user = await User.get_user(msg.author)
     if user is None:
         ctx.error = True
         await Messages.send_error_dm(
             msg.author,
             f"You should create an account with me first, send me `{config.Config.instance().command_prefix}help` to get started."
         )
         return
     elif user.frozen:
         ctx.error = True
         await Messages.send_error_dm(
             msg.author,
             f"Your account is frozen. Contact an admin if you need further assistance."
         )
         return
     # Update name, if applicable
     await user.update_name(msg.author.name)
     ctx.user = user
     # See if amount meets tip_minimum requirement
     try:
         send_amount = RegexUtil.find_float(msg.content)
         if ctx.command.name == 'tiprandom_cmd' and send_amount < Constants.TIPRANDOM_MINIMUM:
             raise AmountMissingException(
                 f"Tip random amount is too low, minimum is {Constants.TIPRANDOM_MINIMUM}"
             )
         elif ctx.command.name != 'tiprandom_cmd' and send_amount < Constants.TIP_MINIMUM:
             raise AmountMissingException(
                 f"Tip amount is too low, minimum is {Constants.TIP_MINIMUM}"
             )
         elif Validators.too_many_decimals(send_amount):
             await Messages.send_error_dm(
                 ctx.message.author,
                 f"You are only allowed to use {Env.precision_digits()} digits after the decimal."
             )
             ctx.error = True
             return
     except AmountMissingException:
         ctx.error = True
         if ctx.command.name == 'tip_cmd':
             await Messages.send_usage_dm(msg.author, TIP_INFO)
         elif ctx.command.name == 'tipsplit_cmd':
             await Messages.send_usage_dm(msg.author, TIPSPLIT_INFO)
         elif ctx.command.name == 'tiprandom_cmd':
             await Messages.send_usage_dm(msg.author, TIPRANDOM_INFO)
         return
     ctx.send_amount = send_amount