見出し画像

Discord.py 自分なりの認証Botを作った。

PythonでDiscordBotを作成して約半年。
他の多機能Botは自分には使いづらいと感じている方、自分のBotが欲しいと考えている方。是非ご覧ください!


最低限動く認証Botを作ってみる

1, 認証Botの原理

・コマンドを実行する際に付与するロールを取得
・Embedとボタンを出し、クリックしたユーザーに取得したロールを付与する

2, 1番の原理だけでBotを作った際の注意点

・複数個置いた際にバグる
・再起動した時、認証することができなくなる(取得したロールが消える)

3, きちんと使える認証Botを作ってみる

@tree.command(name='verify', description='認証')
@app_commands.describe(
   role='認証時に付与するロール',
   title='認証パネルのタイトル',
   description='認証パネルの詳細',
)
async def verify(interaction: discord.Interaction, role:discord.Role,title:str='認証', description:str='ボタンを押して認証を開始!'):
    await interaction.response.defer(ephemeral=True)
    with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'w', encoding='UTF-8') as file:
       file.write(f'{role.id}')
    embed=discord.Embed(title=title, color=discord.Colour.green())
    embed.add_field(name='', value=description)
    await interaction.channel.send(embed=embed, view=Verify_nomal())

まずは基本となるEmbedとbutton(viewだけ)を書きました。
9行目のファイルを開く動作は再起動した後も認証できるようにするためです。


class Verify_nomal(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @discord.ui.button(label='認証', style=discord.ButtonStyle.green, row=1, custom_id='verify_nomal')
    async def nomal_verify(self, interaction: discord.Interaction, button: discord.ui.Button):
        rol=[]
        with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'r', encoding='UTF-8') as file:
            for i in file:
                i=i.replace('\n', '')
                rol.append(i)
        role=interaction.guild.get_role(int(rol[0]))
        await interaction.user.add_roles(role)
        embed=discord.Embed(title='認証完了',color=discord.Colour.green())
        embed.add_field(name='', value=f'認証ユーザー: {interaction.user.mention}\n付与ロール: {role.mention}')
        await interaction.response.send_message(embed=embed, ephemeral=True)

こちらはbuttonのコードです。
面倒臭いですが、いちいちファイルを開いてロールIDを取得し、
ロールIDからロールを取得して付与します。

role=interaction.guild.get_role(int(rol[0]))
await interaction.user.add_roles(role)

理由としては先ほど挙げた 再起動しても使えるようにするため です。
これで何個設置しても何回再起動しても認証できるようになります!

カスタマイズしてみる

ここまでは最低限動く認証Botでした。
次は認証方法をいろんなものにしてみたり、カスタマイズしてみましょう!

1, 認証方法を選択式にする

これまでは ボタンを押して認証ロールを与える だけでしたが、次は計算認証なども作ってみましょう!
少し難しく聞こえるかもしれませんが変更を加えるところは大体はbuttonの部分です!

class Math(Modal):
    def __init__(self, title: str) -> None:
        one=random.randint(1, 30)
        two=random.randint(1, 30)
        ans=one+two
        global answer
        answer=ans
        super().__init__(title=title)
        self.answer = TextInput(label="計算問題", placeholder=f'{one} + {two} = ??', style=TextStyle.short)
        self.add_item(self.answer)

    async def on_submit(self, interaction: Interaction) -> None:
        if int(self.answer.value)==answer: #計算結果が正しい
            rol=[]
            with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'r', encoding='UTF-8') as file:
                for i in file:
                    i=i.replace('\n', '')
                    rol.append(i)
            role=interaction.guild.get_role(int(rol[0]))
            await interaction.user.add_roles(role)
            embed=discord.Embed(title='認証完了',color=discord.Colour.green())
            embed.add_field(name='', value=f'認証ユーザー: {interaction.user.mention}\n付与ロール: {role.mention}')
            await interaction.response.send_message(embed=embed, ephemeral=True)
        else: #計算結果が正しくない
           await interaction.response.send_message('計算が間違えています。',ephemeral=True)


class Verify_math(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @discord.ui.button(label='認証', style=discord.ButtonStyle.green, row=1, custom_id='verify_math')
    async def math_verify(self, interaction: discord.Interaction, button: discord.ui.Button):
        modal=Math('認証')
        await interaction.response.send_modal(modal)

どうだったでしょうか?
モーダルウィンドウを使用し、計算してもらう。答えが正しければロールを付与し、正しくなければ付与しません。
簡単な計算ですが荒らしやBotなどの対策になります!

2, ログを送信する

あまりいないかとは思いますが一応….
認証をされた際にどこかにログを送信するようにします。
やり方としては、

async def verify(interaction: discord.Interaction, role:discord.Role, log: discord.TextChannel,title:str='認証', description:str='ボタンを押して認証を開始!'):

このようにログチャンネルを取得します。
その次にファイルを開くと思うのですがそこにログチャンネルのIDを入れます。

with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'w', encoding='UTF-8') as file:
       file.write(f'{role.id}\n{log.id}')

まずこうすることでログチャンネルを記憶します。
その次に認証を済ませ終わった後のコードに今から書くコードを付けたします。

log_ch=[]
with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'r', encoding='UTF-8') as file:
    for i in file:
        i=i.replace('\n', '')
        log_ch.append(i)
channel=client.get_channel(int(log_ch[1])
embed=discord.Embed(title='認証ログ', color=discord.Colour.green())
embed.add_field(name='', value=f'{interaction.user.mention}さんが認証しました')
await channel.send(embed=embed)

このようにすれば、決めたチャンネルに認証のログを送ることが可能です!

全体コード

class Math(Modal):
    def __init__(self, title: str) -> None:
        one=random.randint(1, 30)
        two=random.randint(1, 30)
        ans=one+two
        global ansa
        ansa=ans
        super().__init__(title=title)
        self.answer = TextInput(label="計算問題", placeholder=f'{one} + {two} = ??', style=TextStyle.short)
        self.add_item(self.answer)

    async def on_submit(self, interaction: Interaction) -> None:
        if int(self.answer.value)==ansa:
            rol=[]
            with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'r', encoding='UTF-8') as file:
                for i in file:
                    i=i.replace('\n', '')
                    rol.append(i)
            role=interaction.guild.get_role(int(rol[0]))
            await interaction.user.add_roles(role)
            embed=discord.Embed(title='認証完了',color=discord.Colour.green())
            embed.add_field(name='', value=f'認証ユーザー: {interaction.user.mention}\n付与ロール: {role.mention}')
            await interaction.response.send_message(embed=embed, ephemeral=True)
        else:
           await interaction.response.send_message('計算が間違えています。',ephemeral=True)
          


class Verify_nomal(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @discord.ui.button(label='認証', style=discord.ButtonStyle.green, row=1, custom_id='verify_nomal')
    async def nomal_verify(self, interaction: discord.Interaction, button: discord.ui.Button):
        rol=[]
        with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'r', encoding='UTF-8') as file:
            for i in file:
                i=i.replace('\n', '')
                rol.append(i)
        role=interaction.guild.get_role(int(rol[0]))
        await interaction.user.add_roles(role)
        embed=discord.Embed(title='認証完了',color=discord.Colour.green())
        embed.add_field(name='', value=f'認証ユーザー: {interaction.user.mention}\n付与ロール: {role.mention}')
        await interaction.response.send_message(embed=embed, ephemeral=True)

class Verify_math(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @discord.ui.button(label='認証', style=discord.ButtonStyle.green, row=1, custom_id='verify_math')
    async def math_verify(self, interaction: discord.Interaction, button: discord.ui.Button):
        modal=Math('認証')
        await interaction.response.send_modal(modal)

class verify_style(Enum):
   通常認証='通常認証'
   計算問題='計算問題'


@tree.command(name='verify', description='認証')
@app_commands.describe(
   role='認証時に付与するロール',
   title='認証パネルのタイトル',
   description='認証パネルの詳細',


)
async def verify(interaction: discord.Interaction, role:discord.Role,title:str='認証', description:str='ボタンを押して認証を開始!', style:verify_style='通常認証'):
    await interaction.response.defer(ephemeral=True)
    with open(f'verify_{interaction.guild.id}-{interaction.channel.id}', 'w', encoding='UTF-8') as file:
       file.write(f'{role.id}')
    embed=discord.Embed(title=title, color=discord.Colour.green())
    embed.add_field(name='', value=description)
    if style.value=='通常認証':
        await interaction.channel.send(embed=embed, view=Verify_nomal())
    else:
       await interaction.channel.send(embed=embed, view=Verify_math())

最後に

最後までご覧頂きありがとうございました!
見にくいところもあったかと思いますが、少しでも参考になれば幸いです。
これからもこのような投稿を定期的にしていきますのでよければフォローお願いします!


いいなと思ったら応援しよう!