Skip to content

Commit

Permalink
+ [ 26 files changed ] Merge branch 'dev' into overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
null2264 committed Sep 6, 2021
2 parents 4508037 + d3949ab commit 4466d13
Show file tree
Hide file tree
Showing 26 changed files with 983 additions and 578 deletions.
36 changes: 33 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
# v3.3

## 3.3.0

- [**New**] Added realurl (get real url of a shorten url)
- [**Improved**] Added case number to modlog message
- [**Changed**] Rename `Bot.master` -> `Bot.owner_ids`
- [**Fixed**] Fix Admin commands' checks not working properly
- [**Improved**] Decrease modlog delay to 2 seconds delay
- [**Improved**] Merged `>help filter: custom` with `>command list`
- [**Changed**] `>command disable` and `>command enable` no longer uses flag,
replaced with choice buttons when there's more than 1 type is found with
identical name
- [**Fixed**] Anilist commands now works in DMs
- [**Fixed**] `>manga search` actually search for manga not anime
- [**Improved**] User now given choices between command and category when their
names are conflicted
- [**Improved**] Custom command list now paginated
- [**New**] Added "compact mode" to paginator
- [**Improved**] Failed NSFW check will now properly "yell" at the executor,
instead of yelling "Check failed!"
- [**Fixed**] Fixed caselog type `mute` being inconsistent ( [**For
self-hoster**] sql query to fix your database: `UPDATE OR IGNORE caseLog SET
type='mute' WHERE type='muted'`)
- [**New**] Added createdAt column to caselog ( [**For self-hoster**]: sql
query to add this column without dropping the table `ALTER TABLE caseLog ADD
COLUMN createdAt INTEGER DEFAULT 0`) [**NOTE**]: Old cases' time will return
either "Unknown" or `1/1/1970`
- [**New**] Added `caselogs`/`cases` command to get moderator's cases
- [**Improved**] Modlog now log unmute and unban
- [**Disabled**] Disable `google` command (blocking the whole bot)

# v3.2

## 3.2.9
Expand All @@ -8,8 +40,6 @@

- [**Fixed**] Fixed Moderation commands' checks not working properly

<!-- (TODO: Check if Admin commands' checks also broken) -->

## 3.2.7

- [**Fixed**] Fixed help command not working in DMs
Expand All @@ -18,7 +48,7 @@

## 3.2.6

- [**Fixed**] Fixed modlog. Added 5 second delay, letting Audit Logs to update
- [**Fixed**] Fixed modlog. Added 5 seconds delay, letting Audit Logs to update
before sending modlog

## 3.2.5
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,17 @@ Moved to [CHANGELOG.md](./CHANGELOG.md)
## Plans

- Event for ~~member boosting a guild~~ (Just need to implement setup for it)
- Properly support different SQL scheme (databases have `database_url.scheme` to check scheme type)
- Tags (stripped version of custom command)
- Unify categories/exts emoji
- Channel manager commands
- Reaction Role
- Reaction Role (With buttons... button role?)
- Starboard

### Pending Plan

- i18n using gettext (Learning how gettext works)
- Slash command (RIP dpy, have to design this myself for now)
- Slash command (Waiting for implementation)
- Properly support different SQL scheme (designing best way to do this)

### Scrapped Plan

Expand Down
29 changes: 20 additions & 9 deletions core/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import logging
import os
import re
import warnings
from collections import Counter
from contextlib import suppress
from typing import Any, Dict, Iterable, List, Optional, Union
Expand Down Expand Up @@ -60,7 +61,7 @@ class ziBot(commands.Bot):

# --- NOTE: Information about the bot
author: str = getattr(config, "author", "ZiRO2264#9999")
version: str = "`3.2.9` - `overhaul`"
version: str = "`3.3.0` - `overhaul`"
links: Dict[str, str] = getattr(
config,
"links",
Expand All @@ -74,16 +75,20 @@ class ziBot(commands.Bot):
# ---

def __init__(self) -> None:
# custom intents, required since dpy v1.5
intents = discord.Intents.all()

super().__init__(
command_prefix=_callablePrefix,
description=(
"A **free and open source** multi-purpose **discord bot** "
"created by ZiRO2264, formerly called `ziBot`."
),
case_insensitive=True,
intents=discord.Intents.all(),
intents=intents,
heartbeat_timeout=150.0,
)

# make cogs case insensitive
self._BotBase__cogs: commands.core._CaseInsensitiveDict = (
commands.core._CaseInsensitiveDict()
Expand All @@ -98,7 +103,7 @@ def __init__(self) -> None:

# Bot master(s)
# self.master = (186713080841895936,)
self.master: tuple = (
self.owner_ids: tuple = (
tuple()
if not hasattr(config, "botMasters")
else tuple([int(master) for master in config.botMasters])
Expand Down Expand Up @@ -197,16 +202,17 @@ async def asyncInit(self) -> None:
async def startUp(self) -> None:
"""Will run when the bot ready"""
await self.wait_until_ready()
if not self.master:

if not self.owner_ids:
# If self.master not set, warn the hoster
self.logger.warning(
"No master is set, you may not able to use certain commands! (Unless you own the Bot Application)"
)

# Add application owner into bot master list
# Add application owner into owner_ids list
owner: discord.User = (await self.application_info()).owner
if owner and owner.id not in self.master:
self.master += (owner.id,)
if owner and owner.id not in self.owner_ids:
self.owner_ids += (owner.id,)

# change bot's presence into guild live count
self.changing_presence.start()
Expand All @@ -216,6 +222,11 @@ async def startUp(self) -> None:
if not hasattr(self, "uptime"):
self.uptime: datetime.datetime = utcnow()

@property
def master(self):
warnings.warn("Bot.master is deprecated, use self.owner_ids instead")
return self.owner_ids

async def getGuildConfigs(
self, guildId: int, filters: Iterable = "*", table: str = "guildConfigs"
) -> Dict[str, Any]:
Expand Down Expand Up @@ -609,7 +620,7 @@ async def on_message(self, message) -> None:
message.author.bot
or message.author.id in self.blacklist.users
or (message.guild and message.guild.id in self.blacklist.guilds)
) and message.author.id not in self.master:
) and message.author.id not in self.owner_ids:
return

# if bot is mentioned without any other message, send prefix list
Expand All @@ -636,7 +647,7 @@ async def on_message_edit(self, before, after):
message.author.bot
or message.author.id in self.blacklist.users
or (message.guild and message.guild.id in self.blacklist.guilds)
) and message.author.id not in self.master:
) and message.author.id not in self.owner_ids:
return

await self.process(message)
Expand Down
4 changes: 2 additions & 2 deletions core/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def has_guild_permissions(**perms):
async def predicate(ctx):
orig = commands.has_guild_permissions(**perms).predicate
try:
isMaster = ctx.author.id in ctx.bot.master
isMaster = ctx.author.id in ctx.bot.owner_ids
except AttributeError:
isMaster = False
return isMaster or await orig(ctx)
Expand All @@ -21,7 +21,7 @@ async def predicate(ctx):

def is_botmaster():
def predicate(ctx):
return ctx.author.id in ctx.bot.master
return ctx.author.id in ctx.bot.owner_ids

return commands.check(predicate)

Expand Down
5 changes: 5 additions & 0 deletions core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,8 @@ def __init__(self, missing_permissions=None, *args):
)

super().__init__(message, *args)


class NotNSFWChannel(CommandError):
def __init__(self):
super().__init__("You're only allowed to use this command in a NSFW channels!")
74 changes: 62 additions & 12 deletions core/menus.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from __future__ import annotations

import asyncio
from collections import namedtuple
from contextlib import suppress
from typing import List, Optional, Union
from typing import TYPE_CHECKING, Any, Iterable, List, Optional, Union

import discord
from discord.ext import menus
Expand All @@ -9,6 +12,10 @@
from core.views import ZView


if TYPE_CHECKING:
from core.context import Context


class ZMenu(menus.MenuPages):
def __init__(self, source, init_msg=None, check_embeds=True, ping=False, loop=None):
super().__init__(source=source, check_embeds=check_embeds)
Expand Down Expand Up @@ -46,7 +53,7 @@ async def finalize(self, timed_out):


class ZReplyMenu(ZMenu):
def __init__(self, source, ping=False):
def __init__(self, source, ping=False) -> None:
self.ping = ping or False
super().__init__(source=source, check_embeds=True)

Expand Down Expand Up @@ -74,15 +81,20 @@ class ZMenuView(ZView):

def __init__(
self,
ctx,
ctx: Context,
*,
timeout: float = 180.0,
ownerOnly: bool = True,
) -> None:
super().__init__(ctx.author, timeout=timeout)
owner: Union[discord.User, discord.Member] = ctx.author
super().__init__(owner, timeout=timeout)
self.context = ctx
self._message: Optional[discord.Message] = None
self.currentPage: int = 0
if isinstance(owner, discord.Member):
self.compact = owner.is_on_mobile()
else:
self.compact = False

def shouldAddButtons(self):
return True
Expand Down Expand Up @@ -118,12 +130,14 @@ class ZMenuPagesView(ZMenuView):

def __init__(
self,
ctx,
ctx: Context,
source: Union[menus.PageSource, Pages],
**kwargs,
) -> None:
self._source: Union[menus.PageSource, Pages] = source
super().__init__(ctx, **kwargs)
self.pageFmt = ("Page " if not self.compact else "") + "{current}/{last}"
self._pageInfo.label = self.pageFmt.format(current="N/A", last="N/A")

def shouldAddButtons(self):
source = self._source
Expand Down Expand Up @@ -161,10 +175,12 @@ async def sendInitialMessage(self, ctx):
kwargs = await self.getPage(0)
if self.shouldAddButtons():
kwargs["view"] = self
self._pageInfo.label = f"Page 1/{self.getMaxPages()}"
self._pageInfo.label = self.pageFmt.format(
current="1", last=self.getMaxPages()
)
if self.getMaxPages() == 2:
self.remove_item(self._first)
self.remove_item(self._last)
self.remove_item(self._first) # type: ignore
self.remove_item(self._last) # type: ignore
return await ctx.try_reply(**kwargs)

async def sendPage(
Expand All @@ -175,8 +191,10 @@ async def sendPage(

self.currentPage = pageNumber
kwargs = await self.getPage(pageNumber)
self._pageInfo.label = f"Page {pageNumber+1}/{self.getMaxPages()}"
await interaction.message.edit(view=self, **kwargs)
self._pageInfo.label = self.pageFmt.format(
current=pageNumber + 1, last=self.getMaxPages()
)
await interaction.message.edit(view=self, **kwargs) # type: ignore

async def sendCheckedPage(self, interaction: discord.Interaction, pageNumber):
maxPages = self.getMaxPages()
Expand Down Expand Up @@ -228,8 +246,8 @@ async def _pageInfo(
message: discord.Message = await self.context.bot.wait_for(
"message",
timeout=30.0,
check=lambda msg: msg.author.id == interaction.user.id
and msg.channel.id == interaction.channel.id
check=lambda msg: msg.author.id == interaction.user.id # type: ignore
and msg.channel.id == interaction.channel.id # type: ignore
and msg.content.isdigit(),
)
with suppress(discord.HTTPException, discord.NotFound):
Expand Down Expand Up @@ -259,3 +277,35 @@ async def _last(self, button: discord.ui.Button, interaction: discord.Interactio
)
async def _stop(self, button: discord.ui.Button, interaction: discord.Interaction):
await self.stop()


choice = namedtuple("choice", ("label", "value"))


class ZChoices(ZView):
"""Basically send choices as buttons"""

def __init__(self, ctx: Context, choices: Iterable[Any]):
super().__init__(owner=ctx.author)
self.context = ctx
self.choices: Iterable[Any] = choices
self.value: Any = None

def makeCallback(choice):
async def callback(interaction):
await interaction.response.defer()
self.value = choice.value
self.stop()

return callback

for choice in self.choices:
button = discord.ui.Button(label=choice.label)
button.callback = makeCallback(choice)
self.add_item(button)

async def wait(self):
await super().wait()

async def start(self):
await self.wait()
20 changes: 17 additions & 3 deletions core/mixin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
from __future__ import annotations

from typing import TYPE_CHECKING


if TYPE_CHECKING:
from databases import Database

from core.bot import ziBot


class CogMixin:
"""Mixin for Cogs/Exts."""

def __init__(self, bot):
self.bot = bot
icon = "❓"
cc = False

def __init__(self, bot: ziBot) -> None:
self.bot: ziBot = bot

@property
def db(self):
def db(self) -> Database:
return self.bot.db
Loading

0 comments on commit 4466d13

Please sign in to comment.