Skip to content

tux.cogs.admin.mail

Classes:

Name Description
Mail

Classes

Mail(bot: Tux)

Bases: Cog

Methods:

Name Description
register

Registers a user for mail.

Source code in tux/cogs/admin/mail.py
Python
def __init__(self, bot: Tux) -> None:
    self.bot = bot
    self.api_url = CONFIG.MAILCOW_API_URL
    self.headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "X-API-Key": CONFIG.MAILCOW_API_KEY,
        "Authorization": f"Bearer {CONFIG.MAILCOW_API_KEY}",
    }
    self.default_options: dict[str, str | list[str]] = {
        "active": "1",
        "domain": "atl.tools",
        "password": "ErrorPleaseReportThis",
        "password2": "ErrorPleaseReportThis",
        "quota": "3072",
        "force_pw_update": "1",
        "tls_enforce_in": "0",
        "tls_enforce_out": "0",
        "tags": ["discord_member"],
    }

Functions

register(interaction: discord.Interaction, member: discord.Member, username: str) -> None async

Registers a user for mail.

Parameters:

Name Type Description Default
interaction Interaction

The interaction object for the command.

required
member Member

The member to register for mail.

required
username str

The username to register for mail.

required

Raises:

Type Description
Forbidden

If the bot is unable to send a DM to the member.

Source code in tux/cogs/admin/mail.py
Python
@mail.command(name="register")
@checks.ac_has_pl(5)
async def register(
    self,
    interaction: discord.Interaction,
    member: discord.Member,
    username: str,
) -> None:
    """
    Registers a user for mail.

    Parameters
    ----------
    interaction : discord.Interaction
        The interaction object for the command.
    member : discord.Member
        The member to register for mail.
    username : str
        The username to register for mail.

    Raises
    ------
    discord.Forbidden
        If the bot is unable to send a DM to the member.
    """
    if not username.isalnum():
        await interaction.response.send_message(
            "Username must be alphanumeric and contain no spaces.",
            ephemeral=True,
            delete_after=30,
        )
        return

    if interaction.guild:
        password = self._generate_password()
        mailbox_data = self._prepare_mailbox_data(username, password, member.id)

        async with httpx.AsyncClient(timeout=10.0) as client:
            try:
                response = await client.post(
                    f"{self.api_url}/add/mailbox",
                    headers=self.headers,
                    json=mailbox_data,
                )

                await self._handle_response(interaction, response, member, password)

            except httpx.RequestError as exc:
                await interaction.response.send_message(
                    f"An error occurred while requesting {exc.request.url!r}.",
                    ephemeral=True,
                    delete_after=30,
                )
                logger.error(f"HTTP request error: {exc}")
    else:
        await interaction.response.send_message(
            "This command can only be used in a guild (server).",
            ephemeral=True,
            delete_after=30,
        )
_generate_password() -> str staticmethod

Generates a random password for the mailbox.

Returns:

Type Description
str

The generated password.

Source code in tux/cogs/admin/mail.py
Python
@staticmethod
def _generate_password() -> str:
    """
    Generates a random password for the mailbox.

    Returns
    -------
    str
        The generated password.
    """
    password = "changeme" + "".join(str(random.randint(0, 9)) for _ in range(6))
    password += "".join(random.choice("!@#$%^&*") for _ in range(4))
    return password
_prepare_mailbox_data(username: str, password: str, member_id: int) -> MailboxData

Prepares the mailbox data for the API request.

Parameters:

Name Type Description Default
username str

The username to register for mail.

required
password str

The password to register for mail.

required
member_id int

The ID of the member to register for mail.

required
Source code in tux/cogs/admin/mail.py
Python
def _prepare_mailbox_data(
    self,
    username: str,
    password: str,
    member_id: int,
) -> MailboxData:
    """
    Prepares the mailbox data for the API request.

    Parameters
    ----------
    username : str
        The username to register for mail.
    password : str
        The password to register for mail.
    member_id : int
        The ID of the member to register for mail.
    """
    mailbox_data = self.default_options.copy()

    mailbox_data.update(
        {
            "local_part": username,
            "name": username,
            "password": password,
            "password2": password,
            "tags": self.default_options["tags"] + [str(member_id)]
            if isinstance(self.default_options["tags"], list)
            else [str(member_id)],
        },
    )

    return mailbox_data
_handle_response(interaction: discord.Interaction, response: httpx.Response, member: discord.Member, password: str) -> None async

Handles the response from the API request.

Parameters:

Name Type Description Default
interaction Interaction

The interaction object for the command.

required
response Response

The response from the API request.

required
member Member

The member to register for mail.

required
password str

The password to register for mail.

required
Source code in tux/cogs/admin/mail.py
Python
async def _handle_response(
    self,
    interaction: discord.Interaction,
    response: httpx.Response,
    member: discord.Member,
    password: str,
) -> None:
    """
    Handles the response from the API request.

    Parameters
    ----------
    interaction : discord.Interaction
        The interaction object for the command.
    response : httpx.Response
        The response from the API request.
    member : discord.Member
        The member to register for mail.
    password : str
        The password to register for mail.
    """
    if response.status_code == 200:
        result: list[dict[str, str | None]] = response.json()
        logger.info(f"Response JSON: {result}")

        if mailbox_info := self._extract_mailbox_info(result):
            await interaction.response.send_message(
                f"Successfully registered {mailbox_info} for mail.",
                ephemeral=True,
            )

            await self._send_dm(interaction, member, mailbox_info, password)

        else:
            await interaction.response.send_message(
                "Failed to register the mailbox. Quota limit exceeded.",
                ephemeral=True,
            )

    elif response.status_code == 401:
        await interaction.response.send_message("Unauthorized. Check your API credentials.", ephemeral=True)

    else:
        await interaction.response.send_message(
            f"Failed to register the requested username for mail. Status code: {response.status_code}.",
            ephemeral=True,
            delete_after=30,
        )
_extract_mailbox_info(result: list[dict[str, str | None]]) -> str | None staticmethod

Extracts the mailbox information from the response.

Parameters:

Name Type Description Default
result list[dict[str, str | None]]

The response from the API request.

required

Returns:

Type Description
str | None

The mailbox information.

Source code in tux/cogs/admin/mail.py
Python
@staticmethod
def _extract_mailbox_info(result: list[dict[str, str | None]]) -> str | None:
    """
    Extracts the mailbox information from the response.

    Parameters
    ----------
    result : list[dict[str, str | None]]
        The response from the API request.

    Returns
    -------
    str | None
        The mailbox information.
    """
    for item in result:
        if "msg" in item:
            msg = item["msg"]

            if msg and "mailbox_added" in msg:
                return msg[1]
            if msg and "mailbox_quota_left_exceeded" in msg:
                return None

    return None
_send_dm(interaction: discord.Interaction, member: discord.Member, mailbox_info: str, password: str) -> None async staticmethod

Sends a DM to the member with the mailbox information.

Parameters:

Name Type Description Default
interaction Interaction

The interaction object for the command.

required
member Member

The member to send the DM to.

required
mailbox_info str

The mailbox information to send to the member.

required
password str

The password to send to the member.

required
Source code in tux/cogs/admin/mail.py
Python
    @staticmethod
    async def _send_dm(
        interaction: discord.Interaction,
        member: discord.Member,
        mailbox_info: str,
        password: str,
    ) -> None:
        """
        Sends a DM to the member with the mailbox information.

        Parameters
        ----------
        interaction : discord.Interaction
            The interaction object for the command.
        member : discord.Member
            The member to send the DM to.
        mailbox_info : str
            The mailbox information to send to the member.
        password : str
            The password to send to the member.
        """
        dm_message = f"""
**Your mailbox has been successfully registered!**

**Email Address**: `{mailbox_info}`
**Access Mailbox**: [mail.atl.tools](https://mail.atl.tools)
**Default Password**: ||`{password}`||

**Please change your password after logging in for the first time.**

After changing, you Ban also set up your mailbox on your mobile device or email client following the instructions provided on the mail server. Alternatively, feel free to use our webmail interface available at [mail.atl.tools/SOGo](https://mail.atl.tools/SOGo/).

If you have any questions or need assistance, please feel free to reach out to the server staff. Enjoy your new mailbox! 📬
        """
        try:
            await member.send(f"Hello {member.mention},\n{dm_message.strip()}", suppress_embeds=True)

        except discord.Forbidden:
            await interaction.response.send_message(
                f"Failed to send a DM to {member.mention}. Please enable DMs from server members.",
                ephemeral=True,
                delete_after=30,
            )