Browse Source

All settings decentralisation done. perm_roles and is_anal depreciated. New convert setting "hide" added.

tags/v2.0.0
Roxie Gibson 5 years ago
parent
commit
49b97efb24
19 changed files with 507 additions and 626 deletions
  1. +3
    -1
      CHANGELOG.md
  2. +1
    -20
      main.py
  3. +16
    -0
      roxbot/__init__.py
  4. +3
    -38
      roxbot/checks.py
  5. +40
    -42
      roxbot/cogs/admin.py
  6. +7
    -3
      roxbot/cogs/customcommands.py
  7. +2
    -2
      roxbot/cogs/fun.py
  8. +24
    -0
      roxbot/cogs/gss.py
  9. +60
    -0
      roxbot/cogs/joinleave.py
  10. +62
    -0
      roxbot/cogs/nsfw.py
  11. +42
    -1
      roxbot/cogs/selfassign.py
  12. +2
    -2
      roxbot/cogs/trivia.py
  13. +32
    -4
      roxbot/cogs/twitch.py
  14. +68
    -11
      roxbot/cogs/voice.py
  15. +12
    -6
      roxbot/guild_settings.py
  16. +37
    -1
      roxbot/logging.py
  17. +0
    -4
      roxbot/settings/servers/.gitignore
  18. +0
    -491
      roxbot/settings/settings.py
  19. +96
    -0
      roxbot/system.py

+ 3
- 1
CHANGELOG.md View File

@@ -5,7 +5,9 @@
- easy setup and get that wiki going

### Big Changes
- All settings have been decentralised between servers and cogs. All changes to the settings have been moved to independant commands. This doesn't effect custom commands or warnings.
- All settings have been decentralised between servers and cogs. All changes to the settings have been moved to independant commands. This doesn't effect custom commands or warnings.
- is_anal setting is now depreciated.`;suck` and `;spank` now only work in channels marked NSFW.
- perm_roles setting is now depreciated. All commands will work of Discord's permission system.

### Regular Updates
#### New Features

+ 1
- 20
main.py View File

@@ -40,22 +40,6 @@ from roxbot import guild_settings as gs
# REMEMBER TO UNCOMMENT THE GSS LINE, ROXIE
# DO NOT UNCOMMENT GSS IF YOU ARE NOT ROXIE

cogs = [
"roxbot.cogs.admin",
"roxbot.cogs.customcommands",
"roxbot.cogs.fun",
"roxbot.cogs.image",
"roxbot.cogs.joinleave",
"roxbot.cogs.nsfw",
"roxbot.cogs.reddit",
"roxbot.cogs.selfassign",
"roxbot.cogs.trivia",
"roxbot.cogs.twitch",
"roxbot.cogs.util",
"roxbot.cogs.voice",
#"roxbot.cogs.gss"
]


# Sets up Logging that discord.py does on its own
logger = logging.getLogger('discord')
@@ -81,9 +65,6 @@ async def on_ready():
bot.load_extension("roxbot.system")
print("system.py Loaded")

bot.load_extension("roxbot.settings.settings")
print("settings.py Loaded")

bot.load_extension("roxbot.err_handle")
print("err_handle.py Loaded")

@@ -96,7 +77,7 @@ async def on_ready():

# Load Extension Cogs
print("Cogs Loaded:")
for cog in cogs:
for cog in roxbot.cogs:
try:
bot.load_extension(cog)
print(cog.split(".")[2])

+ 16
- 0
roxbot/__init__.py View File

@@ -55,3 +55,19 @@ __author__ = "Roxanne Gibson"
__version__ = "2.0.0a"

datetime_formatting = "{:%a %Y/%m/%d %H:%M:%S} UTC"

cogs = [
"roxbot.cogs.admin",
"roxbot.cogs.customcommands",
"roxbot.cogs.fun",
"roxbot.cogs.image",
"roxbot.cogs.joinleave",
"roxbot.cogs.nsfw",
"roxbot.cogs.reddit",
"roxbot.cogs.selfassign",
"roxbot.cogs.trivia",
"roxbot.cogs.twitch",
"roxbot.cogs.util",
"roxbot.cogs.voice",
#"roxbot.cogs.gss"
]

+ 3
- 38
roxbot/checks.py View File

@@ -33,38 +33,15 @@ from roxbot import guild_settings as gs

# TODO: Clean up this file.

def is_owner_or_admin():

def has_permission_or_owner(**perms):
def predicate(ctx):
if ctx.author.id == roxbot.owner:
return True
elif isinstance(ctx.channel, discord.DMChannel):
return False
else:
for role in ctx.author.roles:
if role.id in gs.get(ctx.guild)["admin"]["admin_roles"]:
return True
return False
return commands.has_permissions(**perms)
return commands.check(predicate)


def _is_admin_or_mod(ctx):
if ctx.message.author.id == roxbot.owner:
return True
elif isinstance(ctx.channel, discord.DMChannel):
return False
else:
admin_roles = gs.get(ctx.guild)["admin"]["admin_roles"]
mod_roles = gs.get(ctx.guild)["admin"]["mod_roles"]
for role in ctx.author.roles:
if role.id in mod_roles or role.id in admin_roles:
return True
return False


def is_admin_or_mod():
return commands.check(_is_admin_or_mod)


def nsfw_predicate(ctx):
if isinstance(ctx.channel, discord.DMChannel):
return False
@@ -79,15 +56,3 @@ def nsfw_predicate(ctx):

def is_nfsw_enabled():
return commands.check(lambda ctx: nsfw_predicate(ctx))


def isnt_anal():
def predicate(ctx):
if isinstance(ctx.channel, discord.DMChannel):
return False
anal = gs.get(ctx.guild)["admin"]["is_anal"]
if not anal or (nsfw_predicate(ctx) and gs.get(ctx.guild).is_anal["y/n"]):
return True
else:
return False
return commands.check(predicate)

+ 40
- 42
roxbot/cogs/admin.py View File

@@ -78,16 +78,11 @@ class Admin:
self.bot = bot_client
self.settings = {
"admin": {
"convert": {"admin_roles": "role", "mod_roles": "role"},
"convert": {"warnings": "hide"},
"admin_roles": [],
"mod_roles": [],
"is_anal": 0,
"warnings": {},
},
"logging": {
"enabled": 0,
"convert": {"enabled": "bool", "channel": "channel"},
"channel": 0
}
}
self.slow_mode = False
@@ -115,11 +110,11 @@ class Admin:
pass

@commands.guild_only()
@roxbot.checks.is_admin_or_mod()
@commands.has_permissions(manage_messages=True)
@commands.bot_has_permissions(manage_messages=True)
@commands.command()
async def slowmode(self, ctx, seconds):
"""Puts the current channel in slowmode.
"""Puts the current channel in slowmode. Requires the Manage Messages permission.
Usage:
;slowmode [time/"off"]
seconds = number of seconds for the cooldown between messages a user has.
@@ -148,7 +143,7 @@ class Admin:
@commands.cooldown(1, 5)
@commands.command()
async def purge(self, ctx, limit=0, *, author: roxbot.converters.User=None):
"""Purges messages from the text channel.
"""Purges messages from the text channel. Requires the Manage Messages permission.
Limit = Limit of messages to be deleted
Author (optional) = If given, roxbot will selectively only delete this user's messages."""
# TODO: To sort out the limit == how many to delete for the author, and not just a limit.
@@ -160,10 +155,10 @@ class Admin:
return await ctx.send(self.OK_PURGE_CONFIRMATION.format(len(messages)))

@commands.guild_only()
@roxbot.checks.is_admin_or_mod()
@commands.has_permissions(kick_members=True)
@commands.group(case_insensitive=True)
async def warn(self, ctx):
"""Group of commands handling warnings"""
"""Group of commands handling . Requires the Kick Members permission."""
if ctx.invoked_subcommand is None:
return await ctx.send('Missing Argument')

@@ -172,6 +167,7 @@ class Admin:
"""Adds a warning to a user."""
# Warning in the settings is a dictionary of user ids. The user ids are equal to a list of dictionaries.
settings = gs.get(ctx.guild)
warnings = settings["admin"]["warnings"]
warning_limit = 2
warning_dict = {
"warned-by": ctx.author.id,
@@ -180,17 +176,18 @@ class Admin:
}
user_id = str(user.id)

if user_id not in settings.warnings:
settings.warnings[user_id] = []
if user_id not in warnings:
warnings[user_id] = []

warn_limit = 10
if len(settings.warnings[user_id]) > warn_limit:
if len(warnings[user_id]) > warn_limit:
return await ctx.send(self.WARN_WARN_ADD_LIMIT_REACHED.format(warn_limit))

settings.warnings[user_id].append(warning_dict)
settings.update(settings.warnings, "warnings")
warnings[user_id].append(warning_dict)
settings["admin"]["warnings"] = warnings
settings.update(settings["admin"], "admin")

amount_warnings = len(settings.warnings[user_id])
amount_warnings = len(warnings[user_id])
if amount_warnings > warning_limit:
await ctx.author.send(self.OK_WARN_ADD_USER_LIMIT_DM.format(str(user), amount_warnings, warning_limit))

@@ -200,19 +197,22 @@ class Admin:
async def list(self, ctx, *, user: roxbot.converters.User=None):
"""Lists all or just the warnings for one user."""
settings = gs.get(ctx.guild)
warnings = settings["admin"]["warnings"]

if user is None:
paginator = commands.Paginator()
for member in settings.warnings:
for member in warnings:
# Remove users with no warning here instead of remove cause im lazy
if not settings.warnings[member]:
settings.warnings.pop(member)
if not warnings[member]:
warnings.pop(member)
else:
member_obj = discord.utils.get(ctx.guild.members, id=int(member))
if member_obj:
paginator.add_line("{}: {} Warning(s)".format(str(member_obj), len(settings.warnings[member])))
paginator.add_line("{}: {} Warning(s)".format(str(member_obj), len(warnings[member])))
else:
paginator.add_line("{}: {} Warning(s)".format(member, len(settings.warnings[member])))
paginator.add_line("{}: {} Warning(s)".format(member, len(warnings[member])))
settings["admin"]["warnings"] = warnings
settings.update(settings["admin"], "admin")
if len(paginator.pages) <= 0:
return await ctx.send(self.OK_WARN_LIST_NO_WARNINGS)
for page in paginator.pages:
@@ -220,18 +220,14 @@ class Admin:
else:
user_id = str(user.id)

if not settings.warnings.get(user_id):
if not warnings.get(user_id):
return await ctx.send(self.OK_WARN_LIST_USER_NO_WARNINGS)

if not settings.warnings[user_id]:
settings.warnings.pop(user_id)
settings.update(settings.warnings, "warnings")

em = discord.Embed(title="Warnings for {}".format(str(user)), colour=roxbot.EmbedColours.pink)
em.set_thumbnail(url=user.avatar_url)

x = 1
userlist = settings.warnings[user_id]
userlist = warnings[user_id]
for warning in userlist:
try:
warned_by = str(await self.bot.get_user_info(warning["warned-by"]))
@@ -248,21 +244,23 @@ class Admin:
"""Removes one or all of the warnings for a user."""
user_id = str(user.id)
settings = gs.get(ctx.guild)
warnings = settings["admin"]["warnings"]

if index:
try:
index = int(index)
index -= 1
settings.warnings[user_id].pop(index)
if not settings.warnings[user_id]:
settings.warnings.pop(user_id)
warnings[user_id].pop(index)
if not warnings[user_id]:
warnings.pop(user_id)

settings.update(settings.warnings, "warnings")
settings["admin"]["warnings"] = warnings
settings.update(settings["admin"], "admin")
return await ctx.send(self.OK_WARN_REMOVE_REMOVED_WARNING.format(index+1, str(user)))

except Exception as e:
if isinstance(e, IndexError):
return await ctx.send(self.ERROR_WARN_REMOVE_INDEXERROR.format(len(settings.warnings[user_id])))
return await ctx.send(self.ERROR_WARN_REMOVE_INDEXERROR.format(len(settings["warnings"][user_id])))
elif isinstance(e, KeyError):
return await ctx.send(self.WARN_WARN_REMOVE_USER_NOT_FOUND.format(str(user)))
elif isinstance(e, ValueError):
@@ -271,8 +269,9 @@ class Admin:
raise e
else:
try:
settings.warnings.pop(user_id)
settings.update(settings.warnings, "warnings")
warnings.pop(user_id)
settings["admin"]["warnings"] = warnings
settings.update(settings["admin"], "admin")
return await ctx.send(self.OK_WARN_REMOVE_REMOVED_WARNINGS.format(str(user)))
except KeyError:
return await ctx.send(self.WARN_WARN_REMOVE_USER_NOT_FOUND.format(str(user)))
@@ -282,15 +281,15 @@ class Admin:
async def prune(self, ctx, dry_run=0):
"""Purges banned users from the warn list. Add a 1 at the end to do a dry run."""
settings = gs.get(ctx.guild)
warnings = settings.warnings.copy()
warnings = settings["admin"]["warnings"].copy()
count = 0
for ban in await ctx.guild.bans():
for user in warnings:
if int(user) == ban.user.id:
if dry_run == 0:
settings.warnings.pop(user)
settings["admin"]["warnings"].pop(user)
count += 1
settings.update(settings.warnings, "warnings")
settings.update(settings["admin"], "admin")
return await ctx.send(self.OK_WARN_PRUNE_PRUNED.format(count))

@commands.guild_only()
@@ -298,7 +297,7 @@ class Admin:
@commands.bot_has_permissions(kick_members=True)
@commands.command()
async def kick(self, ctx, member: discord.Member, *, reason=""):
"""Kicks mentioned user. Allows you to give a reason."""
"""Kicks mentioned user. Allows you to give a reason. Requires the Kick Members permission."""
try:
await member.kick(reason=reason)
return await ctx.send(self.OK_MOD_ACTION.format("Kicked", member, reason))
@@ -310,7 +309,7 @@ class Admin:
@commands.bot_has_permissions(ban_members=True)
@commands.command()
async def ban(self, ctx, member: discord.Member, *, reason=""):
"""Bans mentioned user. Allows you to give a reason."""
"""Bans mentioned user. Allows you to give a reason. Requires the Ban Members permission."""
try:
await member.ban(reason=reason, delete_message_days=0)
return await ctx.send(self.OK_MOD_ACTION.format("Banned", member, reason))
@@ -322,11 +321,10 @@ class Admin:
@commands.bot_has_permissions(ban_members=True)
@commands.command()
async def unban(self, ctx, member: roxbot.converters.User, *, reason=""):
"""Unbans user with given ID. Allows you to give a reason."""
"""Unbans user with given ID. Allows you to give a reason. Requires the Ban Members permission."""
ban = await ctx.guild.get_ban(member)
mem = ban.user
if mem is None:
# TODO: For issues like this, make BadArgument a negative response embed not an error
return await ctx.send(self.WARN_UNBAN_NOTFOUND)
try:
await ctx.guild.unban(mem, reason=reason)

+ 7
- 3
roxbot/cogs/customcommands.py View File

@@ -52,7 +52,8 @@ class CustomCommands:
"custom_commands": {
"0": {},
"1": {},
"2": {}
"2": {},
"convert": {"0": "hide", "1": "hide", "2": "hide"}
}
}

@@ -129,11 +130,14 @@ class CustomCommands:
command_output = self._get_output(settings["custom_commands"]["0"][command])
return await channel.send(command_output)

@commands.has_permissions(manage_messages=True)
@commands.guild_only()
@commands.group(aliases=["cc"])
@roxbot.checks.is_owner_or_admin()
async def custom(self, ctx):
""""A group of commands to manage custom commands for your server."""
""""
A group of commands to manage custom commands for your server.
Requires the Manage Messages permission.
"""
if ctx.invoked_subcommand is None:
return await ctx.send('Missing Argument')


+ 2
- 2
roxbot/cogs/fun.py View File

@@ -188,7 +188,7 @@ class Fun:
response += '\n'
return await ctx.send(response)

@roxbot.checks.isnt_anal()
@commands.is_nsfw()
@commands.command()
async def spank(self, ctx, *, user: discord.User = None):
"""
@@ -201,7 +201,7 @@ class Fun:
return await ctx.send("You didn't mention someone for me to spank")
return await ctx.send(":peach: :wave: *{} spanks {}*".format(self.bot.user.name, user.name))

@roxbot.checks.isnt_anal()
@commands.is_nsfw()
@commands.command(aliases=["succ"])
async def suck(self, ctx, *, user: discord.User = None):
"""

+ 24
- 0
roxbot/cogs/gss.py View File

@@ -133,6 +133,30 @@ class GaySoundsShitposts:
return ctx.send("Error, message roxie thanks.")
return await ctx.invoke(self.perms, role=arg)

@commands.command()
async def gss(self, ctx, selection=None, *, changes=None):
"""Custom Cog for the GaySoundsShitposts Discord Server."""
selection = selection.lower()
settings = roxbot.guild_settings.get(ctx.guild)
gss = settings["gss"]

if selection == "loggingchannel":
if ctx.message.channel_mentions:
channel = ctx.channel_mentions[0]
else:
channel = self.bot.get_channel(changes)
gss["log_channel"] = channel.id
await ctx.send("Logging Channel set to '{}'".format(channel.name))
elif selection == "requireddays":
gss["required_days"] = int(changes)
await ctx.send("Required days set to '{}'".format(str(changes)))
elif selection == "requiredscore":
gss["required_score"] = int(changes)
await ctx.send("Required score set to '{}'".format(str(changes)))
else:
return await ctx.send("No valid option given.")
return settings.update(gss, "gss")


def setup(bot_client):
bot_client.add_cog(GaySoundsShitposts(bot_client))

+ 60
- 0
roxbot/cogs/joinleave.py View File

@@ -25,7 +25,10 @@ SOFTWARE.
"""


import typing
import discord
from discord.ext import commands

import roxbot
from roxbot import guild_settings

@@ -83,6 +86,63 @@ class JoinLeave():
return await channel.send(embed=discord.Embed(
description="{}#{} has left or been beaned.".format(member.name, member.discriminator), colour=roxbot.EmbedColours.pink))

@commands.has_permissions(manage_messages=True)
@commands.command()
async def greets(self, ctx, setting, channel: typing.Optional[discord.TextChannel] = None, *, text: str):
"""Edits settings for the Welcome Messages

Options:
enable/disable: Enable/disables parts of the cog. Needs to specify which part.
channel: Sets the channels for either option. Must be a ID or mention.
message: specifies a custom message for the greet messages.
"""
setting = setting.lower()
settings = guild_settings.get(ctx.guild)
greets = settings["greets"]
if setting == "enable":
greets["enabled"] = 1
await ctx.send("'greets' was enabled!")
elif setting == "disable":
greets["enabled"] = 0
await ctx.send("'greets' was disabled :cry:")
elif setting == "channel":
if channel is None:
channel = ctx.channel
greets["welcome-channel"] = channel.id
elif setting == "custommessage":
greets["custom-message"] = text
await ctx.send("Custom message set to '{}'".format(text))
else:
return await ctx.send("No valid option given.")
return settings.update(greets, "greets")


@commands.has_permissions(manage_messages=True)
@commands.command()
async def goodbyes(self, ctx, setting, *, channel: typing.Optional[discord.TextChannel] = None):
"""Edits settings for the Welcome Messages

Options:
enable/disable: Enable/disables parts of the cog. Needs to specify which part.
channel: Sets the channels for either option. Must be a ID or mention.
message: specifies a custom message for the greet messages.
"""
setting = setting.lower()
settings = guild_settings.get(ctx.guild)
goodbyes = settings["goodbyes"]
if setting == "enable":
goodbyes["enabled"] = 1
await ctx.send("'goodbyes' was enabled!")
elif setting == "disable":
goodbyes["enabled"] = 0
await ctx.send("'goodbyes' was disabled :cry:")
elif setting == "channel":
if channel is None:
channel = ctx.channel
goodbyes["goodbye-channel"] = channel.id
else:
return await ctx.send("No valid option given.")
return settings.update(goodbyes, "goodbyes")

def setup(Bot):
Bot.add_cog(JoinLeave(Bot))

+ 62
- 0
roxbot/cogs/nsfw.py View File

@@ -25,6 +25,7 @@ SOFTWARE.
"""


import typing
import random
import discord
from discord.ext import commands
@@ -44,6 +45,14 @@ class NFSW():
def __init__(self, bot_client):
self.bot = bot_client
self.cache = {}
self.settings = {
"nsfw": {
"enabled": 0,
"channels": [],
"convert": {"enabled": "bool", "channels": "channel"},
"blacklist": []
}
}

@roxbot.checks.is_nfsw_enabled()
@commands.command(hidden=True)
@@ -112,6 +121,59 @@ class NFSW():
post_url = "https://simg3.gelbooru.com/images/"
return await ctx.invoke(self.gelbooru_clone, base_url=base_url, post_url=post_url, tags=tags)

@commands.command()
async def nsfw(self, ctx, setting, channel: typing.Optional[discord.TextChannel] = None, *, changes=None):
"""Edits settings for the nsfw cog and other nsfw commands.
If nsfw is enabled and nsfw channels are added, the bot will only allow nsfw commands in the specified channels.

Options:
enable/disable: Enable/disables nsfw commands.
addchannel/removechannel: Adds/Removes a nsfw channel.
addbadtag/removebadtag: Add/Removes blacklisted tags so that you can avoid em with the commands.
Example:
;settings nsfw addchannel #nsfw_stuff
"""
setting = setting.lower()
settings = roxbot.guild_settings.get(ctx.guild)
nsfw = settings["nsfw"]

if setting == "enable":
nsfw["enabled"] = 1
await ctx.send("'nsfw' was enabled!")
elif setting == "disable":
nsfw["enabled"] = 0
await ctx.send("'nsfw' was disabled :cry:")
elif setting == "addchannel":
if not channel and not changes:
channel = ctx.channel
if channel.id not in nsfw["channels"]:
nsfw["channels"].append(channel.id)
await ctx.send("'{}' has been added to the nsfw channel list.".format(channel.name))
else:
return await ctx.send("'{}' is already in the list.".format(channel.name))
elif setting == "removechannel":
if not channel and not changes:
channel = ctx.channel
try:
nsfw["channels"].remove(channel.id)
await ctx.send("'{}' has been removed from the nsfw channel list.".format(channel.name))
except ValueError:
return await ctx.send("That role was not in the list.")
elif setting == "addbadtag":
if changes not in nsfw["blacklist"]:
nsfw["blacklist"].append(changes)
await ctx.send("'{}' has been added to the blacklisted tag list.".format(changes))
else:
return await ctx.send("'{}' is already in the list.".format(changes))
elif setting == "removebadtag":
try:
nsfw["blacklist"].remove(changes)
await ctx.send("'{}' has been removed from the blacklisted tag list.".format(changes))
except ValueError:
return await ctx.send("That tag was not in the blacklisted tag list.")
else:
return await ctx.send("No valid option given.")
return settings.update(nsfw, "nsfw")

def setup(bot_client):
bot_client.add_cog(NFSW(bot_client))

+ 42
- 1
roxbot/cogs/selfassign.py View File

@@ -24,7 +24,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""


import discord
from discord.ext import commands

@@ -51,6 +50,48 @@ class SelfAssign():
sa["roles"].remove(role.id)
return settings.update(sa, "self_assign")

@commands.has_permissions(manage_roles=True)
@commands.guild_only()
@commands.command(aliases=["sa"])
async def selfassign(self, ctx, setting, *, role: discord.Role):
"""Edits settings for self assign cog. Requires Manage Roles permission.

Options:
enable/disable: Enable/disables the cog.
add/remove: adds or removes a role that can be self assigned in the server.
"""
settings = roxbot.guild_settings.get(ctx.guild)
self_assign = settings["self_assign"]
setting = setting.lower()


if setting == "enable":
self_assign["enabled"] = 1
await ctx.send("'self_assign' was enabled!")
elif setting == "disable":
self_assign["enabled"] = 0
await ctx.send("'self_assign' was disabled :cry:")
elif setting == "add":
try:
if role.id in self_assign["roles"]:
return await ctx.send("{} is already a self-assignable role.".format(role.name))
self_assign["roles"].append(role.id)
await ctx.send('Role "{}" added'.format(str(role)))
except AttributeError:
raise commands.BadArgument("Could not find that role.")
elif setting == "remove":
try:
if role.id in self_assign["roles"]:
self_assign["roles"].remove(role.id)
await ctx.send('"{}" has been removed from the self-assignable roles.'.format(str(role)))
else:
return await ctx.send("That role was not in the list.")
except AttributeError:
raise commands.BadArgument("Could not find that role.")
else:
return await ctx.send("No valid option given.")
return settings.update(self_assign, "self_assign")

@commands.guild_only()
@commands.command(pass_context=True)
async def listroles(self, ctx):

+ 2
- 2
roxbot/cogs/trivia.py View File

@@ -419,10 +419,10 @@ class Trivia:
else:
await ctx.send(embed=discord.Embed(description="Game isn't being played here.", colour=self.error_colour))

@checks.is_admin_or_mod()
@commands.has_permissions(manage_channels=True)
@trivia.command()
async def kick(self, ctx, user: discord.Member):
"""Mod command to kick users out of the game. Useful if a user is AFK."""
"""Mod command to kick users out of the game. Useful if a user is AFK. Requires Manage Channels permission."""
channel = ctx.channel
player = user
if channel.id in self.games:

+ 32
- 4
roxbot/cogs/twitch.py View File

@@ -25,7 +25,8 @@ SOFTWARE.
"""


from discord import ActivityType
import typing
import discord
from discord.ext import commands

import roxbot
@@ -54,14 +55,14 @@ class Twitch():
return

if member_a.activitiy:
if member_a.activity.type == ActivityType.streaming and member_b.activity.type != ActivityType.streaming:
if member_a.activity.type == discord.ActivityType.streaming and member_b.activity.type != discord.ActivityType.streaming:
if not twitch["whitelist"]["enabled"] or member_a.id in twitch["whitelist"]["list"]:
channel = self.bot.get_channel(twitch["channel"])
return await channel.send(":video_game:** {} is live!** :video_game:\n{}\n{}".format(
member_a.name, member_a.game.name, member_a.game.url))

@commands.group()
@roxbot.checks.is_admin_or_mod()
@commands.group(aliases=["wl"])
@commands.has_permissions(manage_channels=True)
async def whitelist(self, ctx):
"""Command group that handles the twitch cog's whitelist."""
if ctx.invoked_subcommand is None:
@@ -115,6 +116,33 @@ class Twitch():
elif option == 'list':
return await ctx.send(settings["twitch"]["whitelist"]["list"])

@commands.has_permissions(manage_channels=True)
@commands.command()
async def twitch(self, ctx, setting, *, channel: discord.TextChannel = None):
"""Edits settings for self assign cog.

Options:
enable/disable: Enable/disables the cog.
channel: Sets the channel to shill in.
"""

setting = setting.lower()
settings = roxbot.guild_settings.get(ctx.guild)
twitch = settings["twitch"]

if setting == "enable":
twitch["enabled"] = 1
await ctx.send("'twitch' was enabled!")
elif setting == "disable":
twitch["enabled"] = 0
await ctx.send("'twitch' was disabled :cry:")
elif setting == "channel":
twitch["channel"] = channel.id
await ctx.send("{} has been set as the twitch shilling channel!".format(channel.mention))
else:
return await ctx.send("No valid option given.")
return settings.update(twitch, "twitch")


def setup(bot_client):
bot_client.add_cog(Twitch(bot_client))

+ 68
- 11
roxbot/cogs/voice.py View File

@@ -34,7 +34,6 @@ from math import ceil
from discord.ext import commands

import roxbot
from roxbot import guild_settings


def _clear_cache():
@@ -61,7 +60,7 @@ def _format_duration(duration):

def volume_perms():
def predicate(ctx):
gs = guild_settings.get(ctx.guild)
gs = roxbot.guild_settings.get(ctx.guild)
if gs["voice"]["need_perms"]: # Had to copy the admin or mod code cause it wouldn't work ;-;
if ctx.message.author.id == roxbot.owner:
return True
@@ -212,7 +211,7 @@ class Voice:
embed.set_footer(text="{}/{} | Volume: {}%".format(time_played, duration, int(self.now_playing[guild.id].volume*100)))
return embed

@roxbot.checks.is_admin_or_mod()
@roxbot.checks.has_permission_or_owner(manage_channels=True)
@commands.guild_only()
@commands.command()
async def join(self, ctx, *, channel: discord.VoiceChannel = None):
@@ -237,7 +236,7 @@ class Voice:
async def play(self, ctx, *, url, stream=False, from_queue=False, queued_by=None):
"""Plays from a url or search query (almost anything youtube_dl supports)"""
guild = ctx.guild
voice = guild_settings.get(guild).get("voice")
voice = roxbot.guild_settings.get(guild).get("voice")

# Checks if invoker is in voice with the bot. Skips admins and mods and owner and if the song was queued previously.
if not (roxbot.checks._is_admin_or_mod(ctx) or from_queue):
@@ -377,10 +376,10 @@ class Voice:
@commands.guild_only()
@commands.command()
async def skip(self, ctx, option=""):
"""Skips or votes to skip the current video. Use option "--force" if your an admin and """
voice = guild_settings.get(ctx.guild)["voice"]
"""Skips or votes to skip the current video. Can use option "--force" if you have manage_channels permission. """
voice = roxbot.guild_settings.get(ctx.guild)["voice"]
if ctx.voice_client.is_playing():
if voice["skip_voting"] and not (option == "--force" and roxbot.checks._is_admin_or_mod(ctx)): # Admin force skipping
if voice["skip_voting"] and not (option == "--force" and ctx.author.guild_permissions.manage_channels): # Admin force skipping
if ctx.author in self.skip_votes[ctx.guild.id]:
return await ctx.send("You have already voted to skip the current track.")
else:
@@ -443,10 +442,10 @@ class Voice:
await ctx.send(embed=page)

@commands.guild_only()
@roxbot.checks.is_admin_or_mod()
@commands.has_permissions(manage_channels=True)
@commands.command()
async def remove(self, ctx, index):
"""Removes a item from the queue with the given index. Can also input all to delete all queued items."""
"""Removes a item from the queue with the given index. Can also input all to delete all queued items. Requires the Manage Channels permission"""
# Try and convert index into an into. If not possible, just move forward
try:
index = int(index)
@@ -470,10 +469,10 @@ class Voice:
raise commands.CommandError("Valid Index not given.")

@commands.guild_only()
@roxbot.checks.is_admin_or_mod()
@commands.has_permissions(manage_channels=True)
@commands.command(alaises=["disconnect"])
async def stop(self, ctx):
"""Stops and disconnects the bot from voice."""
"""Stops and disconnects the bot from voice. Requires the Manage Channels permission"""
if ctx.voice_client is None:
raise commands.CommandError("Roxbot is not in a voice channel.")
else:
@@ -484,6 +483,64 @@ class Voice:
await ctx.voice_client.disconnect()
return await ctx.send(":wave:")

@commands.has_permissions(manage_channels=True)
@commands.command()
async def voice(self, ctx, setting=None, change=None):
"""Edits settings for the voice cog. Requires the Manage Channels permission
Options:
enable/disable: Enable/disables specified change.
skipratio: Specify what the ratio should be for skip voting if enabled. Example: 0.6 for 60%
maxlength/duration: Specify (in seconds) the max duration of a video that can be played. Ignored if staff of the server/bot owner.
Possible settings to enable/disable:
needperms: specifies whether volume controls and other bot functions need mod/admin perms.
skipvoting: specifies whether skipping should need over half of voice users to vote to skip. Bypassed by mods.
Example:
;settings voice enable skipvoting
"""
setting = setting.lower()
change = change.lower()
settings = roxbot.guild_settings.get(ctx.guild)
voice = settings["voice"]

if setting == "enable":
if change == "needperms":
voice["need_perms"] = 1
await ctx.send("'{}' has been enabled!".format(change))
elif change == "skipvoting":
voice["skip_voting"] = 1
await ctx.send("'{}' has been enabled!".format(change))
else:
return await ctx.send("Not a valid change.")
elif setting == "disable":
if change == "needperms":
voice["need_perms"] = 1
await ctx.send("'{}' was disabled :cry:".format(change))
elif change == "skipvoting":
voice["skip_voting"] = 1
await ctx.send("'{}' was disabled :cry:".format(change))
else:
return await ctx.send("Not a valid change.")
elif setting == "skipratio":
change = float(change)
if 1 > change > 0:
voice["skip_ratio"] = change
elif 0 < change <= 100:
change = change/10
voice["skip_ratio"] = change
else:
return await ctx.send("Valid ratio not given.")
await ctx.send("Skip Ratio was set to {}".format(change))
elif setting == "maxlength" or setting == "maxduration":
change = int(change)
if change >= 1:
voice["skip_ratio"] = change
else:
return await ctx.send("Valid max duration not given.")
await ctx.send("Max Duration was set to {}".format(change))
else:
return await ctx.send("Valid option not given.")
return settings.update(voice, "voice")


def setup(bot_client):
bot_client.add_cog(Voice(bot_client))

+ 12
- 6
roxbot/guild_settings.py View File

@@ -179,7 +179,7 @@ class GuildSettings(object):
for key, setting in settings.items():
if setting.get("convert"):
for x in setting["convert"].keys():
if setting["convert"][x] != "bool":
if setting["convert"][x] not in ("bool", "hide"):
if isinstance(setting[x], list):
for y, value in enumerate(setting[x]):
if option == "str":
@@ -207,14 +207,20 @@ class GuildSettings(object):
"""
Get latest settings, and update them with a change.
:param changed_dict:
:param setting: Setting should be a str of the setting key. If nothing is passed, it is assumed changed_dict is the settings file for the whole server.
:param setting: Setting should be a str of the setting key.
If nothing is passed, it is assumed changed_dict is the settings file for the whole server.
THIS IS NOT RECOMMENED. Always try and just pass the cogs settings and not a whole settings file.
:return:
"""
self.settings = self.refresh()
settings = self.settings.copy()
if setting is not None:
self.settings[setting] = changed_dict
settings[setting] = changed_dict
elif isinstance(changed_dict, dict):
settings = changed_dict
elif isinstance(changed_dict, GuildSettings):
settings = changed_dict.settings
else:
self.settings = changed_dict
settings = self.settings.copy()
self._convert(settings, "str")
raise TypeError("changed_dict can only be a dict or GuildSettings object.")
settings = self._convert(settings, "str")
_write_changes(self.id, self.cogs, settings)

+ 37
- 1
roxbot/logging.py View File

@@ -24,8 +24,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import typing
import discord
from discord.ext import commands

import roxbot
from roxbot import guild_settings
@@ -58,6 +59,13 @@ async def log(guild, channel, command_name, **kwargs):
class Logging:
def __init__(self, bot_client):
self.bot = bot_client
self.settings = {
"logging": {
"enabled": 0,
"convert": {"enabled": "bool", "channel": "channel"},
"channel": 0
}
}

async def on_member_join(self, member):
logging = guild_settings.get(member.guild)["logging"]
@@ -79,6 +87,34 @@ class Logging:
embed = discord.Embed(description="{} left the server".format(member), colour=roxbot.EmbedColours.pink)
return await channel.send(embed=embed)

@commands.guild_only()
@commands.command(aliases=["log"])
async def logging(self, ctx, setting, *, channel: typing.Optional[discord.TextChannel] = None):
"""Edits the logging settings.

Options:
enable/disable: Enable/disables logging.
channel: sets the channel.
"""

setting = setting.lower()
settings = guild_settings.get(ctx.guild)

if setting == "enable":
settings["logging"]["enabled"] = 1
await ctx.send("'logging' was enabled!")
elif setting == "disable":
settings["logging"]["enabled"] = 0
await ctx.send("'logging' was disabled :cry:")
elif setting == "channel":
if not channel:
channel = ctx.channel
settings["logging"]["channel"] = channel.id
await ctx.send("{} has been set as the logging channel!".format(channel.mention))
else:
return await ctx.send("No valid option given.")
return settings.update(settings["logging"], "logging")


def setup(bot_client):
bot_client.add_cog(Logging(bot_client))

+ 0
- 4
roxbot/settings/servers/.gitignore View File

@@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

+ 0
- 491
roxbot/settings/settings.py View File

@@ -1,491 +0,0 @@
# -*- coding: utf-8 -*-

"""
MIT License

Copyright (c) 2017-2018 Roxanne Gibson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import discord
from discord.ext import commands

from roxbot import checks, guild_settings, EmbedColours



class Settings:
"""
Settings is a mix of settings and admin stuff for the bot. OWNER OR ADMIN ONLY.
"""
def __init__(self, bot_client):
self.bot = bot_client

def get_channel(self, ctx, channel):
if ctx.message.channel_mentions:
return ctx.message.channel_mentions[0]
else:
return self.bot.get_channel(channel)

def parse_setting(self, ctx, settings_to_copy, raw=False):
settingcontent = ""
setting = settings_to_copy.copy()
convert = setting.get("convert", None)
if convert is not None and not raw:
for x in convert.keys():
if convert[x] == "bool":
if setting[x] == 0:
setting[x] = "False"
else:
setting[x] = "True"
elif convert[x] == "channel":
if isinstance(setting[x], list):
if len(setting[x]) >= 60:
setting[x] = "There is too many channels to display."
else:
new_channels = []
for channel in setting[x]:
try:
new_channels.append(self.bot.get_channel(channel).mention)
except AttributeError:
new_channels.append(channel)
setting[x] = new_channels
else:
try:
setting[x] = self.bot.get_channel(setting[x]).mention
except AttributeError:
pass
elif convert[x] == "role":
if isinstance(setting[x], list):
if len(setting[x]) >= 60:
setting[x] = "There is too many roles to display."
else:
new_roles = []
for role_id in setting[x]:
try:
new_roles.append(discord.utils.get(ctx.guild.roles, id=role_id).name)
except AttributeError:
new_roles.append(role_id)
setting[x] = new_roles
else:
try:
setting[x] = discord.utils.get(ctx.guild.roles, id=setting[x]).name
except AttributeError:
pass
elif convert[x] == "user":
if isinstance(setting[x], list):
if len(setting[x]) >= 60:
setting[x] = "There is too many users to display."
else:
new_users = []
for user_id in setting[x]:

user = self.bot.get_user(user_id)
if user is None:
new_users.append(str(user_id))
else:
new_users.append(str(user))
setting[x] = new_users
else:
user = self.bot.get_user(setting[x])
if user is None:
setting[x] = str(setting[x])
else:
setting[x] = str(user)
elif convert[x] == "hide":
setting[x] = "This is hidden. Please use other commands to get this data."
for x in setting.items():
if x[0] != "convert":
settingcontent += str(x).strip("()") + "\n"
return settingcontent

@commands.command(aliases=["printsettingsraw"])
@checks.is_admin_or_mod()
async def printsettings(self, ctx, option=None):
"""OWNER OR ADMIN ONLY: Prints the servers settings file."""
# TODO: Use paginator to make the output here not break all the time.
config = guild_settings.get(ctx.guild)
settings = dict(config.settings.copy()) # Make a copy of settings so we don't change the actual settings.
paginator = commands.Paginator(prefix="```md")
paginator.add_line("{} settings for {}.\n".format(self.bot.user.name, ctx.message.guild.name))
if option in settings:
raw = bool(ctx.invoked_with == "printsettingsraw")
settingcontent = self.parse_setting(ctx, settings[option], raw=raw)
paginator.add_line("**{}**".format(option))
paginator.add_line(settingcontent)
for page in paginator.pages:
await ctx.send(page)
else:
for setting in settings:
if setting != "custom_commands" and setting != "warnings":
raw = bool(ctx.invoked_with == "printsettingsraw")
settingcontent = self.parse_setting(ctx, settings[setting], raw=raw)
paginator.add_line("**{}**".format(setting))
paginator.add_line(settingcontent)
for page in paginator.pages:
await ctx.send(page)

@commands.group(case_insensitive=True)
@checks.is_admin_or_mod()
async def settings(self, ctx):
self.guild_settings = guild_settings.get(ctx.guild)

@settings.command(aliases=["log"])
async def logging(self, ctx, selection=None, *, changes=None):
"""Edits the logging settings.

Options:
enable/disable: Enable/disables logging.
channel: sets the channel.
"""
selection = selection.lower()
settings = guild_settings.get(ctx.guild)

if selection == "enable":
settings.logging["enabled"] = 1
await ctx.send("'logging' was enabled!")
elif selection == "disable":
settings.logging["enabled"] = 0
await ctx.send("'logging' was disabled :cry:")
elif selection == "channel":
channel = self.get_channel(ctx, changes)
settings.logging["channel"] = channel.id
await ctx.send("{} has been set as the logging channel!".format(channel.mention))
else:
return await ctx.send("No valid option given.")
return self.guild_settings.update(settings.logging, "logging")

@settings.command(aliases=["sa"])
async def selfassign(self, ctx, selection=None, *, changes=None):
"""Edits settings for self assign cog.

Options:
enable/disable: Enable/disables the cog.
addrole/removerole: adds or removes a role that can be self assigned in the server.
"""

selection = selection.lower()
role = discord.utils.find(lambda u: u.name == changes, ctx.message.guild.roles)

self_assign = self.guild_settings.self_assign

if selection == "enable":
self_assign["enabled"] = 1
await ctx.send("'self_assign' was enabled!")
elif selection == "disable":
self_assign["enabled"] = 0
await ctx.send("'self_assign' was disabled :cry:")
elif selection == "addrole":
try:
if role.id in self_assign["roles"]:
return await ctx.send("{} is already a self-assignable role.".format(role.name))
self_assign["roles"].append(role.id)
await ctx.send('Role "{}" added'.format(str(role)))
except AttributeError:
return await ctx.send("Role param incorrect. Check you spelt it correctly")
elif selection == "removerole":
try:
if role.id in self_assign["roles"]:
self_assign["roles"].remove(role.id)
await ctx.send('"{}" has been removed from the self-assignable roles.'.format(str(role)))
else:
return await ctx.send("That role was not in the list.")
except AttributeError:
return await ctx.send("Role param incorrect. Check you spelt it correctly")
else:
return await ctx.send("No valid option given.")
return self.guild_settings.update(self_assign, "self_assign")

@settings.command(aliases=["jl"])
async def joinleave(self, ctx, selection=None, *, changes=None):
"""Edits settings for joinleave cog.

Options:
enable/disable: Enable/disables parts of the cog. Needs to specify which part.
Example:
;settings joinleave enable greets|goodbyes
greetschannel/goodbyeschannel: Sets the channels for either option. Must be a ID or mention.
custommessage: specifies a custom message for the greet messages.
"""

selection = selection.lower()
channel = self.get_channel(ctx, changes)
greets = self.guild_settings.greets
goodbyes = self.guild_settings.goodbyes

if selection == "greets":
if changes == "enable":
greets["enabled"] = 1
await ctx.send("'greets' was enabled!")
elif changes == "disable":
greets["enabled"] = 0
await ctx.send("'greets' was disabled :cry:")

elif selection == "goodbyes":
if changes == "enable":
goodbyes["enabled"] = 1
await ctx.send("'goodbyes' was enabled!")
elif changes == "disable":
goodbyes["enabled"] = 0
await ctx.send("'goodbyes' was disabled :cry:")

else:
if selection == "greetschannel":
greets["welcome-channel"] = channel.id
changes = "greets"
await ctx.send("{} has been set as the welcome channel!".format(channel.mention))
elif selection == "goodbyeschannel":
goodbyes["goodbye-channel"] = channel.id
changes = "goodbyes"
await ctx.send("{} has been set as the goodbye channel!".format(channel.mention))
elif selection == "custommessage":
greets["custom-message"] = changes
await ctx.send("Custom message set to '{}'".format(changes))
changes = "greets"
else:
return await ctx.send("No valid option given.")

if changes == "greets":
return self.guild_settings.update(greets, "greets")
elif changes == "goodbyes":
return self.guild_settings.update(goodbyes, "goodbyes")

@settings.command()
async def twitch(self, ctx, selection=None, *, changes=None):
"""Edits settings for self assign cog.

Options:
enable/disable: Enable/disables the cog.
channel: Sets the channel to shill in.
"""
# TODO: Menu also needs editing since I edited the twitch backend
selection = selection.lower()
twitch = self.guild_settings.twitch

if selection == "enable":
twitch["enabled"] = 1
await ctx.send("'twitch' was enabled!")
elif selection == "disable":
twitch["enabled"] = 0
await ctx.send("'twitch' was disabled :cry:")
elif selection == "channel":
channel = self.get_channel(ctx, changes)
twitch["channel"] = channel.id
await ctx.send("{} has been set as the twitch shilling channel!".format(channel.mention))
# Is lacking whitelist options. Might be added or might be depreciated.
# Turns out this is handled in the cog and I don't think it needs changing but may be confusing.
else:
return await ctx.send("No valid option given.")
return self.guild_settings.update(twitch, "twitch")

@settings.command(aliases=["perms"])
async def permrole(self, ctx, selection=None, *, changes=None):
"""Edits settings for permission roles.

Options:
addadmin/removeadmin: Adds/Removes admin role.
addmod/removemod: Adds/Removes mod role.
Example:
;settings permrole addadmin Admin
"""

selection = selection.lower()
role = discord.utils.find(lambda u: u.name == changes, ctx.message.guild.roles)
perm_roles = self.guild_settings.perm_roles

if selection == "addadmin":
if role.id not in perm_roles["admin"]:
perm_roles["admin"].append(role.id)
await ctx.send("'{}' has been added to the Admin role list.".format(role.name))
else:
return await ctx.send("'{}' is already in the list.".format(role.name))
elif selection == "addmod":
if role.id not in perm_roles["mod"]:
perm_roles["mod"].append(role.id)
await ctx.send("'{}' has been added to the Mod role list.".format(role.name))
else:
return await ctx.send("'{}' is already in the list.".format(role.name))
elif selection == "removeadmin":
try:
perm_roles["admin"].remove(role.id)
await ctx.send("'{}' has been removed from the Admin role list.".format(role.name))
except ValueError:
return await ctx.send("That role was not in the list.")
elif selection == "removemod":
try:
perm_roles["mod"].remove(role.id)
await ctx.send("'{}' has been removed from the Mod role list.".format(role.name))
except ValueError:
return await ctx.send("That role was not in the list.")

else:
return await ctx.send("No valid option given.")
return self.guild_settings.update(perm_roles, "perm_roles")

@settings.command()
async def gss(self, ctx, selection=None, *, changes=None):
"""Custom Cog for the GaySoundsShitposts Discord Server."""
# TODO: Menu
selection = selection.lower()
gss = self.guild_settings.gss

if selection == "loggingchannel":
channel = self.get_channel(ctx, changes)
gss["log_channel"] = channel.id
await ctx.send("Logging Channel set to '{}'".format(channel.name))
elif selection == "requireddays":
gss["required_days"] = int(changes)
await ctx.send("Required days set to '{}'".format(str(changes)))
elif selection == "requiredscore":
gss["required_score"] = int(changes)
await ctx.send("Required score set to '{}'".format(str(changes)))
else:
return await ctx.send("No valid option given.")
return self.guild_settings.update(gss, "gss")

@settings.command()
async def nsfw(self, ctx, selection=None, *, changes=None):
"""Edits settings for the nsfw cog and other nsfw commands.
If nsfw is enabled and nsfw channels are added, the bot will only allow nsfw commands in the specified channels.

Options:
enable/disable: Enable/disables nsfw commands.
addchannel/removechannel: Adds/Removes a nsfw channel.
addbadtag/removebadtag: Add/Removes blacklisted tags so that you can avoid em with the commands.
Example:
;settings nsfw addchannel #nsfw_stuff
"""
#menu = Menu.nsfw(ctx.guild)
#print(menu.content)
selection = selection.lower()
nsfw = self.guild_settings.nsfw

if selection == "enable":
nsfw["enabled"] = 1
await ctx.send("'nsfw' was enabled!")
elif selection == "disable":
nsfw["enabled"] = 0
await ctx.send("'nsfw' was disabled :cry:")
elif selection == "addchannel":
channel = self.get_channel(ctx, changes)
if channel.id not in nsfw["channels"]:
nsfw["channels"].append(channel.id)
await ctx.send("'{}' has been added to the nsfw channel list.".format(channel.name))
else:
return await ctx.send("'{}' is already in the list.".format(channel.name))
elif selection == "removechannel":
channel = self.get_channel(ctx, changes)
try:
nsfw["channels"].remove(channel.id)
await ctx.send("'{}' has been removed from the nsfw channel list.".format(channel.name))
except ValueError:
return await ctx.send("That role was not in the list.")
elif selection == "addbadtag":
if changes not in nsfw["blacklist"]:
nsfw["blacklist"].append(changes)
await ctx.send("'{}' has been added to the blacklisted tag list.".format(changes))
else:
return await ctx.send("'{}' is already in the list.".format(changes))
elif selection == "removebadtag":
try:
nsfw["blacklist"].remove(changes)
await ctx.send("'{}' has been removed from the blacklisted tag list.".format(changes))
except ValueError:
return await ctx.send("That tag was not in the blacklisted tag list.")
else:
return await ctx.send("No valid option given.")
return self.guild_settings.update(nsfw, "nsfw")

@settings.command()
async def voice(self, ctx, setting=None, change=None):
"""Edits settings for the voice cog.
Options:
enable/disable: Enable/disables specified change.
skipratio: Specify what the ratio should be for skip voting if enabled. Example: 0.6 for 60%
maxlength/duration: Specify (in seconds) the max duration of a video that can be played. Ignored if staff of the server/bot owner.
Possible settings to enable/disable:
needperms: specifies whether volume controls and other bot functions need mod/admin perms.
skipvoting: specifies whether skipping should need over half of voice users to vote to skip. Bypassed by mods.
Example:
;settings voice enable skipvoting
"""
setting = setting.lower()
change = change.lower()
voice = self.guild_settings.voice

if setting == "enable":
if change == "needperms":
voice["need_perms"] = 1
await ctx.send("'{}' has been enabled!".format(change))
elif change == "skipvoting":
voice["skip_voting"] = 1
await ctx.send("'{}' has been enabled!".format(change))
else:
return await ctx.send("Not a valid change.")
elif setting == "disable":
if change == "needperms":
voice["need_perms"] = 1
await ctx.send("'{}' was disabled :cry:".format(change))
elif change == "skipvoting":
voice["skip_voting"] = 1
await ctx.send("'{}' was disabled :cry:".format(change))
else:
return await ctx.send("Not a valid change.")
elif setting == "skipratio":
change = float(change)
if 1 > change > 0:
voice["skip_ratio"] = change
elif 0 < change <= 100:
change = change/10
voice["skip_ratio"] = change
else:
return await ctx.send("Valid ratio not given.")
await ctx.send("Skip Ratio was set to {}".format(change))
elif setting == "maxlength" or setting == "maxduration":
change = int(change)
if change >= 1:
voice["skip_ratio"] = change
else:
return await ctx.send("Valid max duration not given.")
await ctx.send("Max Duration was set to {}".format(change))
else:
return await ctx.send("Valid option not given.")
return self.guild_settings.update(voice, "voice")

@commands.guild_only()
@checks.is_admin_or_mod()
@commands.command()
async def serverisanal(self, ctx):
"""Tells the bot where the server is anal or not.
This only changes if roxbot can do the suck and spank commands outside of the specified nsfw channels."""
gs = guild_settings.get(ctx.guild)
is_anal = gs.is_anal
if is_anal["y/n"] == 0:
is_anal["y/n"] = 1
gs.update(is_anal, "is_anal")
await ctx.send("I now know this server is anal")
else:
is_anal["y/n"] = 0
gs.update(is_anal, "is_anal")
await ctx.send("I now know this server is NOT anal")


def setup(bot_client):
bot_client.add_cog(Settings(bot_client))

+ 96
- 0
roxbot/system.py View File

@@ -180,6 +180,102 @@ class System:
await self.bot.change_presence(status=discord_status)
await ctx.send("**:ok:** Status set to {}".format(discord_status))

def parse_setting(self, ctx, settings_to_copy, raw=False):
settingcontent = ""
setting = settings_to_copy.copy()
convert = setting.get("convert", None)
if convert is not None and not raw:
for x in convert.keys():
if convert[x] == "bool":
if setting[x] == 0:
setting[x] = "False"
else:
setting[x] = "True"
elif convert[x] == "channel":
if isinstance(setting[x], list):
if len(setting[x]) >= 60:
setting[x] = "There is too many channels to display."
else:
new_channels = []
for channel in setting[x]:
try:
new_channels.append(self.bot.get_channel(channel).mention)
except AttributeError:
new_channels.append(channel)
setting[x] = new_channels
else:
try:
setting[x] = self.bot.get_channel(setting[x]).mention
except AttributeError:
pass
elif convert[x] == "role":
if isinstance(setting[x], list):
if len(setting[x]) >= 60:
setting[x] = "There is too many roles to display."
else:
new_roles = []
for role_id in setting[x]:
try:
new_roles.append(discord.utils.get(ctx.guild.roles, id=role_id).name)
except AttributeError:
new_roles.append(role_id)
setting[x] = new_roles
else:
try:
setting[x] = discord.utils.get(ctx.guild.roles, id=setting[x]).name
except AttributeError:
pass
elif convert[x] == "user":
if isinstance(setting[x], list):
if len(setting[x]) >= 60:
setting[x] = "There is too many users to display."
else:
new_users = []
for user_id in setting[x]:

user = self.bot.get_user(user_id)
if user is None:
new_users.append(str(user_id))
else:
new_users.append(str(user))
setting[x] = new_users
else:
user = self.bot.get_user(setting[x])
if user is None:
setting[x] = str(setting[x])
else:
setting[x] = str(user)
elif convert[x] == "hide":
setting[x] = "This is hidden. Please use other commands to get this data."
for x in setting.items():
if x[0] != "convert":
settingcontent += str(x).strip("()") + "\n"
return settingcontent

@commands.command(aliases=["printsettingsraw"])
@commands.has_permissions(manage_guild=True)
async def printsettings(self, ctx, option=None):
"""OWNER OR ADMIN ONLY: Prints the servers settings file."""
config = roxbot.guild_settings.get(ctx.guild)
settings = dict(config.settings.copy()) # Make a copy of settings so we don't change the actual settings.
paginator = commands.Paginator(prefix="```md")
paginator.add_line("{} settings for {}.\n".format(self.bot.user.name, ctx.message.guild.name))
if option in settings:
raw = bool(ctx.invoked_with == "printsettingsraw")
settingcontent = self.parse_setting(ctx, settings[option], raw=raw)
paginator.add_line("**{}**".format(option))
paginator.add_line(settingcontent)
for page in paginator.pages:
await ctx.send(page)
else:
for setting in settings:
raw = bool(ctx.invoked_with == "printsettingsraw")
settingcontent = self.parse_setting(ctx, settings[setting], raw=raw)
paginator.add_line("**{}**".format(setting))
paginator.add_line(settingcontent)
for page in paginator.pages:
await ctx.send(page)

@commands.command()
@commands.is_owner()
async def shutdown(self, ctx):

Loading…
Cancel
Save