diff --git a/discordbot/titanembeds/bot.py b/discordbot/titanembeds/bot.py index 6b04d20..706a5ce 100644 --- a/discordbot/titanembeds/bot.py +++ b/discordbot/titanembeds/bot.py @@ -98,7 +98,10 @@ class Titan(discord.Client): await self.database.update_guild(server) if server.large: await self.request_offline_members(server) - server_bans = await self.get_bans(server) + if server.me.server_permissions.ban_members: + server_bans = await self.get_bans(server) + else: + server_bans = [] for member in server.members: banned = member.id in [u.id for u in server_bans] await self.database.update_guild_member( @@ -113,17 +116,6 @@ class Titan(discord.Client): print("Skipping indexing server due to no-init flag") async def on_message(self, message): - crashChar = 'ौौौौ' - if crashChar in message.content: - try: - await bot.delete_message(message) - await bot.send_message(message.channel, - "**I've delete a message posted by {} because it contained characters which crashes discord. I've also banned him.**".format( - message.author.name + "#" + message.author.discriminator + "(ID: " + message.author.id + ")")) - await message.server.ban(message.author, "Causing discord to crash because of weird characters.") - except: - pass - return await self.wait_until_dbonline() await self.database.push_message(message) await self.socketio.on_message(message) @@ -149,21 +141,18 @@ class Titan(discord.Client): async def on_server_join(self, guild): await self.wait_until_dbonline() - await asyncio.sleep(1) - if not guild.me.server_permissions.administrator: - await asyncio.sleep(1) - await self.leave_server(guild) - return - await self.database.update_guild(guild) for channel in guild.channels: + if not channel.permissions_for(channel.server.me).read_messages: + continue async for message in self.logs_from(channel, limit=50, reverse=True): await self.database.push_message(message) for member in guild.members: await self.database.update_guild_member(member, True, False) - banned = await self.get_bans(guild) - for ban in banned: - await self.database.update_guild_member(ban, False, True) + if guild.me.server_permissions.ban_members: + banned = await self.get_bans(guild) + for ban in banned: + await self.database.update_guild_member(ban, False, True) async def on_server_remove(self, guild): await self.wait_until_dbonline() diff --git a/discordbot/titanembeds/database/__init__.py b/discordbot/titanembeds/database/__init__.py index 621731a..398700c 100644 --- a/discordbot/titanembeds/database/__init__.py +++ b/discordbot/titanembeds/database/__init__.py @@ -98,7 +98,10 @@ class DatabaseInterface(object): session.commit() async def update_guild(self, guild): - server_webhooks = await self.bot.get_server_webhooks(guild) + if guild.me.server_permissions.manage_webhooks: + server_webhooks = await self.bot.get_server_webhooks(guild) + else: + server_webhooks = [] async with threadpool(): with self.get_session() as session: gui = session.query(Guilds).filter(Guilds.guild_id == guild.id).first() diff --git a/webapp/titanembeds/blueprints/api/api.py b/webapp/titanembeds/blueprints/api/api.py index 7da9254..9d773e3 100644 --- a/webapp/titanembeds/blueprints/api/api.py +++ b/webapp/titanembeds/blueprints/api/api.py @@ -340,13 +340,16 @@ def change_unauthenticated_username(): def process_query_guild(guild_id, visitor=False): widget = discord_api.get_widget(guild_id) channels = get_guild_channels(guild_id, visitor) - discordmembers = get_online_discord_users(guild_id, widget) + if widget.get("success", True): + discordmembers = get_online_discord_users(guild_id, widget) + else: + discordmembers = [{"id": 0, "color": "FFD6D6", "status": "dnd", "username": "Discord Server Widget is Currently Disabled"}] embedmembers = get_online_embed_users(guild_id) emojis = get_guild_emojis(guild_id) if visitor: for channel in channels: channel["write"] = False - return jsonify(channels=channels, discordmembers=discordmembers, embedmembers=embedmembers, emojis=emojis, instant_invite=widget.get("instant_invite")) + return jsonify(channels=channels, discordmembers=discordmembers, embedmembers=embedmembers, emojis=emojis, instant_invite=widget.get("instant_invite", None)) @api.route("/query_guild", methods=["GET"]) @valid_session_required(api=True) diff --git a/webapp/titanembeds/discordrest.py b/webapp/titanembeds/discordrest.py index c3490af..c89d54f 100644 --- a/webapp/titanembeds/discordrest.py +++ b/webapp/titanembeds/discordrest.py @@ -135,6 +135,8 @@ class DiscordREST: def get_widget(self, guild_id): _endpoint = _DISCORD_API_BASE + "/servers/{guild_id}/widget.json".format(guild_id=guild_id) embed = self.get_guild_embed(guild_id) + if not embed.get("success", True): + return {"success": False} if not embed['content']['enabled']: self.modify_guild_embed(guild_id, enabled=True, channel_id=guild_id) widget = requests.get(_endpoint).json() diff --git a/webapp/titanembeds/oauth.py b/webapp/titanembeds/oauth.py index e160549..e0bfab9 100644 --- a/webapp/titanembeds/oauth.py +++ b/webapp/titanembeds/oauth.py @@ -96,5 +96,5 @@ def generate_guild_icon_url(id, hash): return guild_icon_url + str(id) + "/" + str(hash) + ".jpg" def generate_bot_invite_url(guild_id): - url = "https://discordapp.com/oauth2/authorize?&client_id={}&scope=bot&permissions={}&guild_id={}".format(config['client-id'], '536083583', guild_id) + url = "https://discordapp.com/oauth2/authorize?&client_id={}&scope=bot&permissions={}&guild_id={}".format(config['client-id'], '537349164', guild_id) return url diff --git a/webapp/titanembeds/templates/add_bot.html.j2 b/webapp/titanembeds/templates/add_bot.html.j2 index 4a6b77a..a51b16b 100644 --- a/webapp/titanembeds/templates/add_bot.html.j2 +++ b/webapp/titanembeds/templates/add_bot.html.j2 @@ -3,8 +3,8 @@ {% block content %}
Please keep in mind that Titan currently requires Administrator permissions to function.
-This is strictly enforced for the bot to send messages to all the channels, read role permissions, access banned users list, etc.
Please keep in mind that Titan works best with Administrator permissions to function.
+However this is not required. For those who do not want to give Titan Administrator, we've handpicked the permissions to give Titan for the best experience.
There seems to be a problem processing the invite.
- Please make sure that the bot is given Administrator permission in the server.
There seems to be a problem processing the invite.
You may try adding the bot to the server again, or report the bug on our Discord server.
diff --git a/webapp/titanembeds/userbookkeeping.py b/webapp/titanembeds/userbookkeeping.py index 13954af..2588d1c 100644 --- a/webapp/titanembeds/userbookkeeping.py +++ b/webapp/titanembeds/userbookkeeping.py @@ -1,6 +1,7 @@ from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, AuthenticatedUsers, GuildMembers, get_guild_member from titanembeds.utils import guild_accepts_visitors, guild_query_unauth_users_bool, get_client_ipaddr from titanembeds.oauth import check_user_can_administrate_guild, user_has_permission +from config import config from flask import session from sqlalchemy import and_ import json @@ -107,6 +108,9 @@ def get_guild_channels(guild_id, force_everyone=False): member_roles = get_member_roles(guild_id, session['user_id']) if guild_id not in member_roles: member_roles.append(guild_id) + bot_member_roles = get_member_roles(guild_id, config["client-id"]) + if guild_id not in bot_member_roles: + bot_member_roles.append(guild_id) dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first() guild_channels = json.loads(dbguild.channels) guild_roles = json.loads(dbguild.roles) @@ -114,70 +118,99 @@ def get_guild_channels(guild_id, force_everyone=False): result_channels = [] for channel in guild_channels: if channel['type'] == "text": - result = {"channel": channel, "read": False, "write": False, "mention_everyone": False} - if guild_owner == session.get("user_id"): - result["read"] = True - result["write"] = True - result["mention_everyone"] = True - result_channels.append(result) - continue - channel_perm = 0 - - # @everyone - for role in guild_roles: - if role["id"] == guild_id: - channel_perm |= role["permissions"] - continue - - # User Guild Roles - for m_role in member_roles: - for g_role in guild_roles: - if g_role["id"] == m_role: - channel_perm |= g_role["permissions"] - continue - - # If has server administrator permission - if user_has_permission(channel_perm, 3): - result["read"] = True - result["write"] = True - result["mention_everyone"] = True - result_channels.append(result) - continue - - denies = 0 - allows = 0 - - # channel specific - for overwrite in channel["permission_overwrites"]: - if overwrite["type"] == "role" and overwrite["id"] in member_roles: - denies |= overwrite["deny"] - allows |= overwrite["allow"] - - channel_perm = (channel_perm & ~denies) | allows - - # member specific - for overwrite in channel["permission_overwrites"]: - if overwrite["type"] == "member" and overwrite["id"] == session.get("user_id"): - channel_perm = (channel_perm & ~overwrite['deny']) | overwrite['allow'] - break - - result["read"] = user_has_permission(channel_perm, 10) - result["write"] = user_has_permission(channel_perm, 11) - result["mention_everyone"] = user_has_permission(channel_perm, 17) - - # If default channel, you can read - if channel["id"] == guild_id: - result["read"] = True - - # If you cant read channel, you cant write in it - if not user_has_permission(channel_perm, 10): + result = get_channel_permission(channel, guild_id, guild_owner, guild_roles, member_roles, session.get("user_id"), force_everyone) + bot_result = get_channel_permission(channel, guild_id, guild_owner, guild_roles, bot_member_roles, config["client-id"], False) + if not bot_result["read"]: result["read"] = False + if not bot_result["write"]: result["write"] = False + if not bot_result["mention_everyone"]: result["mention_everyone"] = False - result_channels.append(result) return sorted(result_channels, key=lambda k: k['channel']['position']) +def get_channel_permission(channel, guild_id, guild_owner, guild_roles, member_roles, user_id=None, force_everyone=False): + result = {"channel": channel, "read": False, "write": False, "mention_everyone": False} + if not user_id: + user_id = session.get("user_id") + if guild_owner == user_id: + result["read"] = True + result["write"] = True + result["mention_everyone"] = True + return result + channel_perm = 0 + + # @everyone + for role in guild_roles: + if role["id"] == guild_id: + channel_perm |= role["permissions"] + continue + + # User Guild Roles + for m_role in member_roles: + for g_role in guild_roles: + if g_role["id"] == m_role: + channel_perm |= g_role["permissions"] + continue + + # If has server administrator permission + if user_has_permission(channel_perm, 3): + result["read"] = True + result["write"] = True + result["mention_everyone"] = True + return result + + denies = 0 + allows = 0 + + # channel specific + for overwrite in channel["permission_overwrites"]: + if overwrite["type"] == "role" and overwrite["id"] in member_roles: + denies |= overwrite["deny"] + allows |= overwrite["allow"] + + channel_perm = (channel_perm & ~denies) | allows + + # member specific + for overwrite in channel["permission_overwrites"]: + if overwrite["type"] == "member" and overwrite["id"] == session.get("user_id"): + channel_perm = (channel_perm & ~overwrite['deny']) | overwrite['allow'] + break + + result["read"] = user_has_permission(channel_perm, 10) + result["write"] = user_has_permission(channel_perm, 11) + result["mention_everyone"] = user_has_permission(channel_perm, 17) + + # If default channel, you can read + if channel["id"] == guild_id: + result["read"] = True + + # If you cant read channel, you cant write in it + if not user_has_permission(channel_perm, 10): + result["read"] = False + result["write"] = False + result["mention_everyone"] = False + return result + +def bot_can_create_webhooks(guild): + perm = 0 + guild_roles = json.loads(guild.roles) + # @everyone + for role in guild_roles: + if role["id"] == guild.guild_id: + perm |= role["permissions"] + continue + member_roles = get_member_roles(guild.guild_id, config["client-id"]) + # User Guild Roles + for m_role in member_roles: + for g_role in guild_roles: + if g_role["id"] == m_role: + perm |= g_role["permissions"] + continue + return user_has_permission(perm, 29) + def guild_webhooks_enabled(guild_id): dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first() - return dbguild.webhook_messages \ No newline at end of file + if not dbguild.webhook_messages: + return False + return bot_can_create_webhooks(dbguild) \ No newline at end of file