async def loggingOnTwitchalertEdit(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when someone changes a twitch alert (mostly) via web. If track option `Twitchalert.edit` is active, it will send a message to discord Required keywords: ------------------ * `ChangeMember` - discord.Member * `twitch_channel` - str * `discord_channel_id` - str * `changes` - dict """ logging_signature: str = "Twitchalert.edit" ChangeMember: discord.Member = kwargs["ChangeMember"] twitch_channel: str = kwargs["twitch_channel"] discord_channel_id: str = kwargs["discord_channel_id"] changes: str = kwargs["changes"] Chan: discord.TextChannel = getDiscordChannelFromString( cls, ChangeMember.guild, discord_channel_id, required_type="text") discord_channel_name: str = Chan.name if Chan else "(Unknown)" new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(ChangeMember.id), "content": f"{ChangeMember.name} changed the Twitch-Alert for {twitch_channel} in #{discord_channel_name}: {str(changes)}" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, ChangeMember.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description=f"{ChangeMember.name} changed a Twitch-Alert.", timestamp=datetime.datetime.now(), color=EVENT_COLOR_WARNING, url=makeWebAccessLink(cls, ChangeMember.guild.id, new_log_id)) Emb.set_thumbnail( url=ChangeMember.avatar_url or ChangeMember.default_avatar_url) Emb.add_field(name="Twitch channel:", value=twitch_channel, inline=False) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")
async def loggingOnAssignroleCreate(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when someone creates a new assignrole via web. If track option `Assignrole.create` is active, it will send a message to discord Required keywords: ------------------ * `Creator` - discord.Member * `assign_role_id` - str * `trigger` - str """ logging_signature: str = "Assignrole.create" Creator: discord.Member = kwargs["Creator"] assign_role_id: str = kwargs["assign_role_id"] trigger: str = kwargs["trigger"] AssignRole: discord.Role = getDiscordRoleFromString( cls, Creator.guild, assign_role_id) assign_role_name: str = AssignRole.name if AssignRole else "(Unknown)" new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(Creator.id), "content": f"{Creator.name} created a new assign role {assign_role_name} with {trigger=}" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, Creator.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description=f"{Creator.name} created a assignrole", timestamp=datetime.datetime.now(), color=EVENT_COLOR_POSITIVE, url=makeWebAccessLink(cls, Creator.guild.id, new_log_id)) Emb.set_thumbnail(url=Creator.avatar_url or Creator.default_avatar_url) Emb.add_field(name="Trigger:", value=trigger, inline=False) Emb.add_field(name="Linked with role:", value=assign_role_name, inline=False) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")
async def loggingOnLevelmedalDelete(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when someone deletes a discordmember medal via web. If track option `Levelmedal.delete` is active, it will send a message to discord Required keywords: ------------------ * `Deleter` - discord.Member * `medal_member_id` - str * `medal_name` - str """ logging_signature: str = "Levelmedal.delete" Deleter: discord.Member = kwargs["Deleter"] medal_member_id: str = kwargs["medal_member_id"] medal_name: str = kwargs["medal_name"] MedalMember: discord.Member = getDiscordMemberFromString( cls, Deleter.guild, medal_member_id) medal_member_name: str = MedalMember.name if MedalMember else "(Unknown)" new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(Deleter.id), "content": f"{Deleter.name} removed a medal from: {medal_member_name}, old medal: {medal_name}" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, Deleter.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description=f"{Deleter.name} removed a medal", timestamp=datetime.datetime.now(), color=EVENT_COLOR_NEGATIVE, url=makeWebAccessLink(cls, Deleter.guild.id, new_log_id)) Emb.set_thumbnail(url=Deleter.avatar_url or Deleter.default_avatar_url) Emb.add_field(name="Target member:", value=medal_member_name, inline=False) Emb.add_field(name="Medal:", value=medal_name, inline=False) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")
async def loggingOnQuoteEdit(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when someone edits a quote, doesn't matter if in discord or web. (You can only do this in web duh) If track option `Quote.create` is active, it will send a message to discord Required keywords: ------------------ * `ChangeMember` - discord.Member * `quote_id` - str * `old_content` - str * `new_content` - str """ logging_signature: str = "Quote.edit" ChangeMember: discord.Member = kwargs["ChangeMember"] quote_id: str = kwargs["quote_id"] old_content: str = kwargs["old_content"] new_content: str = kwargs["new_content"] new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(ChangeMember.id), "content": f"{ChangeMember.name} changed quote #{quote_id}: {old_content} -> {new_content}" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, ChangeMember.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description=f"{ChangeMember.name} changed a quote.", timestamp=datetime.datetime.now(), color=EVENT_COLOR_WARNING, url=makeWebAccessLink(cls, ChangeMember.guild.id, new_log_id)) Emb.set_thumbnail( url=ChangeMember.avatar_url or ChangeMember.default_avatar_url) Emb.add_field(name="Content:", value=f"{old_content[:500]} -> {new_content[:500]}", inline=True) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")
async def loggingOnAssignroleEdit(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when someone edits assignrole via web. If track option `Assignrole.edit` is active, it will send a message to discord Required keywords: ------------------ * `Editor` - discord.Member * `assign_role_trigger` - str * `changes` - dict """ logging_signature: str = "Assignrole.edit" Editor: discord.Member = kwargs["Editor"] assign_role_trigger: str = kwargs["assign_role_trigger"] changes: dict = kwargs["changes"] new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(Editor.id), "content": f"{Editor.name} edited the assign role with trigger='{assign_role_trigger}' changes: {str(changes)}" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, Editor.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description=f"{Editor.name} edited a assignrole", timestamp=datetime.datetime.now(), color=EVENT_COLOR_WARNING, url=makeWebAccessLink(cls, Editor.guild.id, new_log_id)) Emb.set_thumbnail(url=Editor.avatar_url or Editor.default_avatar_url) Emb.add_field(name="Role trigger:", value=assign_role_trigger, inline=False) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")
async def loggingOnMemberJoin(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when a member is added (joins) a guild. If track option `Member.join` is active, it will send a message to discord Required keywords: ------------------ * `NewMember` - discord.Member Optional keywords: ------------------ * `link_in_name` - bool : (Default: False) """ logging_signature: str = "Member.join" NewMember: discord.Member = kwargs["NewMember"] link_in_name: bool = bool(kwargs.get("link_in_name", False)) new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(NewMember.id), "content": f"{NewMember.name} joined the server" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, NewMember.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description= f"Initial name: {NewMember.name}\nMention: {NewMember.mention}\nID: {NewMember.id}", timestamp=datetime.datetime.now(), color=EVENT_COLOR_POSITIVE, url=makeWebAccessLink(cls, NewMember.guild.id, new_log_id)) Emb.set_thumbnail(url=NewMember.avatar_url or NewMember.default_avatar_url) if link_in_name: Emb.add_field(name=":warning: Blocked public announcements", value="Link in name", inline=True) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")
async def eventOnMemberRemove(cls: "PhaazebotDiscord", Member: discord.Member) -> None: """ Get's triggered everytime a member leaves a guild the following action may be taken (in this order): * Send logging message * Send a leave message to guild channel * set member inactive in levels table """ Settings: DiscordServerSettings = await getDiscordSeverSettings( cls, Member.guild.id) link_in_name: bool = bool(ContainsLink.match(Member.name)) # logging message log_coro: Coroutine = loggingOnMemberRemove(cls, Settings, OldMember=Member, link_in_name=link_in_name) asyncio.ensure_future(log_coro, loop=cls.BASE.DiscordLoop) # send leave message if Settings.leave_chan and Settings.leave_msg and (not link_in_name): LeaveChan: discord.TextChannel = getDiscordChannelFromString( cls, Member.guild, Settings.leave_chan, required_type="text") if LeaveChan: welcome_msg_vars: dict = { "user-name": Member.name, "user-mention": Member.mention, "server-name": Member.guild.name, "member-count": str(Member.guild.member_count) } finished_message: str = await responseFormatter( cls, Settings.leave_msg, var_dict=welcome_msg_vars, enable_special=True, DiscordGuild=Member.guild) try: finished_message = finished_message[:1997] await LeaveChan.send(finished_message) except Exception as E: cls.BASE.Logger.warning( f"Can't send leave message: {E} {traceback.format_exc()}") # set member inactive cls.BASE.PhaazeDB.updateQuery(table="discord_user", content={"on_server": 0}, where="guild_id = %s AND member_id = %s", where_values=(str(Member.guild.id), str(Member.id)))
async def loggingOnCommandCreate(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when someone creates a new command (mostly) via web. If track option `Command.create` is active, it will send a message to discord Required keywords: ------------------ * `Creator` - discord.Member * `command_trigger` - str * `command_info` - dict """ logging_signature: str = "Command.create" Creator: discord.Member = kwargs["Creator"] command_trigger: str = kwargs["command_trigger"] command_info: dict = kwargs["command_info"] new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(Creator.id), "content": f"{Creator.name} created a new command ({command_trigger}) : {str(command_info)}" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, Creator.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description=f"{Creator.name} created a command.", timestamp=datetime.datetime.now(), color=EVENT_COLOR_POSITIVE, url=makeWebAccessLink(cls, Creator.guild.id, new_log_id)) Emb.set_thumbnail(url=Creator.avatar_url or Creator.default_avatar_url) Emb.add_field(name="New Trigger:", value=command_trigger, inline=True) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")
async def searchChannel(cls: "PhaazebotWeb", WebRequest: ExtendedRequest, Data: WebRequestContent) -> Response: search_term: str = Data.getStr("term", "") guild_id: str = Data.getStr("guild_id", "", must_be_digit=True) if not guild_id: return await apiMissingData(cls, WebRequest, msg="invalid or missing 'guild_id'") Guild: discord.Guild = discord.utils.get(cls.BASE.Discord.guilds, id=int(guild_id)) if not Guild: return await apiDiscordGuildUnknown(cls, WebRequest) Channel: Union[discord.TextChannel, discord.VoiceChannel, discord.CategoryChannel] = getDiscordChannelFromString( cls.BASE.Discord, Guild, search_term, contains=True) if not Channel: return await apiDiscordChannelNotFound(cls, WebRequest) data: dict = { "name": str(Channel.name), "id": str(Channel.id), "position": Channel.position, } if type(Channel) is discord.TextChannel: data["channel_type"] = "text" elif type(Channel) is discord.VoiceChannel: data["channel_type"] = "voice" elif type(Channel) is discord.CategoryChannel: data["channel_type"] = "category" else: data["channel_type"] = "unknown" return cls.response(text=json.dumps(dict(result=data, status=200)), content_type="application/json", status=200)
async def apiDiscordConfigsGameEnabledChannelsCreate( cls: "PhaazebotWeb", WebRequest: ExtendedRequest) -> Response: """ Default url: /api/discord/configs/gameenabledchannels/create """ Data: WebRequestContent = WebRequestContent(WebRequest) await Data.load() # get required stuff Create: StorageTransformer = StorageTransformer() Create["guild_id"] = Data.getStr("guild_id", UNDEFINED, must_be_digit=True) Create["channel_id"] = Data.getStr("channel_id", UNDEFINED, must_be_digit=True) # checks if not Create["guild_id"]: return await cls.Tree.Api.errors.apiMissingData( cls, WebRequest, msg="missing or invalid 'guild_id'") if not Create["channel_id"]: return await cls.Tree.Api.errors.apiMissingData( cls, WebRequest, msg="missing or invalid 'channel_id'") PhaazeDiscord: "PhaazebotDiscord" = cls.BASE.Discord Guild: discord.Guild = discord.utils.get(PhaazeDiscord.guilds, id=int(Create["guild_id"])) if not Guild: return await cls.Tree.Api.Discord.errors.apiDiscordGuildUnknown( cls, WebRequest) # get user info AuthDiscord: AuthDiscordWebUser = await authDiscordWebUser(cls, WebRequest) if not AuthDiscord.found: return await cls.Tree.Api.errors.apiMissingAuthorisation( cls, WebRequest) # get member CheckMember: discord.Member = Guild.get_member( int(AuthDiscord.User.user_id)) if not CheckMember: return await cls.Tree.Api.Discord.errors.apiDiscordMemberNotFound( cls, WebRequest, guild_id=Create["guild_id"], user_id=AuthDiscord.User.user_id) # check permissions if not (CheckMember.guild_permissions.administrator or CheckMember.guild_permissions.manage_guild): return await cls.Tree.Api.Discord.errors.apiDiscordMissingPermission( cls, WebRequest, guild_id=Create["guild_id"], user_id=AuthDiscord.User.user_id) ActionChannel: discord.TextChannel = getDiscordChannelFromString( PhaazeDiscord, Guild, Create["channel_id"], required_type="text") if not ActionChannel: return await cls.Tree.Api.Discord.errors.apiDiscordChannelNotFound( cls, WebRequest, channel_id=Create["channel_id"]) # check if already exists res: list = cls.BASE.PhaazeDB.selectQuery( """ SELECT COUNT(*) AS `match` FROM `discord_enabled_gamechannel` WHERE `discord_enabled_gamechannel`.`guild_id` = %s AND `discord_enabled_gamechannel`.`channel_id` = %s""", (Create["guild_id"], Create["channel_id"])) if res[0]["match"]: return await cls.Tree.Api.Discord.Configs.Gameenabledchannels.errors.apiDiscordConfigsGameEnabledChannelExists( cls, WebRequest, channel_id=Create["channel_id"], channel_name=ActionChannel.name) cls.BASE.PhaazeDB.insertQuery(table="discord_enabled_gamechannel", content={ "guild_id": Create["guild_id"], "channel_id": Create["channel_id"] }) cls.BASE.Logger.debug( f"(API/Discord) Game enabled channel: {Create['guild_id']=} added: {Create['channel_id']=}", require="discord:configs") return cls.response(text=json.dumps( dict(msg="Game enabled channel: Added new entry", entry=Create["channel_id"], status=200)), content_type="application/json", status=200)
async def responseFormatter(cls: "PhaazebotDiscord", content: str, *_x, **kwargs) -> str: """ This new formatter is support to ensure all formatting with all known regex means all [key] fields, if there are provided, but also special regex like <#name#> Info source keywords: --------------------- * DiscordGuild `discord.Guild` : (Default: None) [ Enables (A) ] * CommandContext `DiscordCommandContext` : (Default: None) [ Enables (B) ] Optional keywords: ------------------ * enable_special `bool` (A) : (Default: False) [Replaces <#name#> or <#!id!#>] * enable_positions `bool` (B) : (Default: False) [Replaces $1, $6, etc.] * var_dict `dict` : (Default: None) [Replaces all keys with dict value] * VarRegex `re.Pattern` : (Default: CommandVariableString) """ DiscordGuild: discord.Guild = kwargs.get("DiscordGuild", None) CommandContext: DiscordCommandContext = kwargs.get("CommandContext", None) enable_special: bool = bool(kwargs.get("enable_special", False)) enable_positions: bool = bool(kwargs.get("enable_positions", False)) var_dict: dict = kwargs.get("var_dict", {}) VarRegex: "re.Pattern" = kwargs.get("VarRegex", ReDiscord.CommandVariableString) # replaces [key1] [key2] with values from a same name dict if var_dict: VarHits: Iterator = re.finditer(VarRegex, content) for VarMatch in VarHits: key: str = VarMatch.group("name") if key in var_dict: content = content.replace(VarMatch.group(0), var_dict[key]) # replaces $1 $5 $7 etc... at Positions if enable_positions and CommandContext: PositionMatch: Iterator = re.finditer(ReDiscord.CommandPosString, content) for PosMatch in PositionMatch: replacement: str = CommandContext.part(int(PosMatch.group("pos"))) if not replacement: replacement = "" content = content.replace(PosMatch.group(0), replacement) # replaces <#name#> and <#!id!#> with the correct channel mention if enable_special and DiscordGuild: ChannelNameIter: Iterator = re.finditer( ReDiscord.SpecialStringChannelName, content) ChannelIDIter: Iterator = re.finditer(ReDiscord.SpecialStringChannelID, content) found: list = [] for NameMatch in ChannelNameIter: found.append(NameMatch) for IDMatch in ChannelIDIter: found.append(IDMatch) if found: for Hit in found: ChannelToMention: discord.abc.GuildChannel = getDiscordChannelFromString( cls, DiscordGuild, Hit.group(1)) if ChannelToMention: content = content.replace(Hit.group(0), ChannelToMention.mention) else: content = content.replace(Hit.group(0), "(unknown)") return content
async def eventOnMemberJoin(cls: "PhaazebotDiscord", Member: discord.Member) -> None: """ Get's triggered everytime a new member joins a guild, the following action may be taken (in this order): * Send logging message * Send a welcome message to guild channel * Send a private welcome message to the new member * Give the new member a predefined role * (if the member was on this guild before) set member active in levels table """ Settings: DiscordServerSettings = await getDiscordSeverSettings( cls, Member.guild.id) link_in_name: bool = bool(ContainsLink.match(Member.name)) # logging message log_coro: Coroutine = loggingOnMemberJoin(cls, Settings, NewMember=Member, link_in_name=link_in_name) asyncio.ensure_future(log_coro, loop=cls.BASE.DiscordLoop) # send welcome message if Settings.welcome_chan and Settings.welcome_msg and (not link_in_name): WelcomeChan: discord.TextChannel = getDiscordChannelFromString( cls, Member.guild, Settings.welcome_chan, required_type="text") if WelcomeChan: welcome_msg_vars: dict = { "user-name": Member.name, "user-mention": Member.mention, "server-name": Member.guild.name, "member-count": str(Member.guild.member_count) } finished_message: str = await responseFormatter( cls, Settings.welcome_msg, var_dict=welcome_msg_vars, enable_special=True, DiscordGuild=Member.guild) try: finished_message = finished_message[:1997] await WelcomeChan.send(finished_message) except Exception as E: cls.BASE.Logger.warning( f"Can't send welcome message: {E} {traceback.format_exc()}" ) # send private welcome message if Settings.welcome_msg_priv: welcome_msg_priv_vars: dict = { "user-name": Member.name, "server-name": Member.guild.name, "member-count": str(Member.guild.member_count) } finished_message: str = await responseFormatter( cls, Settings.welcome_msg_priv, var_dict=welcome_msg_priv_vars, enable_special=True, DiscordGuild=Member.guild) try: finished_message = finished_message[:1997] await Member.send(finished_message) except Exception as E: cls.BASE.Logger.warning( f"Can't send private welcome message: {E} {traceback.format_exc()}" ) # give member autorole if Settings.autorole_id: RoleToGive: discord.Role = getDiscordRoleFromString( cls, Member.guild, Settings.autorole_id) if RoleToGive and RoleToGive < Member.guild.me.top_role: # there is a role found and phaaze can give this role try: await Member.add_roles(RoleToGive) except Exception as E: cls.BASE.Logger.warning( f"Can't add role to member: {E} {traceback.format_exc()}") # set member active, if there was a known entry cls.BASE.PhaazeDB.updateQuery(table="discord_user", content={"on_server": 1}, where="guild_id = %s AND member_id = %s", where_values=(str(Member.guild.id), str(Member.id)))
async def apiDiscordConfigsEdit(cls: "PhaazebotWeb", WebRequest: ExtendedRequest) -> Response: """ Default url: /api/discord/configs/edit """ Data: WebRequestContent = WebRequestContent(WebRequest) await Data.load() # get required stuff Edit: StorageTransformer = StorageTransformer() Edit["guild_id"] = Data.getStr("guild_id", "", must_be_digit=True) # checks if not Edit["guild_id"]: return await cls.Tree.Api.errors.apiMissingData( cls, WebRequest, msg="missing or invalid 'guild_id'") PhaazeDiscord: "PhaazebotDiscord" = cls.BASE.Discord Guild: discord.Guild = discord.utils.get(PhaazeDiscord.guilds, id=int(Edit["guild_id"])) if not Guild: return await cls.Tree.Api.Discord.errors.apiDiscordGuildUnknown( cls, WebRequest) # get user info AuthDiscord: AuthDiscordWebUser = await authDiscordWebUser(cls, WebRequest) if not AuthDiscord.found: return await cls.Tree.Api.errors.apiMissingAuthorisation( cls, WebRequest) # get member CheckMember: discord.Member = Guild.get_member( int(AuthDiscord.User.user_id)) if not CheckMember: return await cls.Tree.Api.Discord.errors.apiDiscordMemberNotFound( cls, WebRequest, guild_id=Edit["guild_id"], user_id=AuthDiscord.User.user_id) # check permissions # to edit configs, at least moderator rights are needed, (there can be options that require server only duh) if not (CheckMember.guild_permissions.administrator or CheckMember.guild_permissions.manage_guild): return await cls.Tree.Api.Discord.errors.apiDiscordMissingPermission( cls, WebRequest, guild_id=Edit["guild_id"], user_id=AuthDiscord.User.user_id) Configs: DiscordServerSettings = await getDiscordSeverSettings( PhaazeDiscord, origin=Edit["guild_id"], prevent_new=True) if not Configs: return await cls.Tree.Api.Discord.errors.apiDiscordGuildUnknown( cls, WebRequest, msg="Could not find configs for this guild") # check all update values update: dict = dict() Edit["autorole_id"] = Data.getStr("autorole_id", UNDEFINED, len_max=128, allow_none=True) if Edit["autorole_id"] != UNDEFINED: error: bool = False if not Edit["autorole_id"]: update["autorole_id"] = None else: Role: discord.Role = getDiscordRoleFromString( PhaazeDiscord, Guild, Edit["autorole_id"]) if not Role: error = True elif Role >= Guild.me.top_role: return await cls.Tree.Api.errors.apiWrongData( cls, WebRequest, msg=f"The Role `{Role.name}` is to high") else: update["autorole_id"] = str(Role.id) if error: return await cls.Tree.Api.errors.apiWrongData( cls, WebRequest, msg= f"{Edit['autorole_id']} could not be resolved as a valid discord role" ) # blacklist_ban_links Edit["blacklist_ban_links"] = Data.getBool("blacklist_ban_links", UNDEFINED) if Edit["blacklist_ban_links"] != UNDEFINED: update["blacklist_ban_links"] = Edit["blacklist_ban_links"] # blacklist_punishment Edit["blacklist_punishment"] = Data.getStr("blacklist_punishment", UNDEFINED, len_max=32) if Edit["blacklist_punishment"] != UNDEFINED: Edit["blacklist_punishment"] = checkPunishmentString( Edit["blacklist_punishment"]) update["blacklist_punishment"] = Edit["blacklist_punishment"] # currency_name Edit["currency_name"] = Data.getStr("currency_name", UNDEFINED, len_max=256, allow_none=True) if Edit["currency_name"] != UNDEFINED: if not Edit['currency_name']: update["currency_name"] = None else: update["currency_name"] = Edit["currency_name"] # currency_name_multi Edit["currency_name_multi"] = Data.getStr("currency_name_multi", UNDEFINED, len_max=256, allow_none=True) if Edit["currency_name_multi"] != UNDEFINED: if not Edit["currency_name_multi"]: update["currency_name_multi"] = None else: update["currency_name_multi"] = Edit["currency_name_multi"] # leave_chan Edit["leave_chan"] = Data.getStr("leave_chan", UNDEFINED, len_max=128, allow_none=True) if Edit["leave_chan"] != UNDEFINED: error: bool = False if not Edit["leave_chan"]: update["leave_chan"] = None else: Chan: discord.TextChannel = getDiscordChannelFromString( PhaazeDiscord, Guild, Edit["leave_chan"], required_type="text") if not Chan: error = True else: update["leave_chan"] = str(Chan.id) if error: return await cls.Tree.Api.errors.apiWrongData( cls, WebRequest, msg= f"'{Edit['leave_chan']}' could not be resolved as a valid discord text channel" ) # leave_msg Edit["leave_msg"] = Data.getStr("leave_msg", UNDEFINED, len_max=1750, allow_none=True) if Edit["leave_msg"] != UNDEFINED: if not Edit["leave_msg"]: update["leave_msg"] = None else: update["leave_msg"] = Edit["leave_msg"] # level_custom_msg Edit["level_custom_msg"] = Data.getStr("level_custom_msg", UNDEFINED, len_max=1750, allow_none=True) if Edit["level_custom_msg"] != UNDEFINED: if not Edit["level_custom_msg"]: update["level_custom_msg"] = None else: update["level_custom_msg"] = Edit["level_custom_msg"] # level_announce_chan Edit["level_announce_chan"] = Data.getStr("level_announce_chan", UNDEFINED, len_max=128, allow_none=True) if Edit["level_announce_chan"] != UNDEFINED: error: bool = False if not Edit["level_announce_chan"]: update["level_announce_chan"] = None else: Chan: discord.TextChannel = getDiscordChannelFromString( PhaazeDiscord, Guild, Edit["level_announce_chan"], required_type="text") if not Chan: error = True else: update["level_announce_chan"] = str(Chan.id) if error: return await cls.Tree.Api.errors.apiWrongData( cls, WebRequest, msg= f"'{Edit['level_announce_chan']}' could not be resolved as a valid discord text channel" ) update["level_announce_chan"] = Edit["level_announce_chan"] # owner_disable_level Edit["owner_disable_level"] = Data.getBool("owner_disable_level", UNDEFINED) if Edit["owner_disable_level"] != UNDEFINED: if not Guild.owner == CheckMember: return await cls.Tree.Api.Discord.errors.apiDiscordMissingPermission( cls, WebRequest, guild_id=Edit["guild_id"], user_id=AuthDiscord.User.user_id, msg="changing 'owner_disable_level' require server owner") update["owner_disable_level"] = Edit["owner_disable_level"] # owner_disable_normal Edit["owner_disable_normal"] = Data.getBool("owner_disable_normal", UNDEFINED) if Edit["owner_disable_normal"] != UNDEFINED: if not Guild.owner == CheckMember: return await cls.Tree.Api.Discord.errors.apiDiscordMissingPermission( cls, WebRequest, guild_id=Edit["guild_id"], user_id=AuthDiscord.User.user_id, msg="changing 'owner_disable_level' require server owner") update["owner_disable_normal"] = Edit["owner_disable_normal"] # owner_disable_regular Edit["owner_disable_regular"] = Data.getBool("owner_disable_regular", UNDEFINED) if Edit["owner_disable_regular"] != UNDEFINED: if not Guild.owner == CheckMember: return await cls.Tree.Api.Discord.errors.apiDiscordMissingPermission( cls, WebRequest, guild_id=Edit["guild_id"], user_id=AuthDiscord.User.user_id, msg="changing 'owner_disable_level' require server owner") update["owner_disable_regular"] = Edit["owner_disable_regular"] # owner_disable_mod Edit["owner_disable_mod"] = Data.getBool("owner_disable_mod", UNDEFINED) if Edit["owner_disable_mod"] != UNDEFINED: if not Guild.owner == CheckMember: return await cls.Tree.Api.Discord.errors.apiDiscordMissingPermission( cls, WebRequest, guild_id=Edit["guild_id"], user_id=AuthDiscord.User.user_id, msg="changing 'owner_disable_level' require server owner") update["owner_disable_mod"] = Edit["owner_disable_mod"] # track_channel Edit["track_channel"] = Data.getStr("track_channel", UNDEFINED, len_max=128, allow_none=True) if Edit["track_channel"] != UNDEFINED: error: bool = False if not Edit["track_channel"]: update["track_channel"] = Edit["track_channel"] else: Chan: discord.TextChannel = getDiscordChannelFromString( PhaazeDiscord, Guild, Edit["track_channel"], required_type="text") if not Chan: error = True else: update["track_channel"] = str(Chan.id) if error: return await cls.Tree.Api.errors.apiWrongData( cls, WebRequest, msg= f"'{Edit['track_channel']}' could not be resolved as a valid discord text channel" ) # track_value Edit["track_value"] = Data.getInt("track_value", UNDEFINED, min_x=0) if Edit["track_value"] != UNDEFINED: update["track_value"] = Edit["track_value"] # welcome_chan Edit["welcome_chan"] = Data.getStr("welcome_chan", UNDEFINED, len_max=128, allow_none=True) if Edit["welcome_chan"] != UNDEFINED: error: bool = False if not Edit["welcome_chan"]: update["welcome_chan"] = None else: Chan: discord.TextChannel = getDiscordChannelFromString( PhaazeDiscord, Guild, Edit["welcome_chan"], required_type="text") if not Chan: error = True else: update["welcome_chan"] = str(Chan.id) if error: return await cls.Tree.Api.errors.apiWrongData( cls, WebRequest, msg= f"'{Edit['welcome_chan']}' could not be resolved as a valid discord text channel" ) # welcome_msg Edit["welcome_msg"] = Data.getStr("welcome_msg", UNDEFINED, len_max=1750, allow_none=True) if Edit["welcome_msg"] != UNDEFINED: if not Edit["welcome_msg"]: update["welcome_msg"] = None else: update["welcome_msg"] = Edit["welcome_msg"] # welcome_msg_priv Edit["welcome_msg_priv"] = Data.getStr("welcome_msg_priv", UNDEFINED, len_max=1750, allow_none=True) if Edit["welcome_msg_priv"] != UNDEFINED: if not Edit["welcome_msg_priv"]: update["welcome_msg_priv"] = None else: update["welcome_msg_priv"] = Edit["welcome_msg_priv"] if not update: return await cls.Tree.Api.errors.apiMissingData( cls, WebRequest, msg="No changes, please add at least one") cls.BASE.PhaazeDB.updateQuery(table="discord_setting", content=update, where="`discord_setting`.`guild_id` = %s", where_values=(Edit["guild_id"], )) # logging log_coro: Coroutine = loggingOnConfigEdit(PhaazeDiscord, Configs, Editor=CheckMember, changes=update) asyncio.ensure_future(log_coro, loop=cls.BASE.DiscordLoop) cls.BASE.Logger.debug( f"(API/Discord) Configs: {Edit['guild_id']=} updated", require="discord:configs") return cls.response(text=json.dumps( dict(msg="Configs: Updated", changes=update, status=200)), content_type="application/json", status=200)
async def apiDiscordTwitchalertsCreate( cls: "PhaazebotWeb", WebRequest: ExtendedRequest) -> Response: """ Default url: /api/discord/twitchalerts/create """ Data: WebRequestContent = WebRequestContent(WebRequest) await Data.load() # get required stuff Create: StorageTransformer = StorageTransformer() Create["guild_id"] = Data.getStr("guild_id", UNDEFINED, must_be_digit=True) Create["discord_channel_id"] = Data.getStr("discord_channel_id", UNDEFINED, must_be_digit=True) Create["twitch_channel"] = Data.getStr("twitch_channel", UNDEFINED) Create["custom_msg"] = Data.getStr("custom_msg", None, len_max=MAX_CONTENT_SIZE, allow_none=True) Create["suppress_gamechange"] = Data.getBool("suppress_gamechange", False) # checks if not Create["guild_id"]: return await cls.Tree.Api.errors.apiMissingData( cls, WebRequest, msg="missing or invalid 'guild_id'") if not Create["discord_channel_id"]: return await cls.Tree.Api.errors.apiMissingData( cls, WebRequest, msg="missing or invalid 'discord_channel_id'") if not Create["twitch_channel"]: return await cls.Tree.Api.errors.apiMissingData( cls, WebRequest, msg="missing or invalid 'twitch_channel'") # get/check discord PhaazeDiscord: "PhaazebotDiscord" = cls.BASE.Discord Guild: discord.Guild = discord.utils.get(PhaazeDiscord.guilds, id=int(Create["guild_id"])) if not Guild: return await cls.Tree.Api.Discord.errors.apiDiscordGuildUnknown( cls, WebRequest) TargetDiscordChannel: discord.TextChannel = getDiscordChannelFromString( PhaazeDiscord, Guild, Create["discord_channel_id"], required_type="text") if not TargetDiscordChannel: return await cls.Tree.Api.Discord.errors.apiDiscordChannelNotFound( cls, WebRequest, msg=f"Could not find a valid text channel") Match: re.Match = TwitchRe().ChannelLink.match(Create["twitch_channel"]) if Match: Create["twitch_channel"] = Match.group("name") user_res: list = await getTwitchUsers(cls.BASE, item=Create["twitch_channel"], item_type="login") if not user_res: return await cls.Tree.Api.Twitch.errors.apiTwitchUserNotFound( cls, WebRequest, user_name=Create["twitch_channel"]) FoundUser: TwitchUser = user_res.pop(0) # check if already exists and limits res: list = cls.BASE.PhaazeDB.selectQuery( """ SELECT COUNT(*) AS `all`, SUM( CASE WHEN `discord_twitch_alert`.`twitch_channel_id` = %(twitch_channel_id)s THEN 1 ELSE 0 END ) AS `twitch_channel_match`, SUM( CASE WHEN `discord_twitch_alert`.`discord_channel_id` = %(discord_channel_id)s THEN 1 ELSE 0 END ) AS `discord_channel_match`, SUM( CASE WHEN `discord_twitch_alert`.`discord_channel_id` = %(discord_channel_id)s AND `discord_twitch_alert`.`twitch_channel_id` = %(twitch_channel_id)s THEN 1 ELSE 0 END ) AS `both_match` FROM `discord_twitch_alert` WHERE `discord_twitch_alert`.`discord_guild_id` = %(discord_guild_id)s""", dict(discord_guild_id=Create["guild_id"], discord_channel_id=str(TargetDiscordChannel.id), twitch_channel_id=FoundUser.user_id)) if res[0]["all"] == 0: res[0]["twitch_channel_match"] = 0 res[0]["discord_channel_match"] = 0 res[0]["both_match"] = 0 if res[0]["twitch_channel_match"] >= MAX_SAME_TWITCH_ALERTS_PER_GUILD: return await cls.Tree.Api.Discord.Twitchalerts.errors.apiDiscordAlertSameTwitchChannelLimit( cls, WebRequest, limit=MAX_SAME_TWITCH_ALERTS_PER_GUILD, twitch_name=FoundUser.display_name) if res[0]["discord_channel_match"] >= 1: # nothing... for now pass if res[0]["both_match"] >= 1: return await cls.Tree.Api.Discord.Twitchalerts.errors.apiDiscordAlertExists( cls, WebRequest, twitch_name=FoundUser.login, discord_id=TargetDiscordChannel.id) # get user info AuthDiscord: AuthDiscordWebUser = await authDiscordWebUser(cls, WebRequest) if not AuthDiscord.found: return await cls.Tree.Api.errors.apiMissingAuthorisation( cls, WebRequest) # get member CheckMember: discord.Member = Guild.get_member( int(AuthDiscord.User.user_id)) if not CheckMember: return await cls.Tree.Api.Discord.errors.apiDiscordMemberNotFound( cls, WebRequest, guild_id=Create["guild_id"], user_id=AuthDiscord.User.user_id) # check permissions if not (CheckMember.guild_permissions.administrator or CheckMember.guild_permissions.manage_guild): return await cls.Tree.Api.Discord.errors.apiDiscordMissingPermission( cls, WebRequest, guild_id=Create["guild_id"], user_id=AuthDiscord.User.user_id) cls.BASE.PhaazeDB.insertQuery(table="discord_twitch_alert", content={ "discord_guild_id": Create["guild_id"], "discord_channel_id": str(TargetDiscordChannel.id), "twitch_channel_id": FoundUser.user_id, "custom_msg": Create["custom_msg"], "suppress_gamechange": Create["suppress_gamechange"] }) # logging GuildSettings: DiscordServerSettings = await getDiscordSeverSettings( PhaazeDiscord, Create["guild_id"], prevent_new=True) log_coro: Coroutine = loggingOnTwitchalertCreate( PhaazeDiscord, GuildSettings, Creator=CheckMember, discord_channel=TargetDiscordChannel.name, twitch_channel=FoundUser.login) asyncio.ensure_future(log_coro, loop=cls.BASE.DiscordLoop) # some after work, with the new data await placeGatheredData(cls, FoundUser) cls.BASE.Logger.debug( f"(API/Discord) Twitchalert: {Create['guild_id']=} added {FoundUser.user_id=}", require="discord:alert") return cls.response(text=json.dumps( dict(msg="Twitchalert: Added new entry", entry=FoundUser.user_type, status=200)), content_type="application/json", status=200)
async def loggingOnLevelEdit(cls: "PhaazebotDiscord", Settings: DiscordServerSettings, **kwargs) -> None: """ Logs the event when someone edits a discordmember-level via web. If track option `Level.edit` is active, it will send a message to discord Required keywords: ------------------ * `Remover` - discord.Member * `changed_member_id` - str * `changes` - dict """ logging_signature: str = "Level.edit" Editor: discord.Member = kwargs["Editor"] changed_member_id: str = kwargs["changed_member_id"] changes: dict = kwargs["changes"] LevelMember: discord.Member = getDiscordMemberFromString( cls, Editor.guild, changed_member_id) level_member_name: str = LevelMember.name if LevelMember else "(Unknown)" new_log_id: int = cls.BASE.PhaazeDB.insertQuery( table="discord_log", content={ "guild_id": Settings.server_id, "event_value": TRACK_OPTIONS[logging_signature], "initiator_id": str(Editor.id), "content": f"{Editor.name} edited the level stats of: {level_member_name} changes: {str(changes)}" }) if not (TRACK_OPTIONS[logging_signature] & Settings.track_value): return # track option not active, skip message to discord server TargetChannel: discord.TextChannel = getDiscordChannelFromString( cls, Editor.guild, Settings.track_channel, required_type="text") if not TargetChannel: return # no channel found Emb: discord.Embed = discord.Embed( title=f"Log Event - [{logging_signature}]", description=f"{Editor.name} edited level stats", timestamp=datetime.datetime.now(), color=EVENT_COLOR_WARNING, url=makeWebAccessLink(cls, Editor.guild.id, new_log_id)) Emb.set_thumbnail(url=Editor.avatar_url or Editor.default_avatar_url) Emb.add_field(name="Edited member:", value=level_member_name, inline=False) if changes.get("edited", False): Emb.add_field( name="Warning:", value="EXP got changed, this member now has a [EDITED] mark", inline=False) try: await TargetChannel.send(embed=Emb) except Exception as E: cls.BASE.Logger.warning( f"Can't log message: {E} {traceback.format_exc()}")